Dataset
timenet.dataset ¶source
The in-memory TimeF model a connector populates during convert().
TimeAxis
module-attribute
¶source
TimeAxis = RegularAxis | IrregularAxis | OrdinalAxis
Every shape a series' time axis can have.
AxisType ¶source
Bases: StrEnum
Name which shape a series' time axis has.
TimeF stores this value and dispatches on it before it reads any shape-specific column. TimeF never infers the case from which columns came back null.
IrregularAxis
dataclass
¶source
A placement no formula produces, so this axis stores every time offset.
This axis holds only the pair a builder can state and the writer can verify without a read. That
pair is the first and the last stored time offset. The time offsets themselves live in the shared
stored axis. Reach them through :attr:~timenet.dataset.Signal.time_offsets_us.
That split is the point. Two ints compare and hash, so the axis goes whole into the writer's series identity and round-trips as a value through the records struct. An axis holding the array does neither: a tuple comparison against an ndarray field raises instead of answering.
The endpoints are metadata about the stream, not an identity for it. Two series whose time offsets differ only in the middle carry equal axes. Nothing can use axis equality to conclude the time offsets agree. Compare the streams instead.
This axis has no time_offset_us and no index_at_or_after on purpose. Both need a read, and a
read is a series-level operation. :class:OrdinalAxis sets the precedent: an axis that cannot
answer in constant time does not offer the method.
first_us
instance-attribute
¶source
first_us: int
Time offset of the first value, in microseconds from the record's relative zero.
last_us
instance-attribute
¶source
last_us: int
Time offset of the last value. The writer checks it against the stream at write time, so it is verified metadata, not an unbacked claim.
spanning
classmethod
¶source
Build the axis describing a stream of time offsets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time_offsets_us
|
ndarray | Sequence[int]
|
The per-value time offsets, in microseconds from the record's relative zero. |
required |
Returns:
| Type | Description |
|---|---|
Self
|
The axis carrying that stream's endpoints, after :func: |
Record
dataclass
¶source
Bases: SupportsAnnotate
One logical unit of time-series data: a recording, a session, a sensor bundle, a market window.
You create a record with :meth:~timenet.dataset.TimeFDataset.add_record. The record is mutable,
so you can add annotations after construction.
Use metadata for untyped JSON details. Record-level facts, such as a subject's age or the
recording device, are :class:~timenet.types.Annotation objects with no span. Such an annotation can
also state a unit, and it travels with every window drawn later from the record.
annotations
class-attribute
instance-attribute
¶source
annotations: tuple[Annotation, ...] = ()
Annotations attached to the record.
has_absolute_time
property
¶source
has_absolute_time: bool
Whether this record's relative timeline has a Unix-time anchor.
id
property
¶source
id: EntityId
The record's id, unique among the records of its dataset.
:meth:~timenet.dataset.TimeFDataset.add_record sets it, and the reader sets it on read-back.
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the record is not in a dataset yet. |
metadata
class-attribute
instance-attribute
¶source
metadata: JsonMapping = field(default_factory=dict)
Optional JSON-compatible recording metadata.
sources
class-attribute
instance-attribute
¶source
The root sources that belong to this recording, each with a distinct name.
start_time
class-attribute
instance-attribute
¶source
start_time: TimeOrigin = field(default_factory=TimeOrigin)
The common relative zero, with an optional absolute timestamp.
time_span
class-attribute
instance-attribute
¶source
time_span: TimeInterval | None = None
The session's overall span on the source recording timeline: an :class:~timenet.types.TimeInterval
covering the whole record, or None. Declare it when the series have gaps and an event may fall in
one, for example a note taken while every sensor was briefly off. This checks an unscoped span
against it, rather than against the union of the series' windows. Its time_series must be
None, and it must contain every series' window.
add_annotations ¶source
add_annotations(
annotations: Iterable[Annotation],
*,
warn_when_outside: bool = True,
) -> tuple[Annotation, ...]
Attach several annotations to the record, all together or not at all.
The whole batch is validated before any of it is attached: if one annotation fails a check, the
call raises and leaves the record unchanged. To keep the annotations before a failure attached,
loop :meth:annotate instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
annotations
|
Iterable[Annotation]
|
The annotations to attach. Pass a single one to :meth: |
required |
warn_when_outside
|
bool
|
As on :meth: |
True
|
Returns:
| Type | Description |
|---|---|
tuple[Annotation, ...]
|
New occurrences that share the input annotations' reusable content, in the order given. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
as documented on :meth: |
annotate ¶source
annotate(
annotation: Annotation,
*,
warn_when_outside: bool = True,
) -> Annotation
Attach an annotation to the record and return it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
annotation
|
Annotation
|
The annotation to attach. |
required |
warn_when_outside
|
bool
|
Warn and keep the span when it leaves its window, rather than raise. |
True
|
Returns:
| Type | Description |
|---|---|
Annotation
|
A new occurrence that shares the input annotation's reusable content. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the annotation's span references a series not on this record. If a
scoped span names a timeless series. If the span falls outside the window its scope
selects: the intersection of named series, the record's |
time_interval ¶source
time_interval(
start: datetime,
end: datetime,
*,
time_series: tuple[Signal, ...] | None = None,
) -> TimeInterval
Build a :class:~timenet.types.TimeInterval between two wall-clock moments on this timeline.
The Record must have a known absolute timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
datetime
|
Wall-clock start, timezone-aware. |
required |
end
|
datetime
|
Wall-clock end, exclusive and timezone-aware. |
required |
time_series
|
tuple[Signal, ...] | None
|
Series the interval is scoped to. |
None
|
Returns:
| Type | Description |
|---|---|
TimeInterval
|
The half-open interval, in microseconds from this record's relative zero. |
time_point ¶source
Build a :class:~timenet.types.TimePoint at a wall-clock moment on this record's timeline.
The Record must have a known absolute timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
at
|
datetime
|
The wall-clock moment, timezone-aware. |
required |
time_series
|
tuple[Signal, ...] | None
|
Series the point is scoped to. |
None
|
Returns:
| Type | Description |
|---|---|
TimePoint
|
The point, in microseconds from this record's relative zero. |
to_arrow ¶source
Read the sole signal's values as an Arrow array, for the common single-signal record.
Returns:
| Type | Description |
|---|---|
Array
|
The single :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the record has more than one signal, read |
to_numpy ¶source
Read the sole signal's values as NumPy, without building Arrow when they are NumPy.
Returns:
| Type | Description |
|---|---|
ndarray
|
The single :class: |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the record does not have exactly one signal. |
walk_annotations ¶source
walk_annotations() -> Iterable[Annotation]
Yield annotation occurrences from this Record, its Sources, and its Signals.
RegularAxis
dataclass
¶source
A constant cadence with an offset from the record's relative zero.
The origin is an index into the cadence, not a time, because a window rarely starts on a whole microsecond. At 44.1 kHz only 3 of 1000 window starts do, so a microsecond origin is inexact for almost every window. An index is exact for all of them.
axis_type
class-attribute
¶source
The stored discriminator. Each shape declares its own tag, so a new shape must declare one too.
offset_us
class-attribute
instance-attribute
¶source
offset_us: int = 0
Whole microseconds from the record origin to the cadence's zero.
period_us
instance-attribute
¶source
period_us: Fraction
Microseconds between values. It is a :class:~fractions.Fraction because not every real rate is
a whole number of microseconds: 360 Hz is 25000/9 and 256 Hz is 15625/4. TimeF stores it as its
numerator and denominator.
start_index
class-attribute
instance-attribute
¶source
start_index: int = 0
Index of this series' first value on the cadence. It is non-zero for a window cut from a longer recording, which keeps a span written against the recording meaningful on the window.
at_index ¶source
Return the axis of a window that starts index values into this one.
This is exact at every rate, because the origin it moves is an index, not a derived time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
index
|
int
|
How many values into this axis the window starts. |
required |
Returns:
| Type | Description |
|---|---|
Self
|
The window's axis, which shares this period. |
from_rate_hz
classmethod
¶source
Build the axis of a regularly sampled series from its exact rate.
This method does not accept a float. Every real sampling rate is a whole number of values per
second, so write 500.0 as 500. A rate that is not whole has no single reading: 29.97
fps is 2997/100 by its spelling and 30000/1001 by its intent. Those two drift 3.6 ms apart
over an hour. State which one with a :class:~fractions.Fraction, and build the Fraction from
a string, not a float. Fraction(29.97) is the binary expansion
(1054475631502295/35184372088832), and Fraction("29.97") is 2997/100.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rate_hz
|
int | Fraction
|
Values per second. |
required |
offset_us
|
int
|
Whole microseconds from the record origin to the cadence's zero. |
0
|
Returns:
| Type | Description |
|---|---|
Self
|
The axis whose period is one sampling period of |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
index_at_or_after ¶source
Return the first value at or after a time offset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time_offset_us
|
int
|
The time offset, in microseconds from the record's relative zero. |
required |
Returns:
| Type | Description |
|---|---|
int
|
The index within this series, which is negative if the time offset precedes its first value. |
time_offset_us ¶source
Return the time offset of one value, floored to whole microseconds.
This floor pairs with the ceiling in :meth:index_at_or_after. The two are exactly inverse at
every period of one microsecond or coarser, including the non-integral ones.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
index
|
int
|
The value's index within this series. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Microseconds from the record's relative zero. |
Signal
dataclass
¶source
Bases: SupportsAnnotate
Reference to one logical stream of time-series data, with optional windowing and lazy values.
Each Signal has exactly one owning Source. Several Signals can share an immutable TimeAxis or
TimeSeriesSpec. Consumers read values through :meth:to_arrow or :meth:to_numpy, which apply the
spec. The values sit behind an internal :class:~timenet.types.ArrayHandle: the constructor holds
them in memory, and :meth:from_loader takes a handle or a callable.
annotations
class-attribute
instance-attribute
¶source
annotations: tuple[Annotation, ...] = ()
Annotations attached directly to this signal.
id
property
¶source
id: EntityId
The signal's id, unique among the signals of its dataset.
:meth:~timenet.dataset.TimeFDataset.add_record sets it, and the reader sets it on read-back.
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the signal's record is not in a dataset yet. |
is_ordinal
property
¶source
is_ordinal: bool
Whether this series counts steps only and has no timeline, so time spans cannot place it.
metadata
class-attribute
instance-attribute
¶source
metadata: JsonMapping = field(default_factory=dict)
Optional JSON-compatible signal metadata.
n_values
instance-attribute
¶source
n_values: int
The number of values the series holds, one per timestep. If spec gives each timestep a shape,
the series counts one value per timestep, not one per scalar. This matches the count a chunk's
n_values reports.
span_us
property
¶source
The half-open microsecond window this series covers, or None if it has no timeline.
The axis derives this window, so the window and the axis cannot disagree. The dispatch ends in
:func:~typing.assert_never, so a new axis shape breaks this method at type-check time.
Returns:
| Type | Description |
|---|---|
tuple[int, int] | None
|
|
spec
instance-attribute
¶source
spec: TimeSeriesSpec
Measurement-modality contract: type tag, units, dtype, and per-timestep shape.
time_axis
instance-attribute
¶source
time_axis: TimeAxis
Where this series' values sit in time. A :class:~timenet.dataset.axis.RegularAxis gives a
cadence, an :class:~timenet.dataset.axis.IrregularAxis stores per-value time offsets, and an
:class:~timenet.dataset.axis.OrdinalAxis marks a sequence with no time at all.
annotate ¶source
annotate(annotation: Annotation) -> Annotation
Attach one annotation and return it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
annotation
|
Annotation
|
The annotation to attach. |
required |
Returns:
| Type | Description |
|---|---|
Annotation
|
The attached annotation. |
from_irregular
classmethod
¶source
from_irregular(
values: ndarray
| Sequence[bool | int | float | str | None]
| Array,
*,
time_offsets_us: ndarray | Sequence[int],
spec: TimeSeriesSpec,
name: str,
full_validation: bool = True,
) -> Signal
Build an irregular series from materialized values and their time offsets.
The axis endpoints come from the stream itself, so the two cannot disagree. You cannot state a
first or last time offset that the time offsets do not have. To convert wall-clock moments, use
:func:~timenet.dataset.axis.time_offsets_from_datetimes before you call.
Numeric NumPy values and normalized time offsets retain their buffers for NumPy reads, which
return read-only arrays. Arrow conversion happens only on an Arrow read. Treat retained input
buffers as read-only.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
ndarray | Sequence[bool | int | float | str | None] | Array
|
The signal values to convert to the spec's dtype. Text and enum specs take
strings. Python |
required |
time_offsets_us
|
ndarray | Sequence[int]
|
One time offset per value, in microseconds from the record's relative zero. |
required |
spec
|
TimeSeriesSpec
|
The series' measurement-modality spec. |
required |
name
|
str
|
The signal name. |
required |
full_validation
|
bool
|
Check timestamp ordering by default. Set to |
True
|
Returns:
| Type | Description |
|---|---|
Signal
|
The constructed :class: |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the time offsets are unusable, or there is not exactly one per value. |
from_loader
classmethod
¶source
from_loader(
*,
spec: TimeSeriesSpec,
time_axis: TimeAxis,
name: str,
loader: ArrayHandle | Callable[[], Array],
n_values: int,
time_offsets_loader: ArrayHandle
| Callable[[], Array]
| None = None,
annotations: tuple[Annotation, ...] = (),
metadata: JsonMapping | None = None,
) -> Signal
Build a signal whose values are loaded only when they are read.
loader and time_offsets_loader each take a value handle, which the signal keeps as it
is, or a plain callable returning an Arrow array, which the signal calls on every read. A
callable with its own read_steps() is rejected: subclass ArrayHandle to keep its range
reads.
Returns:
| Type | Description |
|---|---|
Signal
|
A signal backed by |
from_values
classmethod
¶source
from_values(
values: ndarray
| Sequence[bool | int | float | str | None],
*,
spec: TimeSeriesSpec,
name: str,
time_axis: TimeAxis,
) -> Signal
Build a series from already-materialized values and hold them in memory in the spec's dtype.
Numeric NumPy arrays retain their buffers when dtype and layout already match the spec.
NumPy reads return fresh read-only views; treat the input buffers as read-only while in use.
Arrow conversion happens only on an Arrow read. Other inputs become Arrow arrays immediately.
The array length sets n_values.
For files or remote sources, use :meth:from_loader and supply the length. That constructor
does not read the values immediately.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
ndarray | Sequence[bool | int | float | str | None]
|
The signal values to convert to the spec's dtype. Text and enum specs take
strings. Python |
required |
spec
|
TimeSeriesSpec
|
The series' measurement-modality spec. |
required |
name
|
str
|
The signal name. |
required |
time_axis
|
TimeAxis
|
Where the values sit in time. |
required |
Returns:
| Type | Description |
|---|---|
Signal
|
The constructed :class: |
is_selected_by ¶source
Return whether span applies to this series.
A step span selects only the series it counts on. A time span with no time_series
selects every series, and a time span with time_series set selects only the series it
lists. Series are compared by identity, not by name, so a span does not select a slice of a
series it names: the slice is a new series.
This checks the scope only, not the time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
span
|
Span
|
A time or step span, point or interval. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
overlaps_with ¶source
Return whether at least one value of this series falls inside span.
A value is inside when its time offset falls in [start_us, exclusive_end), the rule
:meth:slice uses, so for a time interval slice(span, clip=True) keeps a value whenever
this returns True. This compares times only and ignores the span's time_series: ask
:meth:is_selected_by whether the span applies to this series.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
span
|
TimeSpan
|
A time interval or time point on the record timeline. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
read_steps ¶source
Read a half-open temporal step range as Arrow without forcing a NumPy conversion.
A series whose stored values were loaded, or that holds its values in memory, is sliced. An unloaded stored series reads only the chunks that intersect the range, and one from a loader callable is read in full first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
int
|
First temporal step, inclusive. |
required |
stop
|
int
|
Last temporal step, exclusive. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
A primitive Arrow array for scalar series or a fixed-shape tensor array for N-D series. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the range is negative or reversed. |
slice ¶source
Return a new lazy series that holds only the steps span covers.
The span must hold at least one value. A step span must count on this series. A time span is
placed by time only, so ask :meth:is_selected_by first when the scope matters. The slice
keeps the name, spec, metadata, and place on the timeline, drops annotations, and reads no
values until it is read::
if signal.overlaps_with(interval):
part = signal.slice(interval, clip=True)
The "Cut a window" docs show how to cut every signal of a record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
span
|
Span
|
The interval to keep: a time interval within :attr: |
required |
clip
|
bool
|
Keep the part of the span inside this series instead of raising when the span reaches past it. |
False
|
Returns:
| Type | Description |
|---|---|
Signal
|
A lazy :class: |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
step_range ¶source
Return the half-open step range (start, stop) of this series that span covers.
The bridge to step-based forecasting libraries: stop - start is the horizon h that
GluonTS, Nixtla, and fev speak in. The pair feeds :meth:read_steps to read the ground
truth. A step span already counts in this series' own steps, so it is the range, bounded by the
series' length. The axis locates a time span instead: the steps whose time offsets fall in
[start_us, end_us), each rounded up to the next step. An ordinal series has no timeline, so a
time span has no answer on it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
span
|
Span
|
The interval to locate. A step span must name this series. |
required |
Returns:
| Type | Description |
|---|---|
tuple[int, int]
|
|
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
time_offsets_us ¶source
Read this series' per-value time offsets.
Only an irregular series has this. A regular axis computes its time offsets without a read, and an ordinal one has none. So neither has a stream to return.
Returns:
| Type | Description |
|---|---|
ndarray
|
One int64 microsecond time offset per value. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If this series' axis is not an
:class: |
to_arrow ¶source
Read the series' values as an Arrow array.
Returns:
| Type | Description |
|---|---|
Array
|
A primitive array for scalar values or a fixed-shape tensor array for N-D values. |
to_numpy ¶source
Read the series' values as a read-only NumPy array.
Returns:
| Type | Description |
|---|---|
Shaped[ndarray, ' time *value']
|
The series' values with shape |
Raises:
| Type | Description |
|---|---|
TimeFNullValuesError
|
If a timestep is missing or only partially present. Use
:meth: |
SignalSelection
dataclass
¶source
A validated set of signals selected from one source subtree.
annotate ¶source
annotate(annotation: Annotation) -> tuple[Annotation, ...]
Attach one annotation content item to the selected signals.
Timed and static annotations create one occurrence per selected Signal. Each occurrence shares the original content. All selected Signals are validated before any annotation is attached.
Returns:
| Type | Description |
|---|---|
tuple[Annotation, ...]
|
The attached occurrences in selection order. |
from_source
classmethod
¶source
from_source(
source: Source,
*,
signals: tuple[Signal, ...] | None,
signal_names: tuple[str, ...] | None,
) -> SignalSelection
Resolve an object or name selection against a source subtree.
Returns:
| Type | Description |
|---|---|
SignalSelection
|
The validated selection. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If selectors are missing, mixed, duplicated, ambiguous, or unknown. |
Source
dataclass
¶source
Bases: SupportsAnnotate
A device, sensor, or subsystem that contains child sources and signals.
annotations
class-attribute
instance-attribute
¶source
annotations: tuple[Annotation, ...] = ()
Annotations attached to this source.
metadata
class-attribute
instance-attribute
¶source
metadata: JsonMapping = field(default_factory=dict)
Optional JSON-compatible source metadata.
sources
class-attribute
instance-attribute
¶source
Direct child sources, each with a distinct name. Their order has no semantic meaning.
annotate ¶source
annotate(annotation: Annotation) -> Annotation
select ¶source
select(
*,
signals: tuple[Signal, ...] | None = None,
signal_names: tuple[str, ...] | None = None,
) -> SignalSelection
Select descendant signals by object or by human-readable name.
Returns:
| Type | Description |
|---|---|
SignalSelection
|
A selection that can be annotated as one declarative operation. |
walk_signals ¶source
Yield every descendant signal in deterministic source and signal order.
Yields:
| Type | Description |
|---|---|
Signal
|
Signals from this source and every descendant source. |
walk_sources ¶source
Yield this source and all descendants in deterministic depth-first order.
Yields:
| Type | Description |
|---|---|
Source
|
This source followed by its descendants, sorted by name at each level. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the graph contains a cycle or one source has two parents. |
TimeFDataset ¶source
Bases: SupportsAnnotate
Holds records and their tasks as Python objects. It does not do I/O. The writer handles persistence.
annotations
property
¶source
annotations: tuple[Annotation, ...]
Annotations attached to the dataset itself.
has_task_stream
property
¶source
has_task_stream: bool
Whether tasks stream from a source (see :meth:set_task_stream) rather than the _tasks list.
last_ids
property
¶source
last_ids: dict[ObjectKind, EntityId]
The last id used per kind. A written version stores it, so later edits never reuse an id.
lineage
property
¶source
The card of every ancestor release, parents included, keyed by org/name@version.
The mapping is read-only. :meth:import_from adds to it.
parent_cards
property
¶source
parent_cards: Mapping[ParentAlias, ParentDatasetCard]
A copy of the card of each parent this dataset imports from, by parent alias.
The mapping is read-only. :meth:import_from adds to it.
records
property
¶source
All records of the dataset.
For a dataset read from a release, the records come in the release's record order, as
:meth:~timenet.reader.TimeFReader.record_ids lists it. Records added later follow them.
For a dataset built in memory, the records come in the order in which they were added.
schema
property
¶source
schema: DatasetSchema | None
The derived schema, or None until :meth:derive_schema is called.
add_record ¶source
Register and return a complete record.
The record and each of its signals get the next id of their kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
Record
|
The complete record hierarchy to register. |
required |
Returns:
| Type | Description |
|---|---|
Record
|
The same :class: |
add_task ¶source
Validate and register one fully constructed task.
The Task owns its input and target object references. Registration verifies those objects against this dataset before it changes the dataset. It does not change the input Records. The task gets the next task id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task
|
Task
|
The concrete task to register. |
required |
Returns:
| Type | Description |
|---|---|
Task
|
The same task instance. |
add_tasks ¶source
Register several complete tasks, all together or not at all.
The method validates the whole batch before it attaches any task. If one task fails a
check, the call raises an error, and the dataset and every task in the batch stay
unchanged. To keep the tasks that passed before a failure, call :meth:add_task in a
loop instead.
A task can derive from another task in the same batch. To do this, list the parent task
in the deriving task's from_tasks field. The batch is checked as a unit, so the order
of tasks within tasks does not matter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tasks
|
Iterable[Task]
|
The task instances to register. For a single task, use :meth: |
required |
Returns:
| Type | Description |
|---|---|
tuple[Task, ...]
|
The registered tasks, in the order given. |
annotate ¶source
annotate(annotation: Annotation) -> Annotation
Attach a static annotation to the dataset.
Returns:
| Type | Description |
|---|---|
Annotation
|
The attached occurrence. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the annotation has a time placement, which is ambiguous across records. |
derive_schema ¶source
derive_schema() -> DatasetSchema
Walk the dataset's instances and build its :class:DatasetSchema.
This method collects the distinct spec, annotation, and task types. It stores the result on the dataset, and it returns the result.
Returns:
| Type | Description |
|---|---|
DatasetSchema
|
The derived :class: |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If one spec type or annotation key yields conflicting descriptors across records. |
describe ¶source
Print a plain-text summary of the dataset: its identity, counts, specs and columns, and a record preview.
This method works like pandas' describe and info methods. The preview reads only
span metadata, not series values. The method checks value dtypes from one series per
spec. This method works even before :meth:derive_schema runs, because it computes
everything from the records.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rows
|
int
|
The number of records to show in the preview. |
5
|
file
|
TextIO | None
|
Where to write the output. The default is |
None
|
from_parts
classmethod
¶source
from_parts(
*,
metadata: DatasetMetadata,
records: Iterable[Record],
tasks: Iterable[Task],
schema: DatasetSchema,
annotations: Iterable[Annotation] = (),
last_ids: Mapping[ObjectKind, EntityId] | None = None,
import_state: ImportState | None = None,
) -> TimeFDataset
Build a dataset from parts that are already constructed.
The reader uses this method when it reads a dataset back from disk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
metadata
|
DatasetMetadata
|
The dataset's descriptive identity. |
required |
records
|
Iterable[Record]
|
Fully built records. Their loaders pull data from disk. |
required |
tasks
|
Iterable[Task]
|
Fully built tasks, with their |
required |
schema
|
DatasetSchema
|
The schema reconstructed from the manifest. |
required |
annotations
|
Iterable[Annotation]
|
Annotations attached directly to the dataset. |
()
|
last_ids
|
Mapping[ObjectKind, EntityId] | None
|
The id counters of the dataset these parts come from, so new objects never reuse the id of a removed one. |
None
|
import_state
|
ImportState | None
|
The parent cards, the lineage, and the import map of the dataset these parts come from. The new dataset keeps this object. Without it, the dataset starts with no parent cards, no lineage, and an empty import map. |
None
|
Returns:
| Type | Description |
|---|---|
TimeFDataset
|
The dataset, built from these parts. The records, signals, and tasks keep the ids they |
TimeFDataset
|
have. |
get_split ¶source
Return the tasks of one split, in insertion order.
A dataset partitions its tasks by setting :attr:~timenet.types.Task.split on each one.
Records carry no split of their own: a record may serve tasks of several splits. A streamed
dataset drains its stream and materializes the selection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
split
|
Split | str
|
The partition to select, as a :class: |
required |
Returns:
| Type | Description |
|---|---|
tuple[Task, ...]
|
The matching tasks. Empty when the dataset partitions its tasks but none is in |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
get_splits ¶source
Return the union of selected splits without changing task assignments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*splits
|
Split | str
|
One or more partitions, such as |
()
|
Returns:
| Type | Description |
|---|---|
Task
|
Matching tasks in dataset order. Repeated split names do not duplicate tasks. |
...
|
Tasks without a split are excluded. A streamed dataset is read once to materialize |
tuple[Task, ...]
|
the selection. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If no splits are supplied, a name is unknown, or the dataset assigns no split to any task. A missing partition otherwise returns no tasks. |
import_from ¶source
import_from(
parent: TimeFReader,
*,
alias: ParentAlias | None = None,
records: Iterable[EntityId] = (),
signals: Iterable[EntityId] = (),
tasks: Iterable[EntityId] = (),
load: LoadPlan = ALL_LAZY,
) -> ImportedDataset
Copy Records, Signals, and tasks from a parent release into this dataset.
The parent must be a release that metadata.parents declares. The call records the parent
in :attr:parent_cards and :attr:lineage. It does not change the card of this dataset.
records=copies each Record whole, with its Sources, Signals, and annotations.signals=copies each Signal into a copy of its Record and of the Sources above it. Such a partial copy keeps the annotations that its Signals place.tasks=copies each task with the Records and Signals that it references and the tasks that it derives from. Each annotation that a task references points at the matching occurrence on the copy of its owner. If this dataset changed or removed that occurrence, the import attaches a copy of the parent's next to it.
Each copy is this dataset's own object, with new IDs and its own metadata and annotations, so
edits do not change the parent. Its Signals keep the parent's value handles, so they read the
parent's stored values unless load loads them. A write of this dataset reuses the parent's
payloads, so it needs the parent release. Annotations on the parent dataset itself come only
with a task that references them.
An import of an object whose copy this dataset holds reuses that copy, with this dataset's
edits. If the call needs Signals that the copy of a Record lacks, it adds them to that copy,
with the Sources and annotations that they bring. An object whose copy this dataset removed is
copied again, under a new ID. An edit such as :func:~timenet.dataset.edit.remove_signals
keeps the import state in the dataset it builds, so an import into that dataset works the
same way. Imports are safe to repeat: if a call fails partway, repeating it completes it.
Select many objects in one call, because each call reads them in batches.
docs/timef-dataset.md describes the rules.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent
|
TimeFReader
|
A reader of the parent release. |
required |
alias
|
ParentAlias | None
|
The parent alias that declares the parent. By default, the alias that the card declares for its release. |
None
|
records
|
Iterable[EntityId]
|
The parent IDs of the Records to copy whole. |
()
|
signals
|
Iterable[EntityId]
|
The parent IDs of the Signals to copy. |
()
|
tasks
|
Iterable[EntityId]
|
The parent IDs of the tasks to copy. |
()
|
load
|
LoadPlan
|
Which kinds of stored values to load. The import reads the parent tasks and Records without their values. Then it loads these kinds on the copies of the selected and needed tasks, Records, and Signals, and on the annotations that it copies, through their own value handles. This includes copies that this dataset holds already. The other Signals of a partial copy stay as they are. The default loads none. |
ALL_LAZY
|
Returns:
| Type | Description |
|---|---|
ImportedDataset
|
The copies of the selected Records, Signals, and tasks, by their parent IDs. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
TimeFNotFoundError
|
If a selected ID names no parent object. This dataset does not change. |
iter_streamed_tasks_validated ¶source
Yield the streamed tasks, validating each against the dataset before it is written.
The id of a streamed task is the task id counter's value at :meth:set_task_stream plus
its position in the stream. Thus every pass over the stream gives the task the same id.
Streamed tasks skip :meth:add_task's checks, so validate each here as it passes through: an
undeclared type, an attachment to an unknown record, a dangling reference, a bad answer, or an
out-of-window span raises before the task reaches disk. The dataset holds no task list. Thus
the cross-task checks (from_tasks derivations) that need every task at once do not run
for a stream.
Yields:
| Type | Description |
|---|---|
Task
|
Each validated task, in the source's order. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If a streamed task fails one of the per-task checks. |
iter_tasks ¶source
iter_tasks(
*,
required_modalities: Iterable[InputModality]
| None = None,
supported_modalities: Iterable[InputModality]
| None = None,
split: Split
| str
| Iterable[Split | str]
| None = None,
) -> Iterator[Task]
Yield the dataset's tasks, from the stream when one is set, else the materialized list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
split
|
Split | str | Iterable[Split | str] | None
|
One split or an iterable of splits to select, or |
None
|
Yields:
| Type | Description |
|---|---|
Task
|
Each task. A streamed dataset re-reads its source on every call. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the selection is empty or contains an unknown split. |
set_task_stream ¶source
Provide tasks as a re-iterable stream instead of materializing them in the dataset.
For a dataset with far more tasks than records (many questions over few recordings), holding
every task in memory does not scale. A streaming connector builds the bounded records. Then it
gives the tasks through source. The writer streams them to disk without a list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task_types
|
Sequence[type[Task]]
|
The task classes the stream yields, so :meth: |
required |
source
|
Callable[[], Iterator[Task]]
|
A callable returning a fresh iterator over the tasks each time it is called. The writer calls it more than once (a peek for id storage, then the write), so it must re-read its source rather than exhaust a one-shot generator. |
required |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If tasks were already added with :meth: |
tasks_for ¶source
Return the tasks that take a record as input, optionally filtered by type.
Tasks reference their records, so this method scans the tasks for the ones whose inputs hold this record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
Record
|
The record whose tasks to find. |
required |
task_type
|
type[Task]
|
Keep only tasks of this subclass. The default keeps every task on the record. |
Task
|
Returns:
| Type | Description |
|---|---|
tuple[Task, ...]
|
The record's tasks of |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
to_features_and_targets ¶source
to_features_and_targets(
*,
task: type[Task] | None = None,
output: Literal["arrow", "numpy"] = "arrow",
features: Literal["timestep", "series"] = "timestep",
split: Split | str | None = None,
) -> tuple[Array, Array] | tuple[ndarray, ndarray]
Build an (X, y) training pair. By default, this method defers materialization.
This method requires every record to carry exactly one task of task. It pairs the
values of that task's sole signal with the task's only scalar target. With split, only
the tasks of that split count, and a record that has none of them is left out rather than
rejected, so one call builds (X_train, y_train) and another (X_test, y_test). The
features argument chooses the shape of X:
"timestep"(the default): one feature per point, in a rectangular matrix. This needs equal-length records. The result is an ArrowFixedSizeListArray[T], or a NumPy(n, T)array offloat32values."series": one sequence feature per record, so variable-length series work too. The result is an ArrowListArray, or a NumPy(n,)object array of 1-D arrays.
With output="arrow" (the default), the method builds these arrays straight from the
series loaders, with no NumPy copy in between. With output="numpy", the method
materializes them. y is always the targets, as an Arrow string array or a 1-D NumPy
array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task
|
type[Task] | None
|
The task type to read targets from, for example
:class: |
None
|
output
|
Literal['arrow', 'numpy']
|
Use |
'arrow'
|
features
|
Literal['timestep', 'series']
|
Use |
'timestep'
|
split
|
Split | str | None
|
Keep only the tasks of this split, or |
None
|
Returns:
| Type | Description |
|---|---|
tuple[Array, Array] | tuple[ndarray, ndarray]
|
|
tuple[Array, Array] | tuple[ndarray, ndarray]
|
|
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
This error occurs if |
write ¶source
write(
*,
path: str | Path,
values_backend: ValuesBackend = PARQUET,
) -> Path
Write this dataset as one immutable TimeF version.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Registry root under which the dataset ID and version directories are created. |
required |
values_backend
|
ValuesBackend
|
Typed values-plane backend selection. |
PARQUET
|
Returns:
| Type | Description |
|---|---|
Path
|
The committed version directory. |