Format
timenet.format ¶source
The TimeF on-disk format contract: filenames, layout templates, and pinned Arrow schemas.
The writer and the reader both use this module. They are otherwise independent. The definitions that both sides of the round-trip must agree on live here, so neither side imports the other.
annotation_codec ¶source
Codec between an annotation's value and the typed value columns of annotation_contents.
An annotation value is a string, an integer, a float, a boolean, a list of strings, or absent for a pure marker. Each shape has its own column so DuckDB can filter on it and the reader hands back the exact Python type that was written: an integer stays an integer and a boolean stays a boolean.
VALUE_COLUMNS
module-attribute
¶source
VALUE_COLUMNS = (
"value_kind",
"text_value",
"integer_value",
"float_value",
"boolean_value",
"text_list_value",
)
The annotation_contents columns that together hold one value.
VALUE_KINDS
module-attribute
¶source
VALUE_KINDS = tuple(
(kind.value) for kind in AnnotationValueKind
)
Every value_kind a stored annotation may carry. A marker has NULL.
decode_annotation_value ¶source
decode_annotation_value(
value_kind: str | None,
text_value: str | None,
integer_value: int | None,
float_value: float | None,
boolean_value: bool | None,
text_list_value: list[str] | None,
) -> Any
Rebuild one annotation value from its columns.
Returns:
| Type | Description |
|---|---|
Any
|
The value in the Python type it was written with, or |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the kind is unknown or its column is NULL. |
encode_annotation_value ¶source
Project one annotation value onto the value columns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
object
|
The annotation's value, or |
required |
label
|
str
|
How to name the annotation in an error message. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
One entry per :data: |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the value is not one of the supported shapes. |
annotation_value_kind ¶source
checksums ¶source
File checksums recorded in the manifest and verified on read.
The reader must hash files the same way the writer did, or :meth:~timenet.reader.TimeFReader.verify
means nothing. The algorithm and the block size live here so both sides call the same code.
stream_checksum ¶source
stream_checksum(handle: _Readable) -> str
Return an open binary stream's manifest checksum, hashing it a block at a time.
This is the stream counterpart of :func:file_checksum. A reader can use it to hash a file
opened through a pyarrow filesystem (local now, an object store later) instead of a local
Path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
handle
|
_Readable
|
An open binary stream positioned at the start. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The checksum as |
constants ¶source
On-disk filenames and layout templates for the TimeF format.
check_relative_path ¶source
Reject a path that would resolve outside the dataset root it is meant to stay under.
Callers join a manifest file entry and a registry handle's relpath onto a root directory
(or filesystem prefix) as-is. An absolute path or a .. segment would escape that root instead
of raising. This would let a crafted manifest or caller read or write outside the intended
directory. Stored paths use forward slashes on every platform; Windows drive paths and
backslashes are rejected even when validation runs on another operating system.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the field to check. It appears in the error message. |
required |
path
|
str
|
The path to check. It must be relative and rooted inside the dataset. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The validated path. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
part_path ¶source
Render a numbered part/shard path, refusing an index that would overflow the fixed width.
The reader visits parts in the order the manifest lists them. The zero-padded names keep an
ls or a prefix listing in that same order. That order only holds while every number fits in
PART_INDEX_DIGITS. A ninth digit sorts before the eighth and silently breaks it. Routing
every part name through here turns that overflow into a loud error instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
template
|
str
|
A layout template whose part number is the |
required |
index
|
int
|
The zero-based part number to render. |
required |
fields
|
str
|
Any remaining named fields the template needs, for example |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
The formatted version-relative path. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
control_audit ¶source
Audit a finished control.duckdb for relational integrity.
The control database has no persisted constraints. ART indexes on large tables such as
signal_chunks make every write slower and the file larger. Instead, the writer keeps the
invariants while it streams rows. It checks them in Python with ID sets. This module holds the SQL
form of the same invariants. It scans every table, so it is not part of the write path. Tests run it
after each round trip, and tooling can run it on a published version.
CROSS_RECORD_PARENT
module-attribute
¶source
CROSS_RECORD_PARENT = "\n SELECT child.source_id\n FROM sources child\n JOIN sources parent ON parent.source_id = child.parent_source_id\n WHERE child.record_id <> parent.record_id\n LIMIT 1\n"
SOURCE_CYCLE
module-attribute
¶source
SOURCE_CYCLE = "\n WITH RECURSIVE ancestors(source_id, parent_source_id, path, cyclic) AS (\n SELECT source_id, parent_source_id, [source_id], false FROM sources\n UNION ALL\n SELECT parent.source_id, parent.parent_source_id,\n list_append(ancestors.path, parent.source_id),\n list_contains(ancestors.path, parent.source_id)\n FROM ancestors\n JOIN sources parent ON parent.source_id = ancestors.parent_source_id\n WHERE NOT ancestors.cyclic\n )\n SELECT source_id FROM ancestors WHERE cyclic LIMIT 1\n"
audit_control_database ¶source
audit_control_database(
connection: DuckDBPyConnection,
*,
require_chunks: bool = True,
) -> None
Scan every control table and raise an error at the first broken rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
DuckDBPyConnection
|
An open connection to the control database. |
required |
require_chunks
|
bool
|
Whether every Signal must be covered exactly by |
True
|
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If a key repeats, a reference points to a missing object, or a value is not allowed. Also if Sources do not form separate trees for each Record. Also if an axis or chunk length differs from its Signal. Also if classification labels break a rule of their label set. |
control_cache ¶source
Materialize a verified DuckDB control file behind a local-path seam.
materialize_control ¶source
materialize_control(version: DatasetVersion) -> Path
Return a local path for a version's verified DuckDB control database.
Local versions already satisfy DuckDB's path requirement. For a remote filesystem, this function
downloads only control.duckdb into a checksum-keyed cache. A future remote-attach implementation
can replace this function without changing the schema or query layer.
Returns:
| Type | Description |
|---|---|
Path
|
A local path suitable for a read-only DuckDB connection. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the manifest lacks a control file or the downloaded file fails verification. |
control_reader ¶source
Build the TimeF object hierarchy from control.duckdb.
The objects hold their stored values behind value handles, unloaded.
RECORD_BATCH_SIZE
module-attribute
¶source
The most Records one batch of a Record stream holds, unless the stream sets another batch size.
TASK_BATCH_SIZE
module-attribute
¶source
The most tasks one batch of a task read or stream holds, unless a stream sets another batch size.
ValueLoaderFactory
module-attribute
¶source
ValueLoaderFactory = Callable[
[int, TimeSeriesSpec, int], ArrayHandle
]
DuckDBControlReader ¶source
Keep one read-only DuckDB connection and build requested records from it.
The connection opens again on the next query after :meth:close, and after the process forks,
since every connection closes before a fork.
chunk_location ¶source
chunk_location(signal_id: int) -> ChunkLocation
Return where one Signal's chunks are stored, from its catalog rows.
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the Signal has no stored chunks. |
chunk_locations_by_ids ¶source
chunk_locations_by_ids(
signal_ids: Iterable[int],
) -> dict[int, ChunkLocation | None]
Return where a batch of Signals' chunks are stored, from their catalog rows.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signal_ids
|
Iterable[int]
|
Signal IDs. |
required |
Returns:
| Type | Description |
|---|---|
dict[int, ChunkLocation | None]
|
Locations keyed by Signal ID, each with the Signal's chunks in chunk-index order, or |
dict[int, ChunkLocation | None]
|
|
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If one Signal's chunks are stored by more than one release. |
import_map ¶source
Return the parent release of each parent alias, and the import map of the catalog.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
The parent release that |
ImportMap
|
object in |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the catalog lists a parent alias, or a parent ID under one alias and kind, more than once. |
imported_ids ¶source
imported_ids(
alias: str,
kind: ObjectKind,
parent_ids: Iterable[EntityId],
) -> tuple[str | None, dict[EntityId, EntityId]]
Return the parent release of a parent alias and the local IDs of objects imported under it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alias
|
str
|
The parent alias the objects were imported under. |
required |
kind
|
ObjectKind
|
The kind of the objects. |
required |
parent_ids
|
Iterable[EntityId]
|
The objects' IDs in the parent release. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
The parent release the catalog names for the alias, or |
dict[EntityId, EntityId]
|
the local object ID of each parent ID the catalog knows. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the catalog lists the alias more than once, or lists one of the parent IDs more than once under the alias and kind. |
iter_record_batches ¶source
iter_record_batches(
record_ids: Iterable[int] | None = None,
*,
with_annotations: bool = True,
batch_size: int = RECORD_BATCH_SIZE,
) -> Iterator[tuple[Record, ...]]
Yield complete records one bounded batch at a time, and build each batch on its own.
Without record_ids, the stream reads the Record IDs one page at a time, in read order. A
page holds up to batch_size IDs. The stream builds one batch from each page that is not
empty. The next page starts after the last read order of the page before. The stream stops
after the first page that holds fewer than batch_size IDs. So the stream does not read
all Record IDs before the first batch.
With record_ids, the stream checks every requested ID before it builds the first batch.
Each batch reads only its own rows. The records of a batch share no object with another
batch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_ids
|
Iterable[int] | None
|
Requested IDs in result order, or |
None
|
with_annotations
|
bool
|
Whether to build annotations on records, sources, and signals. |
True
|
batch_size
|
int
|
The most records that a batch holds. By default, a batch holds up to 1,000
records ( |
RECORD_BATCH_SIZE
|
Yields:
| Type | Description |
|---|---|
tuple[Record, ...]
|
The records of each batch, with their stored values behind unloaded handles. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If |
TimeFNotFoundError
|
If a requested record is absent. |
iter_task_batches ¶source
iter_task_batches(
records: Iterable[Record] | None = None,
*,
required_modalities: Iterable[InputModality]
| None = None,
supported_modalities: Iterable[InputModality]
| None = None,
split: Split | str | None = None,
batch_size: int = TASK_BATCH_SIZE,
) -> Iterator[list[Task]]
Yield the tasks whose inputs include one of records, a bounded batch at a time.
Each batch runs a handful of keyed queries and builds only that batch's tasks, so a caller
that walks one Record at a time never holds the whole task table in memory. Only None
skips the input Record filter; an empty collection selects no tasks.
Each batch is built on its own. The parents its tasks derive from through from_tasks,
and the Records, Signals, and annotations they refer to outside records, are built for
the batch and shared only among its tasks, so nothing of a yielded batch stays with the
stream.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record] | None
|
Input Records to select, or |
None
|
split
|
Split | str | None
|
Keep only tasks of this split, or |
None
|
batch_size
|
int
|
The most tasks a batch holds. By default, a batch holds up to 5,000 tasks
( |
TASK_BATCH_SIZE
|
Yields:
| Type | Description |
|---|---|
list[Task]
|
Each batch's concrete tasks, in stable ID order across batches. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If a relationship refers to a missing object or has an invalid field. |
read_annotation_table ¶source
read_annotation_table(
object_type: ObjectKind | None = None,
) -> Table
Return every annotation occurrence joined with its content as Arrow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
object_type
|
ObjectKind | None
|
Keep only occurrences on this object type, or |
None
|
Returns:
| Type | Description |
|---|---|
Table
|
One row per occurrence. Each row has the annotated object's type and ID, the content's |
Table
|
ID and key, typed value columns, unit, span columns, confidence, and JSON metadata. The |
Table
|
object ID is NULL for the Dataset, which has a string |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If |
read_dataset_annotations ¶source
read_dataset_annotations(
dataset_id: str,
*,
by_occurrence: _AnnotationsByOccurrence | None = None,
) -> tuple[Annotation, ...]
Return annotations attached directly to a dataset, as new objects on every call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset_id
|
str
|
The dataset whose annotations to read. |
required |
by_occurrence
|
_AnnotationsByOccurrence | None
|
Filled with every annotation by its occurrence id, so that a task read of the same call can reference these objects. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[Annotation, ...]
|
Dataset-level annotation occurrences in storage order. |
read_last_ids ¶source
read_last_ids() -> dict[ObjectKind, int]
Return the last used id per entity kind, as the writer stored it.
Returns:
| Type | Description |
|---|---|
dict[ObjectKind, int]
|
The stored counters. The result does not include a kind without a stored value. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If a stored counter names an unknown kind or is not an integer. |
read_records ¶source
read_records(
record_ids: Iterable[int] | None = None,
*,
with_annotations: bool = True,
shared_offsets: dict[EntityId, StoredOffsets]
| None = None,
) -> tuple[Record, ...]
Build complete recursive records, with their stored values behind unloaded handles.
Source links, clocks, axes, and time-offset locations are checked before any object is built. No payload file is opened.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_ids
|
Iterable[int] | None
|
Requested IDs in result order, or |
None
|
with_annotations
|
bool
|
Whether to build annotations on records, sources, and signals. |
True
|
shared_offsets
|
dict[EntityId, StoredOffsets] | None
|
Time-offset handles by axis ID, shared with earlier record reads of
the same call, and extended with this read's new ones. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[Record, ...]
|
The built records. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If a requested ID is not an int. |
TimeFNotFoundError
|
If a requested record is absent. |
TimeFFormatError
|
If the stored hierarchy is inconsistent. |
read_signals_by_id ¶source
read_signals_by_id(
signal_ids: Collection[EntityId],
) -> dict[EntityId, Signal]
Build the Records that hold the given Signals, and return those Signals.
Each Record is built once, however many of its Signals are asked for, and the Records of one call share one time-offsets handle per axis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signal_ids
|
Collection[EntityId]
|
The Signals' IDs. |
required |
Returns:
| Type | Description |
|---|---|
dict[EntityId, Signal]
|
The Signals by ID, each inside its Record, with stored values behind unloaded handles. |
Raises:
| Type | Description |
|---|---|
TimeFNotFoundError
|
If an ID names no stored Signal. |
read_target_table ¶source
read_target_table(
record_ids: Iterable[int] | None = None,
*,
required_modalities: Iterable[InputModality]
| None = None,
supported_modalities: Iterable[InputModality]
| None = None,
split: Split | str | None = None,
) -> Table
Return every inline target as Arrow, one typed row each, with references as public IDs.
The columns follow :class:timenet.format.task_target_row.TargetValueRow: a step span names
its one series in span_signal_ids.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_ids
|
Iterable[int] | None
|
Keep only targets of tasks whose inputs include one of these Records. |
None
|
split
|
Split | str | None
|
Keep only targets of tasks of this split, or |
None
|
Returns:
| Type | Description |
|---|---|
Table
|
Targets in task ID and position order. |
read_task_table ¶source
read_task_table(
record_ids: Iterable[int] | None = None,
*,
required_modalities: Iterable[InputModality]
| None = None,
supported_modalities: Iterable[InputModality]
| None = None,
split: Split | str | None = None,
) -> Table
Return the task table as Arrow, with object references as public IDs, without building Tasks.
The table has one row per task. Each row holds the type, prompt, rationale, the four scope
columns, the configuration columns, ordered input_record_ids, ordered from_task_ids,
and the metadata JSON string. Targets are in :meth:read_target_table.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_ids
|
Iterable[int] | None
|
Keep only tasks whose inputs include one of these Records, or |
None
|
split
|
Split | str | None
|
Keep only tasks of this split, or |
None
|
Returns:
| Type | Description |
|---|---|
Table
|
The tasks in task ID order. |
read_tasks ¶source
read_tasks(
records: Iterable[Record] | None = None,
*,
cached_records: Iterable[Record] = (),
dataset_annotations: Mapping[int, Annotation]
| None = None,
required_modalities: Iterable[InputModality]
| None = None,
supported_modalities: Iterable[InputModality]
| None = None,
split: Split | str | None = None,
) -> tuple[Task, ...]
Build every selected task and restore all in-memory object references.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record] | None
|
Input Records to select, or |
None
|
cached_records
|
Iterable[Record]
|
Records already built, to reuse without restricting the selection. |
()
|
dataset_annotations
|
Mapping[int, Annotation] | None
|
The dataset's annotations, already built, by occurrence id, which tasks
then reference instead of their own copies, or |
None
|
split
|
Split | str | None
|
Keep only tasks of this split, or |
None
|
Returns:
| Type | Description |
|---|---|
tuple[Task, ...]
|
Concrete tasks in stable ID order. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If a relationship refers to a missing object or has an invalid field. |
read_tasks_by_id ¶source
read_tasks_by_id(
task_ids: Collection[EntityId],
) -> dict[EntityId, Task]
Build the given tasks, sharing the Records they reference, a bounded batch at a time.
The tasks they derive from through from_tasks are built too.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task_ids
|
Collection[EntityId]
|
The task IDs, each once. |
required |
Returns:
| Type | Description |
|---|---|
dict[EntityId, Task]
|
The tasks by ID. |
Raises:
| Type | Description |
|---|---|
TimeFNotFoundError
|
If an ID names no stored task. |
record_clock_ids ¶source
record_clock_ids(
record_ids: Collection[EntityId],
) -> dict[EntityId, int]
Return the clock of each of the given Records, building no object.
A clock ID names one clock within this catalog only. Records with one clock ID share one
TimeOrigin when a read builds them.
Returns:
| Type | Description |
|---|---|
dict[EntityId, int]
|
The clock ID of each Record, by Record ID. An ID that names no Record is absent. |
run ¶source
run(query: Callable[[DuckDBPyConnection], _T]) -> _T
Run one read through the connection, which opens again first if it was closed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
Callable[[DuckDBPyConnection], _T]
|
Reads through the connection it is given. |
required |
Returns:
| Type | Description |
|---|---|
_T
|
What |
Raises:
| Type | Description |
|---|---|
TimeFReaderError
|
If the connection closed while the read ran, through :meth: |
TimeFFormatError
|
If the catalog lacks a table, column, or type that the read expects. |
Error
|
Any other DuckDB failure, such as I/O, memory, or an interrupt, unchanged. |
signal_record_ids ¶source
signal_record_ids(
signal_ids: Collection[EntityId],
) -> dict[EntityId, EntityId]
Return the ID of the Record that holds each of the given Signals, building no object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signal_ids
|
Collection[EntityId]
|
The Signals' IDs. |
required |
Returns:
| Type | Description |
|---|---|
dict[EntityId, EntityId]
|
The Record ID of each Signal, by Signal ID. |
Raises:
| Type | Description |
|---|---|
TimeFNotFoundError
|
If an ID names no stored Signal. |
task_facts ¶source
Return the per-database facts that task reads need, read once per reader.
Returns:
| Type | Description |
|---|---|
_TaskFacts
|
The IDs of tasks other tasks derive from, and whether any task carries annotations. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If two task rows share an ID. |
control_schema ¶source
The single description of the control database's tables.
The SQL table definitions and the writer's Arrow batch schemas come from :data:CONTROL_TABLES.
The audit also uses it to examine keys and references. Define schema changes there.
This is version 1 of the control schema. Every table except label_sets uses ids as keys.
Records, Signals, and Tasks use the public ids that the caller sees. All other objects use the
writer's storage ids.
Each label set has a unique name in a dataset. The label_sets table uses this name as its key. A foreign key stores the key of the row that it refers to.
Fixed-shape fields are typed columns, so SQL can filter them. Only the free-form metadata
dictionaries are JSON. The database has no persisted constraints. The writer keeps
:data:Table.unique and :data:Table.foreign_keys while it streams rows, and
:func:timenet.format.control_audit.audit_control_database checks them again.
ANNOTATED_OBJECT_TYPES
module-attribute
¶source
ANNOTATED_OBJECT_TYPES: frozenset[ObjectKind] = frozenset(
ANNOTATED_OWNER_TABLES
)
The values annotation_occurrences.object_type can hold.
ANNOTATED_OWNER_TABLES
module-attribute
¶source
ANNOTATED_OWNER_TABLES: dict[
ObjectKind, tuple[str, str] | None
] = {
ObjectKind.DATASET: None,
ObjectKind.RECORD: ("records", "record_id"),
ObjectKind.SOURCE: ("sources", "source_id"),
ObjectKind.SIGNAL: ("signals", "signal_id"),
ObjectKind.TASK: ("tasks", "task_id"),
}
The owner table and key column of each annotated object type. The Dataset has no owner row.
ANNOTATION_CONTENTS
module-attribute
¶source
ANNOTATION_CONTENTS = Table(
"annotation_contents",
(
_required("content_id", ColumnType.BIGINT),
_required("name"),
Column("value_kind", ColumnType.VARCHAR),
Column("text_value", ColumnType.VARCHAR),
Column("integer_value", ColumnType.BIGINT),
Column("float_value", ColumnType.DOUBLE),
Column("boolean_value", ColumnType.BOOLEAN),
Column("text_list_value", ColumnType.VARCHAR_LIST),
Column("unit", ColumnType.VARCHAR),
Column("description", ColumnType.VARCHAR),
_required("metadata", ColumnType.JSON),
),
unique=(("content_id",),),
)
ANNOTATION_OCCURRENCES
module-attribute
¶source
ANNOTATION_OCCURRENCES = Table(
"annotation_occurrences",
(
_required("occurrence_id", ColumnType.BIGINT),
_required("content_id", ColumnType.BIGINT),
_required("object_type"),
Column("object_id", ColumnType.BIGINT),
_required("span_type"),
Column("start_us", ColumnType.BIGINT),
Column("end_us", ColumnType.BIGINT),
Column("provenance", ColumnType.JSON),
Column("confidence", ColumnType.DOUBLE),
_required("metadata", ColumnType.JSON),
),
unique=(("occurrence_id",),),
foreign_keys=(
ForeignKey(
"content_id",
"annotation_contents",
"content_id",
),
),
)
The owner is (object_type, object_id). object_id is the public id of a Record, Signal,
or Task, or the storage id of a Source. Ids are unique only within one kind, so the type is part of
the reference. object_id is NULL exactly when the owner is the Dataset.
AXES
module-attribute
¶source
AXES = Table(
"axes",
(
_required("axis_id", ColumnType.BIGINT),
_required("axis_type"),
Column("period_numerator_us", ColumnType.BIGINT),
Column("period_denominator", ColumnType.BIGINT),
Column("start_index", ColumnType.BIGINT),
Column("offset_us", ColumnType.BIGINT),
Column("first_us", ColumnType.BIGINT),
Column("last_us", ColumnType.BIGINT),
),
unique=(("axis_id",),),
)
CLOCKS
module-attribute
¶source
CLOCKS = Table(
"clocks",
(
_key("clock_id"),
Column("start_time_us", ColumnType.BIGINT),
),
unique=(("clock_id",),),
)
CONTROL_METADATA
module-attribute
¶source
CONTROL_METADATA = Table(
"control_metadata",
(_required("key"), _required("value")),
unique=(("key",),),
)
CONTROL_TABLES
module-attribute
¶source
CONTROL_TABLES: tuple[Table, ...] = (
CONTROL_METADATA,
IMPORTS,
EXTERNAL_VALUES,
IMPORTED_OBJECTS,
DATASETS,
RECORDS,
CLOCKS,
SOURCES,
AXES,
SIGNALS,
SIGNAL_CHUNKS,
ANNOTATION_CONTENTS,
ANNOTATION_OCCURRENCES,
LABEL_SETS,
TASKS,
TASK_TARGETS,
TASK_RECORD_REFS,
TASK_ANNOTATION_REFS,
TASK_DEPENDENCIES,
)
Every control table, in creation order.
DATASETS
module-attribute
¶source
DATASETS = Table(
"datasets",
(_required("dataset_id"),),
unique=(("dataset_id",),),
)
Exactly one row, the dataset the file describes.
EXTERNAL_OWNER_TABLES
module-attribute
¶source
EXTERNAL_OWNER_TABLES: dict[ObjectKind, tuple[str, str]] = {
ObjectKind.TASK: ("tasks", "task_id"),
ObjectKind.ANNOTATION_CONTENT: (
"annotation_contents",
"content_id",
),
ObjectKind.AXIS: ("axes", "axis_id"),
}
The owner table and key column of each object kind whose values can be stored externally.
EXTERNAL_VALUES
module-attribute
¶source
EXTERNAL_VALUES = Table(
"external_values",
(
_required("object_kind"),
_required("object_id", ColumnType.BIGINT),
_required("field"),
_key("position"),
Column("source_key", ColumnType.VARCHAR),
_required("value_path"),
_key("row_index"),
_required("value_kind"),
_key("n_values"),
Column("value_digest", ColumnType.VARCHAR),
),
unique=(
("object_kind", "object_id", "field", "position"),
),
)
The owner is (object_kind, object_id): a Task by its public id, or an annotation content row
or an irregular axis by the storage id that this write gave its row. Ids are unique only within one
kind, so the kind is part of the reference. Signals that share an axis share its row, so the axis's
time offsets are stored once.
IMPORTED_OBJECTS
module-attribute
¶source
IMPORTED_OBJECTS = Table(
"imported_objects",
(
_required("alias"),
_required("object_kind"),
_required("parent_id", ColumnType.BIGINT),
_required("object_id", ColumnType.BIGINT),
),
unique=(("alias", "object_kind", "parent_id"),),
foreign_keys=(ForeignKey("alias", "imports", "alias"),),
)
Local object IDs indexed by parent alias, object kind, and original parent ID.
IMPORTS
module-attribute
¶source
IMPORTS = Table(
"imports",
(_required("alias"), _required("parent_ref")),
unique=(("alias",), ("parent_ref",)),
)
Catalog lookup projection of the aliases and exact releases in Manifest.parent_cards.
LABEL_SETS
module-attribute
¶source
LABEL_SETS = Table(
"label_sets",
(
_required("name"),
_required("labels", ColumnType.LABEL_LIST),
_required("multi_label", ColumnType.BOOLEAN),
),
unique=(("name",),),
)
Each row stores one label set that a classification task uses.
The labels column holds one {name, description} entry per label, in label order.
If a label has no description, description is NULL. Tasks refer to a set by its name in
tasks.label_set.
LAST_ID_PREFIX
module-attribute
¶source
Prefix of the control_metadata keys that store the last id used per entity kind.
RECORDS
module-attribute
¶source
RECORDS = Table(
"records",
(
_required("record_id", ColumnType.BIGINT),
_key("clock_id"),
Column("time_span_start_us", ColumnType.BIGINT),
Column("time_span_end_us", ColumnType.BIGINT),
_required("metadata", ColumnType.JSON),
_required("read_order", ColumnType.BIGINT),
),
unique=(("record_id",), ("read_order",)),
foreign_keys=(
ForeignKey("clock_id", "clocks", "clock_id"),
),
)
SIGNALS
module-attribute
¶source
SIGNALS = Table(
"signals",
(
_required("signal_id", ColumnType.BIGINT),
_key("source_id"),
_required("name"),
_key("axis_id"),
_required("spec_type"),
_required("spec_name"),
Column("unit", ColumnType.VARCHAR),
_required("dtype"),
_required("categories", ColumnType.VARCHAR_LIST),
_required("value_shape", ColumnType.BIGINT_LIST),
_required(
"dimension_names", ColumnType.VARCHAR_LIST
),
_required("nullable", ColumnType.BOOLEAN),
_key("n_values"),
_required("metadata", ColumnType.JSON),
_required("modality"),
),
unique=(("signal_id",),),
foreign_keys=(
ForeignKey("source_id", "sources", "source_id"),
ForeignKey("axis_id", "axes", "axis_id"),
),
)
SIGNAL_CHUNKS
module-attribute
¶source
SIGNAL_CHUNKS = Table(
"signal_chunks",
(
_key("signal_id"),
_key("chunk_index"),
_required("value_path"),
Column("source_key", ColumnType.VARCHAR),
_key("chunk_major_index"),
Column("chunk_minor_index", ColumnType.BIGINT),
_key("n_values"),
),
unique=(("signal_id", "chunk_index"),),
foreign_keys=(
ForeignKey("signal_id", "signals", "signal_id"),
),
)
SOURCES
module-attribute
¶source
SOURCES = Table(
"sources",
(
_required("source_id", ColumnType.BIGINT),
_key("record_id"),
Column("parent_source_id", ColumnType.BIGINT),
_required("name"),
_required("metadata", ColumnType.JSON),
),
unique=(("source_id",),),
foreign_keys=(
ForeignKey("record_id", "records", "record_id"),
ForeignKey(
"parent_source_id", "sources", "source_id"
),
),
)
TABLES
module-attribute
¶source
TABLES: dict[str, Table] = {
(table.name): table for table in CONTROL_TABLES
}
The control tables by name.
TASKS
module-attribute
¶source
TASKS = Table(
"tasks",
(
_required("task_id", ColumnType.BIGINT),
_required("task_type"),
Column("prompt", ColumnType.VARCHAR),
_required(
"input_modalities", ColumnType.VARCHAR_LIST
),
Column("split", ColumnType.VARCHAR),
Column("scope_type", ColumnType.VARCHAR),
Column("scope_start", ColumnType.BIGINT),
Column("scope_end", ColumnType.BIGINT),
Column("scope_signal_ids", ColumnType.BIGINT_LIST),
_required("has_inline_targets", ColumnType.BOOLEAN),
Column("label_set", ColumnType.VARCHAR),
Column("unit", ColumnType.VARCHAR),
Column("target_name", ColumnType.VARCHAR),
Column("mode", ColumnType.VARCHAR),
Column("rationale", ColumnType.VARCHAR),
_required("metadata", ColumnType.JSON),
),
unique=(("task_id",),),
foreign_keys=(
ForeignKey(
"scope_signal_ids",
"signals",
"signal_id",
many=True,
),
ForeignKey("label_set", "label_sets", "name"),
),
)
TASK_ANNOTATION_REFS
module-attribute
¶source
TASK_ANNOTATION_REFS = Table(
"task_annotation_refs",
(
_key("task_id"),
_required("field"),
_key("position"),
_key("occurrence_id"),
),
unique=(("task_id", "field", "position"),),
foreign_keys=(
ForeignKey("task_id", "tasks", "task_id"),
ForeignKey(
"occurrence_id",
"annotation_occurrences",
"occurrence_id",
),
),
)
TASK_DEPENDENCIES
module-attribute
¶source
TASK_DEPENDENCIES = Table(
"task_dependencies",
(
_key("task_id"),
_key("position"),
_key("parent_task_id"),
),
unique=(("task_id", "position"),),
foreign_keys=(
ForeignKey("task_id", "tasks", "task_id"),
ForeignKey("parent_task_id", "tasks", "task_id"),
),
)
TASK_RECORD_REFS
module-attribute
¶source
TASK_RECORD_REFS = Table(
"task_record_refs",
(
_key("task_id"),
_required("field"),
_key("position"),
_key("record_id"),
),
unique=(("task_id", "field", "position"),),
foreign_keys=(
ForeignKey("task_id", "tasks", "task_id"),
ForeignKey("record_id", "records", "record_id"),
),
)
TASK_TARGETS
module-attribute
¶source
TASK_TARGETS = Table(
"task_targets",
(
_key("task_id"),
_key("position"),
_required("target_kind"),
Column("text_value", ColumnType.VARCHAR),
Column("integer_value", ColumnType.BIGINT),
Column("float_value", ColumnType.DOUBLE),
Column("boolean_value", ColumnType.BOOLEAN),
Column("record_id", ColumnType.BIGINT),
Column("signal_id", ColumnType.BIGINT),
Column("span_start", ColumnType.BIGINT),
Column("span_end", ColumnType.BIGINT),
Column("span_signal_ids", ColumnType.BIGINT_LIST),
),
unique=(("task_id", "position"),),
foreign_keys=(
ForeignKey("task_id", "tasks", "task_id"),
ForeignKey("record_id", "records", "record_id"),
ForeignKey("signal_id", "signals", "signal_id"),
ForeignKey(
"span_signal_ids",
"signals",
"signal_id",
many=True,
),
),
)
The value columns match :class:timenet.format.task_target_row.TargetValueRow. A span names its
series in span_signal_ids: one Signal for a step span, and any number for a time span.
ColumnType ¶source
Bases: Enum
The DuckDB column types the control schema uses, each with the Arrow type that feeds it.
The writer builds every batch with the table's Arrow schema, so a value of the wrong Python type fails in Arrow, naming the column, instead of being cast by DuckDB.
LABEL_LIST
class-attribute
instance-attribute
¶source
LABEL_LIST = (
"STRUCT(name VARCHAR, description VARCHAR)[]",
pa.list_(
pa.struct(
[
("name", pa.string()),
("description", pa.string()),
]
)
),
)
control_writer ¶source
Write the in-memory TimeF hierarchy into control.duckdb.
DuckDBControlWriter ¶source
Serialize the relational part of one immutable TimeF version.
write_hierarchy ¶source
write_hierarchy(
dataset: TimeFDataset,
placements: dict[tuple[int, int], ChunkPlacement]
| None = None,
*,
tasks: Iterable[Task] | None = None,
) -> dict[str, int]
Write records, sources, signals, axes, and their annotations atomically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset
|
TimeFDataset
|
The complete in-memory hierarchy. |
required |
placements
|
dict[tuple[int, int], ChunkPlacement] | None
|
Values-plane chunks keyed by |
None
|
tasks
|
Iterable[Task] | None
|
A previously validated task stream, or |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
Counts keyed by concrete task type. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the hierarchy refers to an object outside the dataset, repeats a task id, holds a value that JSON cannot store, or declares Signal lengths that do not match its axis offsets or value chunks. |
duckdb ¶source
DuckDB schema and connection helpers for the TimeF relational control plane.
CATALOG_ERRORS
module-attribute
¶source
DuckDB errors that mean a catalog lacks a table, column, or type that a read expects.
CONTROL_FILE
module-attribute
¶source
Name of the relational control-plane database in a TimeF version.
check_control_schema ¶source
check_control_schema(connection: DuckDBPyConnection) -> int
Return the version of a supported control database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
DuckDBPyConnection
|
An open TimeF control database. |
required |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the schema metadata is missing, malformed, or unsupported. |
create_control_schema ¶source
Create every control-plane table in one transaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
DuckDBPyConnection
|
A writable connection to a new database. |
required |
transaction ¶source
transaction(
connection: DuckDBPyConnection,
) -> Generator[None]
Commit a block atomically or roll it back when any operation fails.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
DuckDBPyConnection
|
The connection that owns the transaction. |
required |
Yields:
| Type | Description |
|---|---|
Generator[None]
|
Control while the transaction is open. |
schemas ¶source
Pinned Arrow schema of the Parquet value shards.
Shards hold no public ids. The DuckDB control plane maps each signal to its chunk placements.
storage ¶source
Write-time collection of the payload sources a new release reads, pinned to their files.
StorageSources ¶source
Collect the releases that store a new release's reused payloads, and pin the files it reads.
With a target registry, each payload source is checked there at its first reuse. The registry must hold the source with the same records of the reused files as the release the values were read from, and the source must not read payloads of the new release itself.
sources
property
¶source
sources: dict[SourceKey, PayloadSource]
Each payload source with the files the new release reads from it, for the manifest.
add ¶source
add(
release: DatasetVersion,
location: PayloadLocation,
*,
nullable: bool = False,
) -> SourceKey
Check a reused payload's files and pin them on the release that stores them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
release
|
DatasetVersion
|
The release whose catalog records |
required |
location
|
PayloadLocation
|
Where the payload's bytes live. |
required |
nullable
|
bool
|
Whether the spec of a signal array is nullable. Zarr stores the array's validity in parallel arrays, which the source must then list too. |
False
|
Returns:
| Type | Description |
|---|---|
SourceKey
|
Its source key in the new release: the exact release as |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the storing release is the output release, its manifest lacks a file of the payload, or the target registry holds a source that reads payloads of the output release. |
TimeNetDatasetNotFoundError
|
If the target registry does not hold the source. |
TimeFFormatError
|
If the target registry's source records a reused file differently. |
stored_array ¶source
Signal arrays stored as chunks in the Parquet or Zarr values files of a release.
ChunkLocation
dataclass
¶source
Locate a signal array stored as chunks in the values files of one release.
The catalog records each chunk's file, coordinates, and length, so the array's place in storage is known without opening a values file.
ChunkReader ¶source
Bases: Protocol
Find and read the stored chunks of one release's signal arrays.
A release's TimeFReader is one: it finds the chunks of a batch of signals at a time, and reads
them from whichever release stores them.
StoredArray
dataclass
¶source
Bases: ArrayHandle
Refer to one signal's array, stored as chunks in the values files of a release.
The handle holds the release's reader and the signal's ID, spec, and number of values. A loaded
handle also keeps the array and the location of its chunks in a write-once cell, so it reads,
slices, and locates them without storage access. An unloaded handle holds no values: every read
goes to the chunks, and read_steps reads only the chunks that cover the range. Handles from
one reader for one signal are equal, whether loaded or not.
is_loaded
property
¶source
is_loaded: bool
Whether the handle keeps the values, so reads need no storage access.
n_values
instance-attribute
¶source
n_values: int
Number of values that the signal declares, which a read of every chunk must return.
reader
class-attribute
instance-attribute
¶source
reader: ChunkReader = dataclass_field(repr=False)
Reader of the release whose catalog records the signal.
read ¶source
Return the kept values, or the values of every chunk.
Returns:
| Type | Description |
|---|---|
Array
|
The signal's values. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the chunks hold another number of values than the signal declares. |
read_numpy ¶source
Return the values as a read-only NumPy array, shaped (n_steps, *value_shape).
The default converts :meth:read. A handle whose data is NumPy already returns it without
building Arrow.
Returns:
| Type | Description |
|---|---|
ndarray
|
The values, in the NumPy dtype of their Arrow type. |
Raises:
| Type | Description |
|---|---|
TimeFNullValuesError
|
If the values contain nulls, which NumPy cannot hold. Read them
with :meth: |
stored_values ¶source
Read and write text, string lists, and time offsets stored in Parquet payloads.
ANNOTATION_COLUMNS
module-attribute
¶source
ANNOTATION_COLUMNS = StoredValueColumns(
kind=ObjectKind.ANNOTATION_CONTENT,
identity="content_id",
fields={
PackedField.VALUE: {
PackedValueKind.TEXT: "text_value",
PackedValueKind.TEXT_LIST: "text_list_value",
}
},
)
Packable columns of the annotation table.
INLINE_LIMIT
module-attribute
¶source
The largest JSON-encoded text size, in bytes, that the writer keeps in the catalog.
The writer stores larger text and lazy text handles in separate payload files to keep the catalog small.
LOCATOR_TABLE
module-attribute
¶source
LOCATOR_TABLE = ModelTable[PackedValueLocator](
EXTERNAL_VALUES
)
PayloadLocation
module-attribute
¶source
PayloadLocation = PackedLocation | ChunkLocation
Where a stored value's bytes live: packed text or time offsets, or a signal array's chunks.
TARGET_COLUMNS
module-attribute
¶source
TARGET_COLUMNS = StoredValueColumns(
kind=ObjectKind.TASK,
identity="task_id",
fields={
PackedField.TARGETS: {
PackedValueKind.TEXT: "text_value"
}
},
position="position",
)
Packable columns of the task-target table.
TASK_COLUMNS
module-attribute
¶source
TASK_COLUMNS = StoredValueColumns(
kind=ObjectKind.TASK,
identity="task_id",
fields={
PackedField.PROMPT: {
PackedValueKind.TEXT: "prompt"
},
PackedField.RATIONALE: {
PackedValueKind.TEXT: "rationale"
},
},
)
Packable columns of the task table.
ExternalObjectFieldKey
dataclass
¶source
Identify an external field on an object, including its position in an ordered field.
The object is named the way the catalog names it: a task by its public id, an annotation's
content by the storage id of its annotation_contents row, and an irregular axis by the
storage id of its axes row.
PackedContentKey
dataclass
¶source
Name one packed value by its payload file's checksum and its place in the file, without a read.
The checksum identifies the file's bytes, so equal keys mean equal values, and readers of one
release, or of releases that share a payload file, give the same key. The key compares equal
only to another PackedContentKey, so it never equals the key of text in memory, which is a
string or a tuple of strings.
PackedLocation
dataclass
¶source
Locate one value packed in a Parquet payload file of a release.
The catalog records every field, so the value's release, kind, length, and digest are known without opening the payload file.
digest
class-attribute
instance-attribute
¶source
digest: bytes | None = None
SHA-256 digest of time offsets, which identifies them without a read. None for text.
kind
instance-attribute
¶source
kind: PackedValueKind
Kind of the value, which names the payload column that holds it.
length
instance-attribute
¶source
length: int
Number of code points in a string, of items in a string list, or of time offsets.
PackedValueLocator ¶source
Bases: TimeFModel
Validate the catalog location and value kind of one external field.
model_config
class-attribute
instance-attribute
¶source
model_config = ConfigDict(
extra="forbid",
frozen=True,
revalidate_instances="always",
serialize_by_alias=True,
validate_by_name=True,
validate_default=True,
)
value_digest
class-attribute
instance-attribute
¶source
value_digest: str | None = Field(
default=None,
pattern=f"^{CHECKSUM_PREFIX}[0-9a-f]{64}$",
strict=True,
)
PackedValueReader ¶source
Read one release's packed values through a bounded cache of decoded payload files.
A value whose location names a source is read from that payload source of the release.
checksum ¶source
checksum(location: PackedLocation) -> str
Return the checksum that the release storing the location's payload file records for it.
The location's source names that release: one of this release's payload sources, or this
release itself for None. Its manifest lists the file, so the checksum needs no read.
Returns:
| Type | Description |
|---|---|
str
|
The file's checksum, with its |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the source is unknown, or its manifest does not list the file. |
content_key ¶source
content_key(location: PackedLocation) -> PackedContentKey
Return the key that names a packed value by its payload file's checksum, without a read.
Returns:
| Type | Description |
|---|---|
PackedContentKey
|
The checksum the manifest records for the location's file, with the row and kind. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the manifest does not list the location's payload file. |
handle ¶source
handle(
location: PackedLocation,
) -> StoredText | StoredTextList
Return a text handle of the location's value kind, without reading the payload.
Returns:
| Type | Description |
|---|---|
StoredText | StoredTextList
|
A |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the manifest does not list the location's payload file. |
TimeFValidationError
|
If the location holds time offsets, whose |
handles ¶source
handles(
connection: DuckDBPyConnection,
kind: ObjectKind,
object_ids: Iterable[int],
) -> dict[
ExternalObjectFieldKey, StoredText | StoredTextList
]
Return text handles for one batch of objects' packed values without opening payload files.
Returns:
| Type | Description |
|---|---|
dict[ExternalObjectFieldKey, StoredText | StoredTextList]
|
Handles keyed by object kind, object id, field, and position. |
locations
staticmethod
¶source
locations(
connection: DuckDBPyConnection,
kind: ObjectKind,
object_ids: Iterable[int],
) -> dict[ExternalObjectFieldKey, PackedLocation]
Return where one batch of objects' values are packed, without opening payload files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
DuckDBPyConnection
|
The release's open control database. |
required |
kind
|
ObjectKind
|
The kind of the objects that own the values. |
required |
object_ids
|
Iterable[int]
|
The catalog ids of the objects, such as task ids or annotation content ids. |
required |
Returns:
| Type | Description |
|---|---|
dict[ExternalObjectFieldKey, PackedLocation]
|
Locations keyed by object kind, object id, field, and position. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the catalog has no locator table, or a locator is invalid or duplicated. |
offsets ¶source
offsets(
location: PackedLocation,
*,
axis_id: int,
first: int,
last: int,
) -> StoredOffsets
Return a handle to one irregular axis's packed time offsets, without reading the payload.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
location
|
PackedLocation
|
Where the time offsets are packed. |
required |
axis_id
|
int
|
The axis's catalog ID, for error messages. |
required |
first
|
int
|
The first time offset the axis declares, in microseconds. |
required |
last
|
int
|
The last time offset the axis declares, in microseconds. |
required |
Returns:
| Type | Description |
|---|---|
StoredOffsets
|
A |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the manifest does not list the location's payload file. |
read_scalar ¶source
read_scalar(location: PackedLocation) -> Scalar
Read a packed value from the payload file of the release that stores it.
Returns:
| Type | Description |
|---|---|
Scalar
|
The Arrow scalar at the location's file and row: a string, or a list of strings or time offsets. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the payload file's schema, the location, or the stored value is invalid. |
PackedValueWriter ¶source
Pack new values into Parquet payload files, and reuse the payloads that store read values.
pack ¶source
pack(
kind: ObjectKind,
object_id: int,
field: PackedField,
value: object,
position: int = 0,
*,
digest: bytes | None = None,
) -> CatalogValue | ExternalValue
Store a value in the catalog or a separate payload file.
Time offsets, :class:LazyText, and :class:LazyTextList go into payload files.
If other text exceeds :data:INLINE_LIMIT, it also goes into a payload file.
Stored handles reuse their existing payload rows.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kind
|
ObjectKind
|
The kind of object that owns the value. |
required |
object_id
|
int
|
The object id in the output catalog: a task id, an annotation content id, or an axis id. |
required |
field
|
PackedField
|
The field that holds the value. |
required |
value
|
object
|
The text, time offsets, or other catalog value to store. |
required |
position
|
int
|
The position in a field with several values, such as task targets. |
0
|
digest
|
bytes | None
|
An optional |
None
|
Returns:
| Type | Description |
|---|---|
CatalogValue | ExternalValue
|
A catalog value or a locator that identifies the value in a payload file. |
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the locator is invalid for this field, the output release stores a reused payload, or the source release lacks a reused payload. |
write_locators ¶source
write_locators(
connection: DuckDBPyConnection, *, at_least: int = 0
) -> None
Store the locators packed so far in the catalog and release them.
The catalog writer calls this once per batch inside its transaction, so a streamed source never holds all of its locators.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
DuckDBPyConnection
|
The open write transaction. |
required |
at_least
|
int
|
Keep the locators while there are fewer than this many. |
0
|
StoredOffsets
dataclass
¶source
Bases: ArrayHandle
Refer to the time offsets of one irregular axis, packed in a Parquet payload.
The handle holds the reader of the release's payloads, the time offsets' location, and the axis's
ID and endpoints. Its first read() checks the time offsets against the location and the axis
and keeps a compact copy in a write-once cell, so from then on the handle is loaded and reads need
no payload access. The location records the number of time offsets and their digest, so both are
known without a read.
digest
property
¶source
digest: bytes
The time offsets' SHA-256 digest, recorded in their location.
The catalog stores a digest with every axis's time offsets, so only a location built by hand can lack one.
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the location records no digest. |
store
class-attribute
instance-attribute
¶source
store: PackedValueReader = dataclass_field(repr=False)
read ¶source
Return the time offsets, read and checked on the first call and kept.
Returns:
| Type | Description |
|---|---|
Array
|
One int64 microsecond offset per step. |
read_numpy ¶source
Return the values as a read-only NumPy array, shaped (n_steps, *value_shape).
The default converts :meth:read. A handle whose data is NumPy already returns it without
building Arrow.
Returns:
| Type | Description |
|---|---|
ndarray
|
The values, in the NumPy dtype of their Arrow type. |
Raises:
| Type | Description |
|---|---|
TimeFNullValuesError
|
If the values contain nulls, which NumPy cannot hold. Read them
with :meth: |
read_steps ¶source
Return the half-open step range [start, stop).
The default slices :meth:read, so a stop past the end reads to the end. A stored
handle reads only the chunks that cover the range.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
int
|
First step, inclusive, and not negative. |
required |
stop
|
int
|
Last step, exclusive, and not before |
required |
Returns:
| Type | Description |
|---|---|
Array
|
The steps' values, in the form :meth: |
StoredText
dataclass
¶source
Bases: TextHandle
Refer to one string packed in a Parquet payload.
The handle holds the reader of the release's payloads and the string's location. A loaded handle
also keeps the string in a write-once cell, and read() returns it without payload access. An
unloaded handle holds no text, and every read() reads the payload. Handles at one location of
one payload file are equal without a read, whether loaded or not.
is_loaded
property
¶source
is_loaded: bool
Whether the handle keeps the string, so reads need no payload access.
store
class-attribute
instance-attribute
¶source
store: PackedValueReader = dataclass_field(repr=False)
StoredTextList
dataclass
¶source
Bases: TextListHandle
Refer to a list of strings packed in a Parquet payload.
The handle holds the reader of the release's payloads and the list's location. A loaded handle
also keeps the strings in a write-once cell, and read() returns a new list of them without
payload access. An unloaded handle holds no text, and every read() reads the payload. Handles
at one location of one payload file are equal without a read, whether loaded or not.
is_loaded
property
¶source
is_loaded: bool
Whether the handle keeps the strings, so reads need no payload access.
store
class-attribute
instance-attribute
¶source
store: PackedValueReader = dataclass_field(repr=False)
StoredValueColumns
dataclass
¶source
Name the columns of one public Arrow table whose values can be packed.
fields
instance-attribute
¶source
fields: Mapping[PackedField, Mapping[PackedValueKind, str]]
Per packed field, the column that holds each value kind.
identity
instance-attribute
¶source
identity: str
Column holding each row's owner id: a task id, or an annotation content id.
kind
instance-attribute
¶source
kind: ObjectKind
Object kind whose locators address the packed values.
materialize_table ¶source
materialize_table(
table: Table,
reader: PackedValueReader,
connection: DuckDBPyConnection,
columns: StoredValueColumns,
) -> Table
Resolve external text fields while retaining the public Arrow table schema.
Returns:
| Type | Description |
|---|---|
Table
|
The original table when it has no external values, otherwise a table with native values. |
offsets_digest ¶source
offsets_digest(offsets: ndarray | Array) -> bytes
Return the SHA-256 digest of an irregular axis's time offsets.
Every caller hashes the same bytes, contiguous little-endian int64, so one sequence of time offsets has one digest whether it is held as NumPy or as Arrow.
Returns:
| Type | Description |
|---|---|
bytes
|
The 32-byte digest. |
table_writer ¶source
Insert catalog rows using their shared table definitions.
insert_rows ¶source
insert_rows(
connection: DuckDBPyConnection,
table: Table,
rows: Sequence[Mapping[str, object]],
) -> None
Insert one Arrow batch using the catalog table's schema and column order.
Raises:
| Type | Description |
|---|---|
TimeFValidationError
|
If the rows cannot be converted or inserted into the table. |
task_codec ¶source
Canonical codecs between Task fields and the typed columns of the tasks and task_targets tables.
Spans, task configuration, and targets are all stored as plain columns rather than JSON, so DuckDB can
filter on them and the reader builds objects straight from row values. Object references are public
IDs. The target rows use the task_targets column names, so the rows are stored and read back
unchanged. A span holds Signal objects, so encoding reads their ids and decoding looks the read-back
Signals up by id.
ANNOTATION_FIELDS
module-attribute
¶source
ANNOTATION_FIELDS = frozenset(
{
TaskRelationshipField.INPUT_ANNOTATIONS,
TaskRelationshipField.TARGET_ANNOTATIONS,
}
)
The fields stored in task_annotation_refs.
PAYLOAD_COLUMNS
module-attribute
¶source
The tasks columns that hold configuration for each task type.
Unused columns are NULL. A classification task stores its label set name in label_set.
The label_sets table stores the set itself.
RECORD_FIELDS
module-attribute
¶source
RECORD_FIELDS = frozenset(
{
TaskRelationshipField.INPUTS,
TaskRelationshipField.CANDIDATE_RECORDS,
}
)
The fields stored in task_record_refs.
TaskRelationshipField ¶source
decode_input_modalities ¶source
decode_input_modalities(
values: list[str] | None,
) -> frozenset[InputModality]
Decode a required stored input modality set.
Returns:
| Type | Description |
|---|---|
frozenset[InputModality]
|
The declared input kinds. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If a stored input kind is unknown or repeated. |
decode_span ¶source
decode_span(
span_type: str | None,
span_start: int | None,
span_end: int | None,
signal_ids: Iterable[EntityId] | None,
*,
signals: Mapping[EntityId, Signal],
) -> Span | None
Decode the four span columns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
span_type
|
str | None
|
The stored span shape, or |
required |
span_start
|
int | None
|
The stored start bound. |
required |
span_end
|
int | None
|
The stored end bound. |
required |
signal_ids
|
Iterable[EntityId] | None
|
The ids of the Signals the span is scoped to. |
required |
signals
|
Mapping[EntityId, Signal]
|
The read-back Signals by id, which take the place of |
required |
Returns:
| Type | Description |
|---|---|
Span | None
|
The decoded Span, or |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the stored span type is unknown, a required bound is NULL, or a Signal id names no read-back Signal. |
decode_split ¶source
Decode a stored split.
Returns:
| Type | Description |
|---|---|
Split | None
|
The task's partition, or |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the stored split is unknown. |
decode_target ¶source
decode_target(
row: Mapping[str, object] | TargetValueRow,
*,
records: Mapping[EntityId, Record],
signals: Mapping[EntityId, Signal],
) -> object
Decode one typed target row and resolve stored object references.
Returns:
| Type | Description |
|---|---|
object
|
The native scalar, Record, Signal, or Span target. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If a required value or referenced object is missing, or the kind is unknown. |
encode_span ¶source
Encode a concrete span as the four span columns without losing its frame or shape.
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
|
dict[str, Any] | None
|
span's series scope: |
dict[str, Any] | None
|
one-element tuple for a step span. |
Raises:
| Type | Description |
|---|---|
TimeFFormatError
|
If the Span subtype is unsupported. |
task_target_kind ¶source
Tags for the scalar, object, and span targets stored in the control catalog.
SPAN_KINDS
module-attribute
¶source
SPAN_KINDS = frozenset(
{
TaskTargetKind.TIME_POINT,
TaskTargetKind.TIME_INTERVAL,
TaskTargetKind.STEP_POINT,
TaskTargetKind.STEP_INTERVAL,
}
)
The kinds that store a span. tasks.scope_type holds one of these too.
task_target_row ¶source
Validated target values and catalog rows.
TargetValueRow ¶source
Bases: TimeFModel
Represent a public target with validated values and public object IDs.
model_config
class-attribute
instance-attribute
¶source
model_config = ConfigDict(
extra="forbid",
frozen=True,
revalidate_instances="always",
serialize_by_alias=True,
validate_by_name=True,
validate_default=True,
)