{"record":{"id":"d21fc5366b13d308","repo":"microsoft/qlib","slug":"please-implement-save-obj","errorCode":null,"errorMessage":"Please implement `save_obj`","messagePattern":"Please implement `save_obj`","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"qlib/utils/objm.py","lineNumber":24,"sourceCode":"from pathlib import Path\n\nfrom qlib.config import C\nfrom qlib.utils.pickle_utils import restricted_pickle_load\n\n\nclass ObjManager:\n    def save_obj(self, obj: object, name: str):\n        \"\"\"\n        save obj as name\n\n        Parameters\n        ----------\n        obj : object\n            object to be saved\n        name : str\n            name of the object\n        \"\"\"\n        raise NotImplementedError(f\"Please implement `save_obj`\")\n\n    def save_objs(self, obj_name_l):\n        \"\"\"\n        save objects\n\n        Parameters\n        ----------\n        obj_name_l : list of <obj, name>\n        \"\"\"\n        raise NotImplementedError(f\"Please implement the `save_objs` method\")\n\n    def load_obj(self, name: str) -> object:\n        \"\"\"\n        load object by name\n\n        Parameters\n        ----------\n        name : str","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/utils/objm.py#L6-L42","documentation":"ObjManager is an abstract storage interface for named pickled objects; save_obj(obj, name) is the single-object write primitive and the base implementation intentionally raises NotImplementedError. Only concrete subclasses (FileManager, or user-provided managers) implement persistence. Reaching this line means you are calling save on the abstract base or an incomplete subclass.","triggerScenarios":"ObjManager().save_obj(obj, 'name'), or a custom subclass that overrides save_objs but not save_obj; also mocking/partial-initializing a manager (e.g. with unittest.mock.patch) that leaves methods abstract.","commonSituations":"Building a custom remote/DB-backed object manager and forgetting one method; passing a bare ObjManager where qlib expects a FileManager (e.g. in qlib's workflow/task persistence); version upgrades that added new abstract methods to the interface.","solutions":["Use qlib.utils.FileManager (file-backed implementation) instead of ObjManager for default persistence.","If subclassing, implement save_obj(self, obj, name) so it persists `obj` under `name` in your backend.","Add a compile-time guard: declare ObjManager as abc.ABC-style in your subclass and run static checks (mypy) to catch missing overrides."],"exampleFix":"// before\nmgr = ObjManager()\nmgr.save_obj(model, 'model_v1')  # NotImplementedError\n\n// after\nfrom qlib.utils import FileManager\nmgr = FileManager(path='./objs')\nmgr.save_obj(model, 'model_v1')","handlingStrategy":"type-guard","validationCode":"from qlib.utils.objm import ObjManager, FileManager\nmgr = FileManager(path='./objs') if path else ObjManager()  # prefer concrete impl","typeGuard":"def is_concrete_manager(mgr) -> bool:\n    return type(mgr).save_obj is not ObjManager.save_obj","tryCatchPattern":"try:\n    mgr.save_obj(obj, name)\nexcept NotImplementedError:\n    mgr = FileManager(path='./objs')\n    mgr.save_obj(obj, name)","preventionTips":["Default to FileManager; treat ObjManager purely as an interface.","When subclassing, add an abstract-method check (inspect or mypy) that every ObjManager method is overridden."],"tags":["qlib","objm","abstract-method","notimplementederror","persistence"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}