"""Ursa subclasses of the core ``temporaldata`` primitives.
These classes shadow the upstream names so callers do
``from ursa import Data, IrregularTimeSeries, RegularTimeSeries`` and get
drop-in replacements that carry catalog-row metadata. With ``metadata=None``
each class is behaviorally identical to its upstream parent.
Future cloud-streaming subclasses (R2 Zarr / Lance — ENG-899) will subclass
*these* classes, inheriting the metadata slot for free.
Storage convention follows upstream's pattern (``_sampling_rate`` →
``sampling_rate`` property): the row is stored as the private attribute
``_metadata`` so it bypasses ``ArrayDict.__setattr__``'s ndarray check, and
exposed via a read-only ``metadata`` property. The single ``slice``
override per class is needed because upstream's ``slice`` builds the
result via ``__class__.__new__`` and only copies the private attrs it
knows about (``_sampling_rate``, ``_timekeys``, ``_domain``).
"""
from __future__ import annotations
from typing import Any, cast
import numpy as np
from temporaldata import Data as _Data
from temporaldata import IrregularTimeSeries as _IrregularTimeSeries
from temporaldata import RegularTimeSeries as _RegularTimeSeries
from ursa.catalog.schemas import ModalityRow, RecordingRow
[docs]
class Data(_Data): # type: ignore[misc]
"""``temporaldata.Data`` carrying optional :class:`RecordingRow` metadata."""
def __init__(
self,
*,
metadata: RecordingRow | None = None,
**kwargs: Any,
) -> None:
_check_metadata(metadata, RecordingRow, "Data")
super().__init__(**kwargs)
self._metadata = metadata
@property
def metadata(self) -> RecordingRow | None:
return self._metadata
[docs]
def slice(self, start: float, end: float, reset_origin: bool = True) -> "Data":
out = cast("Data", super().slice(start, end, reset_origin))
out._metadata = self._metadata
return out
[docs]
class IrregularTimeSeries(_IrregularTimeSeries): # type: ignore[misc]
"""``temporaldata.IrregularTimeSeries`` carrying optional :class:`ModalityRow` metadata."""
def __init__(
self,
timestamps: np.ndarray,
*,
metadata: ModalityRow | None = None,
**kwargs: Any,
) -> None:
_check_metadata(metadata, ModalityRow, "IrregularTimeSeries")
super().__init__(timestamps, **kwargs)
self._metadata = metadata
@property
def metadata(self) -> ModalityRow | None:
return self._metadata
[docs]
def slice(self, start: float, end: float, reset_origin: bool = True) -> "IrregularTimeSeries":
out = cast("IrregularTimeSeries", super().slice(start, end, reset_origin))
out._metadata = self._metadata
return out
[docs]
class RegularTimeSeries(_RegularTimeSeries): # type: ignore[misc]
"""``temporaldata.RegularTimeSeries`` carrying optional :class:`ModalityRow` metadata."""
def __init__(
self,
*,
metadata: ModalityRow | None = None,
**kwargs: Any,
) -> None:
_check_metadata(metadata, ModalityRow, "RegularTimeSeries")
super().__init__(**kwargs)
self._metadata = metadata
@property
def metadata(self) -> ModalityRow | None:
return self._metadata
[docs]
def slice(self, start: float, end: float, reset_origin: bool = True) -> "RegularTimeSeries":
out = cast("RegularTimeSeries", super().slice(start, end, reset_origin))
out._metadata = self._metadata
return out
__all__ = ["Data", "IrregularTimeSeries", "RegularTimeSeries"]