microsoft/qlib · error · NotImplementedError

Please implement `save_obj`

Error message

Please implement `save_obj`

What it means

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.

Source

Thrown at qlib/utils/objm.py:24

from pathlib import Path

from qlib.config import C
from qlib.utils.pickle_utils import restricted_pickle_load


class ObjManager:
    def save_obj(self, obj: object, name: str):
        """
        save obj as name

        Parameters
        ----------
        obj : object
            object to be saved
        name : str
            name of the object
        """
        raise NotImplementedError(f"Please implement `save_obj`")

    def save_objs(self, obj_name_l):
        """
        save objects

        Parameters
        ----------
        obj_name_l : list of <obj, name>
        """
        raise NotImplementedError(f"Please implement the `save_objs` method")

    def load_obj(self, name: str) -> object:
        """
        load object by name

        Parameters
        ----------
        name : str

View on GitHub (pinned to 79633dd950)

Solutions

  1. Use qlib.utils.FileManager (file-backed implementation) instead of ObjManager for default persistence.
  2. If subclassing, implement save_obj(self, obj, name) so it persists `obj` under `name` in your backend.
  3. Add a compile-time guard: declare ObjManager as abc.ABC-style in your subclass and run static checks (mypy) to catch missing overrides.

Example fix

// before
mgr = ObjManager()
mgr.save_obj(model, 'model_v1')  # NotImplementedError

// after
from qlib.utils import FileManager
mgr = FileManager(path='./objs')
mgr.save_obj(model, 'model_v1')
Defensive patterns

Strategy: type-guard

Validate before calling

from qlib.utils.objm import ObjManager, FileManager
mgr = FileManager(path='./objs') if path else ObjManager()  # prefer concrete impl

Type guard

def is_concrete_manager(mgr) -> bool:
    return type(mgr).save_obj is not ObjManager.save_obj

Try / catch

try:
    mgr.save_obj(obj, name)
except NotImplementedError:
    mgr = FileManager(path='./objs')
    mgr.save_obj(obj, name)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/d21fc5366b13d308. Report an issue: GitHub.