microsoft/qlib · error · NotImplementedError

Subclass of FeatureStorage must implement `end_index` method

Error message

Subclass of FeatureStorage must implement `end_index` method

What it means

FeatureStorage.end_index (qlib/data/storage/storage.py:294) is abstract: it must return the right (closed) boundary of the data range, where the next append point is end_index + 1, or None when storage does not exist. The base class raises NotImplementedError because each backend stores range metadata differently (e.g. in a .start/end file, in a binary header, or computed from the data).

Source

Thrown at qlib/data/storage/storage.py:294

        Notes
        -----
        If the data(storage) does not exist, return None
        """
        raise NotImplementedError("Subclass of FeatureStorage must implement `start_index` method")

    @property
    def end_index(self) -> Union[int, None]:
        """get FeatureStorage end index

        Notes
        -----
        The  right index of the data range (both sides are closed)

            The next  data appending point will be  `end_index + 1`

        If the data(storage) does not exist, return None
        """
        raise NotImplementedError("Subclass of FeatureStorage must implement `end_index` method")

    def clear(self) -> None:
        raise NotImplementedError("Subclass of FeatureStorage must implement `clear` method")

    def write(self, data_array: Union[List, np.ndarray, Tuple], index: int = None):
        """Write data_array to FeatureStorage starting from index.

        Notes
        ------
            If index is None, append data_array to feature.

            If len(data_array) == 0; return

            If (index - self.end_index) >= 1, self[end_index+1: index] will be filled with np.nan

        Examples
        ---------
            .. code-block::

View on GitHub (pinned to 79633dd950)

Solutions

  1. Use an existing concrete implementation (FileFeatureStorage) via the storage factory
  2. Implement `end_index` in your subclass returning the last stored index or None if empty
  3. Implement the full abstract interface (data, start_index, end_index, clear, write) before using the subclass
  4. Add unit tests that instantiate your backend and assert start/end index behavior

Example fix

// before
class MyStorage(FeatureStorage):
    ...
    # no end_index -> NotImplementedError on append

// after
class MyStorage(FeatureStorage):
    @property
    def end_index(self):
        return None if len(self.data) == 0 else int(self.data.index[-1])
Defensive patterns

Strategy: type-guard

Validate before calling

from qlib.data.storage.storage import FeatureStorage
assert type(storage).end_index is not FeatureStorage.end_index, 'end_index not implemented'

Type guard

def has_concrete_end_index(storage) -> bool:
    return type(storage).end_index is not FeatureStorage.end_index

Try / catch

try:
    ei = storage.end_index
except NotImplementedError as e:
    raise TypeError(f'{type(storage).__name__} lacks end_index implementation') from e

Prevention

When it happens

Trigger: Reading `.end_index` on FeatureStorage directly or on a subclass missing this property; append logic (write with index=None) that first consults end_index to find the append position; rebase() which reads both start_index and end_index.

Common situations: Writing a custom backend and forgetting the range properties; extending qlib's storage layer for a new data format; running dataset dump scripts that query storage boundaries.

Related errors


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