Skip to content

ModelDefinitions

Represents a batch of ML model metadata records.

Parameters

FieldTypeDescription
model_nameslist[str]Required. Model names, length N.
model_formatslist[str]Required. Model serialization formats, length N.
visibilitieslist[str]Required. Model visibility levels, length N.
model_statuseslist[str]Required. Model statuses, length N.
model_descriptionslist[str | None] | NoneOptional. Per-model descriptions, length N.
model_inputslist[list[ModelTensorDefinition | dict] | None] | NoneOptional. Per-model input tensor signatures, length N. Dict entries are converted via ModelTensorDefinition.from_dict.
model_outputslist[list[ModelTensorDefinition | dict] | None] | NoneOptional. Per-model output tensor signatures, same shape as model_inputs.
created_atslist[datetime | None] | NoneOptional. Per-model creation timestamps, length N.
updated_atslist[datetime | None] | NoneOptional. Per-model last-update timestamps, length N.

Raises

ExceptionCondition
TypeErrorA required field isn't a list of the expected element type, or an optional field isn't None/a list of the expected type.
ValueErrorAny provided field's length doesn't match len(model_names).

Attributes

AttributeTypeDescription
model_namesnp.ndarrayShape (N,), object dtype.
model_formatsnp.ndarrayShape (N,), object dtype.
visibilitiesnp.ndarrayShape (N,), object dtype.
model_statusesnp.ndarrayShape (N,), object dtype.
model_descriptionsnp.ndarray | NoneShape (N,), or None if every record omitted it.
model_inputsnp.ndarray | NoneLength-N ragged object array; each element is a list[ModelTensorDefinition] or None, or the whole attribute is None if every record omitted it.
model_outputsnp.ndarray | NoneSame shape/semantics as model_inputs.
created_atslist[datetime] | NonePlain list (not an np.ndarray), length N, or None if every record omitted it.
updated_atslist[datetime] | NonePlain list, length N, or None if every record omitted it.

All properties allocate a fresh array/list on each access — none are defensive views into mutable internal state, so there's no separate setter to validate against.

Methods

MethodDescription
ModelDefinitions.coerce(value, name="value")Classmethod. Returns value unchanged if it's already a ModelDefinitions; expands a dict of constructor keyword arguments via cls(**value). Raises TypeError otherwise.

Operators

OperationBehavior
len(defs)Number of records, N.
defs[i] (int)A length-1 ModelDefinitions sub-batch. Negative indices are supported; raises IndexError if out of range.
defs[i:j] (slice)A ModelDefinitions sub-batch.
defs[mask] (boolean np.ndarray)A ModelDefinitions sub-batch of the matched rows. Raises ValueError if mask isn't length N.
a == bTrue if other is a ModelDefinitions with equal fields, in the same order.

Not hashable (__hash__ is None) — despite being immutable after construction (no data-style setter), ModelDefinitions is deliberately excluded from hashing.

Serialization

to_pyarrow() uses list-of-structs (one shared offsets buffer for the whole batch) rather than struct-of-lists, which is measurably faster to (de)serialize and marginally smaller:

ListArray length 1
└── values: StructArray length N
        ├── model_name:        string
        ├── model_format:      string
        ├── visibility:        string
        ├── model_status:      string
        ├── model_description: string (null if omitted)
        ├── model_input:       list<struct<name, canonical_name, dtype, shape:list<int32>>> (null if omitted)
        ├── model_output:      same type as model_input (null if omitted)
        ├── created_at:        timestamp[ns, tz=UTC] (null if omitted)
        └── updated_at:        timestamp[ns, tz=UTC] (null if omitted)

One ModelDefinitions object serializes as one Arrow row, with all N records packed into that row's single list element.

Visualization

datatypes.visualize(definitions, entity_path=...) logs the batch as a rerun markdown table, one row per record. model_description is omitted from the table to keep rows compact; model_input/model_output are rendered as name:dtype[shape] entries joined by "; ".

Example

python
"""Demonstrates the Telekinesis ModelDefinitions datatype."""

import time
from datetime import datetime, timezone

import rerun as rr
from loguru import logger

from telekinesis import datatypes

def model_definitions_example():
    """Demonstrate batch construction (canonical_name input_0/output_N), access, indexing, empty batches, and serialization."""

    # ======================= Create ============================================
    created_at = datetime(2024, 6, 1, tzinfo=timezone.utc)
    updated_at = datetime(2024, 6, 15, tzinfo=timezone.utc)

    model_input = datatypes.ModelTensorDefinition(
        name="images", canonical_name="input_0", dtype="float32", shape=[1, 3, 224, 224]
    )
    model_output = datatypes.ModelTensorDefinition(
        name="logits", canonical_name="output_0", dtype="float32", shape=[1, 1000]
    )
    other_output = datatypes.ModelTensorDefinition(
        name="logits", canonical_name="output_0", dtype="float32", shape=[1, 1000]
    )

    definitions = datatypes.ModelDefinitions(
        model_names=["model-a", "model-b"],
        model_formats=["onnx", "pytorch"],
        visibilities=["private", "public"],
        model_statuses=["uploaded", "deploying"],
        model_descriptions=["first model", None],
        model_inputs=[[model_input], None],
        model_outputs=[[model_output, other_output], None],
        created_ats=[created_at, updated_at],
        updated_ats=[created_at, updated_at],
    )

    # ======================= Visualize =========================================
    rr.init("model_definitions_example", spawn=True)
    datatypes.visualize(definitions, entity_path="/ModelDefinitions")

    # ======================= Inspect ===========================================
    logger.info(f"Number of records: {len(definitions)}")
    logger.info(f"model_names={definitions.model_names}, model_formats={definitions.model_formats}")
    logger.info(f"visibilities={definitions.visibilities}, model_statuses={definitions.model_statuses}")
    logger.info(f"model_inputs={definitions.model_inputs}")
    logger.info(f"created_ats={definitions.created_ats}, updated_ats={definitions.updated_ats}")

    # ======================= Index =============================================
    first = definitions[0]
    subset = definitions[0:1]
    mask = definitions.model_statuses == "uploaded"
    uploaded_only = definitions[mask]

    logger.info(f"definitions[0] = {first}")
    logger.info(f"definitions[0:1] = {len(subset)} record(s), names={subset.model_names}")
    logger.info(f"definitions[uploaded mask] = {len(uploaded_only)} record(s)")

    # ======================= Empty Batch =======================================
    empty = datatypes.ModelDefinitions(
        model_names=[], model_formats=[], visibilities=[], model_statuses=[]
    )
    datatypes.visualize(empty, entity_path="/ModelDefinitions/empty")

    # ======================= Serialize / Deserialize ===========================
    start = time.perf_counter()
    serialized = datatypes.serialize(definitions)
    serialization_ms = (time.perf_counter() - start) * 1000

    start = time.perf_counter()
    deserialized = datatypes.deserialize(serialized)["param_0"]
    deserialization_ms = (time.perf_counter() - start) * 1000

    logger.info(f"Deserialized ModelDefinitions: {deserialized}")
    logger.info(f"Round-trip successful: {deserialized == definitions}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")


if __name__ == "__main__":
    model_definitions_example()