{"record":{"id":"a9d072de954cf0e6","repo":"microsoft/qlib","slug":"subclass-of-featurestorage-must-implement-end-ind","errorCode":null,"errorMessage":"Subclass of FeatureStorage must implement `end_index` method","messagePattern":"Subclass of FeatureStorage must implement `end_index` method","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"qlib/data/storage/storage.py","lineNumber":294,"sourceCode":"        Notes\n        -----\n        If the data(storage) does not exist, return None\n        \"\"\"\n        raise NotImplementedError(\"Subclass of FeatureStorage must implement `start_index` method\")\n\n    @property\n    def end_index(self) -> Union[int, None]:\n        \"\"\"get FeatureStorage end index\n\n        Notes\n        -----\n        The  right index of the data range (both sides are closed)\n\n            The next  data appending point will be  `end_index + 1`\n\n        If the data(storage) does not exist, return None\n        \"\"\"\n        raise NotImplementedError(\"Subclass of FeatureStorage must implement `end_index` method\")\n\n    def clear(self) -> None:\n        raise NotImplementedError(\"Subclass of FeatureStorage must implement `clear` method\")\n\n    def write(self, data_array: Union[List, np.ndarray, Tuple], index: int = None):\n        \"\"\"Write data_array to FeatureStorage starting from index.\n\n        Notes\n        ------\n            If index is None, append data_array to feature.\n\n            If len(data_array) == 0; return\n\n            If (index - self.end_index) >= 1, self[end_index+1: index] will be filled with np.nan\n\n        Examples\n        ---------\n            .. code-block::","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/data/storage/storage.py#L276-L312","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use an existing concrete implementation (FileFeatureStorage) via the storage factory","Implement `end_index` in your subclass returning the last stored index or None if empty","Implement the full abstract interface (data, start_index, end_index, clear, write) before using the subclass","Add unit tests that instantiate your backend and assert start/end index behavior"],"exampleFix":"// before\nclass MyStorage(FeatureStorage):\n    ...\n    # no end_index -> NotImplementedError on append\n\n// after\nclass MyStorage(FeatureStorage):\n    @property\n    def end_index(self):\n        return None if len(self.data) == 0 else int(self.data.index[-1])","handlingStrategy":"type-guard","validationCode":"from qlib.data.storage.storage import FeatureStorage\nassert type(storage).end_index is not FeatureStorage.end_index, 'end_index not implemented'","typeGuard":"def has_concrete_end_index(storage) -> bool:\n    return type(storage).end_index is not FeatureStorage.end_index","tryCatchPattern":"try:\n    ei = storage.end_index\nexcept NotImplementedError as e:\n    raise TypeError(f'{type(storage).__name__} lacks end_index implementation') from e","preventionTips":["Cover all five abstract members when implementing a backend; use a test that touches each one","Log the concrete storage class returned by factories in debug builds"],"tags":["qlib","storage","abstract-method","not-implemented","index"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}