tanat.cast package#

Submodules#

tanat.cast.base module#

Cast primitives, structural casts, and the recipe skeleton.

class tanat.cast.base.BaseCastRecipe[source]#

Bases: object

Common methods shared by sequence- and trajectory-level recipes.

Subclasses must:

  • be decorated with @dataclass(frozen=True),

  • declare structural: StructuralCasts and features: <FeatureCasts> with default factories,

  • set _FEATURES_CLS to the dataclass used for features.

classmethod coerce(value)[source]#

Coerce value into a recipe instance.

Accepted:

  • None → default recipe.

  • a recipe instance → returned unchanged.

  • a dict in the canonical nested form {"structural": ..., "features": ...} (each side may itself be a dict, which is then unpacked into the matching dataclass).

copy()[source]#

Return a deep copy of the recipe.

features: object[source]#
property id: list[DataType][source]#

Ordered dtype steps of the id recipe.

id_caster() Callable[[Expr], Expr] | None[source]#

Return the compiled caster for the id column, or None.

property id_dtype: DataType | None[source]#

Final dtype of the id recipe, None if no cast is registered.

is_empty() bool[source]#

Return True when no structural and no feature cast is registered.

replace(**kwargs)[source]#

Functional update.

Recognised keys:

  • structural= / features=: canonical nested form.

  • id= : shortcut to reset the structural id recipe.

  • time_index=: shortcut to reset the structural time_index recipe.

property static: dict[str, list[DataType]][source]#

Per-column dtype steps of the static feature recipes.

static_caster(col: str) Callable[[Expr], Expr] | None[source]#

Return the compiled caster for static feature col, or None.

structural: StructuralCasts[source]#
property time_index: list[DataType][source]#

Ordered dtype steps of the time_index recipe.

time_index_caster() Callable[[Expr], Expr] | None[source]#

Return the compiled caster for the time_index column, or None.

property time_index_dtype: DataType | None[source]#

Final dtype of the time_index recipe, None if no cast is registered.

class tanat.cast.base.CastStep(dtype: pl.DataType, strict: bool = True)[source]#

Bases: NamedTuple

A single dtype-cast step with its strict flag.

Parameters:
  • dtype – Target Polars data type.

  • strict – When True (default), non-convertible values raise a ComputeError. When False, non-convertible values silently become null.

dtype: DataType[source]#

Alias for field number 0

strict: bool[source]#

Alias for field number 1

class tanat.cast.base.ColumnMapCast(recipes: dict[str, list[~tanat.cast.base.CastStep]]=<factory>)[source]#

Bases: object

Ordered cast recipes for a named set of columns.

__init__(recipes: dict[str, list[~tanat.cast.base.CastStep]]=<factory>) None[source]#
append(schema: dict[str, DataType], strict: bool = True) ColumnMapCast[source]#

Return a new map with each col dtype of schema appended.

Parameters:
  • schema – Mapping of column names to target dtypes.

  • strict – When True (default), non-convertible values raise. When False, they become null. The flag is stored per step so successive calls on the same column are independent.

apply(lf: LazyFrame) LazyFrame[source]#

Apply all registered column casts to lf (no-op when empty).

caster(col: str) Callable[[Expr], Expr] | None[source]#

Return the compiled caster for col, or None when unset.

copy() ColumnMapCast[source]#

Return a deep copy of the map.

exprs() list[Expr][source]#

Return one with_columns expression per registered column.

is_empty() bool[source]#

Return True when no column has a registered cast recipe.

probe_lf(lf: LazyFrame, n_rows: int = 10) None[source]#

Eagerly evaluate an n_rows sample of lf to surface cast errors.

The candidate recipe is applied only for the probe; lf itself remains lazy and unchanged for the caller.

recipes: dict[str, list[CastStep]][source]#
class tanat.cast.base.ScalarCast(recipe: list[DataType] = <factory>)[source]#

Bases: object

Ordered cast recipe for a single, well-known column.

__init__(recipe: list[DataType] = <factory>) None[source]#
append(dtype: DataType) ScalarCast[source]#

Return a new recipe with dtype appended as a final step.

caster() Callable[[Expr], Expr] | None[source]#

Return the compiled caster, or None when the recipe is empty.

copy() ScalarCast[source]#

Return a deep copy of the recipe.

final_dtype() DataType | None[source]#

Return the dtype the recipe ultimately casts to, None if empty.

is_empty() bool[source]#

Return True when no cast step is registered.

recipe: list[DataType][source]#
class tanat.cast.base.StructuralCasts(id: ScalarCast = <factory>, time_index: ScalarCast = <factory>)[source]#

Bases: object

Shared ordered casts consumed by stores: id and time index.

__init__(id: ScalarCast = <factory>, time_index: ScalarCast = <factory>) None[source]#
append_id(dtype: DataType) StructuralCasts[source]#

Append dtype to the id recipe; reject closed-domain dtypes.

pl.Enum / pl.Categorical would conflict with any id outside the current view (the store consumes the cast on the full physical data). Materialise the view via save() first to narrow the domain.

append_time_index(dtype: DataType) StructuralCasts[source]#

Append dtype to the time_index recipe.

apply(lf: LazyFrame, *, id_col: str | None = None, time_cols: list[str] | None = None) LazyFrame[source]#

Apply id and (optionally) time-index structural casts to lf.

Parameters:
  • lf – Input LazyFrame.

  • id_col – Name of the id column to cast. None → skip.

  • time_cols – Names of time columns to cast. None / [] → skip.

copy() StructuralCasts[source]#

Return a deep copy of the structural casts.

id: ScalarCast[source]#
id_caster() Callable[[Expr], Expr] | None[source]#

Return the compiled caster for the id column, or None.

is_empty() bool[source]#

Return True when both id and time_index recipes are empty.

probe(view) None[source]#

Validate id and time_index recipes against full structural store data.

time_index: ScalarCast[source]#
time_index_caster() Callable[[Expr], Expr] | None[source]#

Return the compiled caster for the time_index column, or None.

tanat.cast.base.apply_cast_exprs(lf: LazyFrame, exprs: list[Expr]) LazyFrame[source]#

Apply pre-built cast expressions to lf.

Returns lf unchanged when exprs is empty.

tanat.cast.base.build_caster(recipe: list[DataType]) Callable[[Expr], Expr][source]#

Build an expression caster from an ordered dtype recipe.

tanat.cast.base.maybe_downgrade_enum_strict(schema: dict[str, DataType], strict: bool, has_scope: bool, stacklevel: int = 3) bool[source]#

Return strict downgraded to False for pl.Enum cols on a scoped view.

When has_scope is True (entity filter or ID mask active), a strict pl.Enum cast would crash on out-of-vocabulary values still present in the full store. This helper auto-downgrades and emits a UserWarning.

Parameters:
  • schema – Cast schema passed to cast_features.

  • strict – Current strict flag.

  • has_scope – Whether the view has an active filter or ID mask.

  • stacklevel – Warning stack level (default 3 reaches the user call site).

Returns:

Possibly downgraded strict flag.

tanat.cast.base.probe_cast_recipe(lf: LazyFrame, recipes: dict[str, list[CastStep]], n_rows: int = 10) None[source]#

Validate multi-step cast recipes on a small sample of lf.

Each column is cast through its recipe in order (T0 T1 Tn). Absent columns are silently skipped. Steps with strict=False do not raise on incompatible values; they only verify structural type acceptance.

Raises:

TypeError – If any strict step fails, with column name and full chain in the message.

tanat.cast.sequence module#

Sequence-level cast recipes.

class tanat.cast.sequence.SequenceCastRecipe(structural: StructuralCasts = <factory>, features: SequenceFeatureCasts = <factory>)[source]#

Bases: BaseCastRecipe

Type-cast overrides for a sequence view.

__init__(structural: StructuralCasts = <factory>, features: SequenceFeatureCasts = <factory>) None[source]#
append(*, id: DataType | None = None, time_index: DataType | None = None, entity: dict[str, DataType] | None = None, static: dict[str, DataType] | None = None, strict: bool = True) SequenceCastRecipe[source]#

Return a new recipe extended with one structural or feature cast.

Exactly one of id, time_index, entity, or static must be provided per call. Bundling multiple fields in a single call is intentionally rejected to keep each recipe step traceable.

Parameters:

strict – Forwarded to ColumnMapCast.append() for feature buckets only (entity and static). Structural columns (id, time_index) are always cast strictly.

Raises:

ValueError – If zero or more than one field argument is provided.

property entity: dict[str, list[DataType]][source]#

Per-column dtype steps of the entity feature recipes.

entity_caster(col: str) Callable[[Expr], Expr] | None[source]#

Return the compiled caster for entity feature col, or None.

feature_exprs(is_static: bool = False) list[Expr][source]#

Return the with_columns expressions for entity or static features.

features: SequenceFeatureCasts[source]#
fork_casts(*, feature_col: str | None = None, static_col: str | None = None) _ForkCasts[source]#

Return precompiled casts for a fork operation.

probe(view) None[source]#

Validate structural and all feature casts against view.

structural: StructuralCasts[source]#
class tanat.cast.sequence.SequenceFeatureCasts(entity: ColumnMapCast = <factory>, static: ColumnMapCast = <factory>)[source]#

Bases: object

Feature casts consumed by sequence views.

__init__(entity: ColumnMapCast = <factory>, static: ColumnMapCast = <factory>) None[source]#
apply(lf: LazyFrame, *, is_static: bool) LazyFrame[source]#

Apply entity or static feature casts to lf (no-op when empty).

copy() SequenceFeatureCasts[source]#

Return a deep copy of the feature casts.

entity: ColumnMapCast[source]#
is_empty() bool[source]#

Return True when no entity and no static cast is registered.

probe(view, *, is_static: bool) None[source]#

Probe this candidate recipe on pre-scope raw data.

Feature casts run before entity scopes in the view pipeline. The probe must therefore use the same pre-scope data the cast will see at runtime.

probe_lf(lf: LazyFrame | None, *, is_static: bool) None[source]#

Force-evaluate the selected bucket on a view LazyFrame.

static: ColumnMapCast[source]#

tanat.cast.trajectory module#

Trajectory-level cast recipes.

class tanat.cast.trajectory.TrajectoryCastRecipe(structural: StructuralCasts = <factory>, features: TrajectoryFeatureCasts = <factory>)[source]#

Bases: BaseCastRecipe

Type-cast overrides for a trajectory view.

Entity-level feature casts live in the trajectory’s sub-pools (see SequenceCastRecipe); at the trajectory layer only static features are observable directly.

__init__(structural: StructuralCasts = <factory>, features: TrajectoryFeatureCasts = <factory>) None[source]#
append(*, id: DataType | None = None, time_index: DataType | None = None, static: dict[str, DataType] | None = None, strict: bool = True) TrajectoryCastRecipe[source]#

Return a new recipe extended with one structural or feature cast.

Exactly one of id, time_index, or static must be provided per call. Bundling multiple fields in a single call is intentionally rejected to keep each recipe step traceable.

Parameters:

strict – Forwarded to ColumnMapCast.append() for the static feature bucket. Structural columns (id, time_index) are always cast strictly.

Raises:

ValueError – If zero or more than one field argument is provided.

feature_exprs() list[Expr][source]#

Return the with_columns expressions for static features.

features: TrajectoryFeatureCasts[source]#
probe(view) None[source]#

Validate structural and static feature casts against view.

structural: StructuralCasts[source]#
class tanat.cast.trajectory.TrajectoryFeatureCasts(static: ColumnMapCast = <factory>)[source]#

Bases: object

Feature casts consumed by trajectory views (static only).

__init__(static: ColumnMapCast = <factory>) None[source]#
apply(lf: LazyFrame) LazyFrame[source]#

Apply static feature casts to lf (no-op when empty).

copy() TrajectoryFeatureCasts[source]#

Return a deep copy of the feature casts.

is_empty() bool[source]#

Return True when no static cast is registered.

probe(view) None[source]#

Probe this candidate recipe on top of the current trajectory view.

probe_lf(lf: LazyFrame | None) None[source]#

Force-evaluate the static bucket on a view LazyFrame.

static: ColumnMapCast[source]#

Module contents#

Cast recipes and reusable cast primitives.

class tanat.cast.CastStep(dtype: pl.DataType, strict: bool = True)[source]#

Bases: NamedTuple

A single dtype-cast step with its strict flag.

Parameters:
  • dtype – Target Polars data type.

  • strict – When True (default), non-convertible values raise a ComputeError. When False, non-convertible values silently become null.

dtype: DataType[source]#

Alias for field number 0

strict: bool[source]#

Alias for field number 1

class tanat.cast.ColumnMapCast(recipes: dict[str, list[~tanat.cast.base.CastStep]]=<factory>)[source]#

Bases: object

Ordered cast recipes for a named set of columns.

__init__(recipes: dict[str, list[~tanat.cast.base.CastStep]]=<factory>) None[source]#
append(schema: dict[str, DataType], strict: bool = True) ColumnMapCast[source]#

Return a new map with each col dtype of schema appended.

Parameters:
  • schema – Mapping of column names to target dtypes.

  • strict – When True (default), non-convertible values raise. When False, they become null. The flag is stored per step so successive calls on the same column are independent.

apply(lf: LazyFrame) LazyFrame[source]#

Apply all registered column casts to lf (no-op when empty).

caster(col: str) Callable[[Expr], Expr] | None[source]#

Return the compiled caster for col, or None when unset.

copy() ColumnMapCast[source]#

Return a deep copy of the map.

exprs() list[Expr][source]#

Return one with_columns expression per registered column.

is_empty() bool[source]#

Return True when no column has a registered cast recipe.

probe_lf(lf: LazyFrame, n_rows: int = 10) None[source]#

Eagerly evaluate an n_rows sample of lf to surface cast errors.

The candidate recipe is applied only for the probe; lf itself remains lazy and unchanged for the caller.

recipes: dict[str, list[CastStep]][source]#
class tanat.cast.ScalarCast(recipe: list[DataType] = <factory>)[source]#

Bases: object

Ordered cast recipe for a single, well-known column.

__init__(recipe: list[DataType] = <factory>) None[source]#
append(dtype: DataType) ScalarCast[source]#

Return a new recipe with dtype appended as a final step.

caster() Callable[[Expr], Expr] | None[source]#

Return the compiled caster, or None when the recipe is empty.

copy() ScalarCast[source]#

Return a deep copy of the recipe.

final_dtype() DataType | None[source]#

Return the dtype the recipe ultimately casts to, None if empty.

is_empty() bool[source]#

Return True when no cast step is registered.

recipe: list[DataType][source]#
class tanat.cast.SequenceCastRecipe(structural: StructuralCasts = <factory>, features: SequenceFeatureCasts = <factory>)[source]#

Bases: BaseCastRecipe

Type-cast overrides for a sequence view.

__init__(structural: StructuralCasts = <factory>, features: SequenceFeatureCasts = <factory>) None[source]#
append(*, id: DataType | None = None, time_index: DataType | None = None, entity: dict[str, DataType] | None = None, static: dict[str, DataType] | None = None, strict: bool = True) SequenceCastRecipe[source]#

Return a new recipe extended with one structural or feature cast.

Exactly one of id, time_index, entity, or static must be provided per call. Bundling multiple fields in a single call is intentionally rejected to keep each recipe step traceable.

Parameters:

strict – Forwarded to ColumnMapCast.append() for feature buckets only (entity and static). Structural columns (id, time_index) are always cast strictly.

Raises:

ValueError – If zero or more than one field argument is provided.

property entity: dict[str, list[DataType]][source]#

Per-column dtype steps of the entity feature recipes.

entity_caster(col: str) Callable[[Expr], Expr] | None[source]#

Return the compiled caster for entity feature col, or None.

feature_exprs(is_static: bool = False) list[Expr][source]#

Return the with_columns expressions for entity or static features.

features: SequenceFeatureCasts[source]#
fork_casts(*, feature_col: str | None = None, static_col: str | None = None) _ForkCasts[source]#

Return precompiled casts for a fork operation.

probe(view) None[source]#

Validate structural and all feature casts against view.

structural: StructuralCasts[source]#
class tanat.cast.SequenceFeatureCasts(entity: ColumnMapCast = <factory>, static: ColumnMapCast = <factory>)[source]#

Bases: object

Feature casts consumed by sequence views.

__init__(entity: ColumnMapCast = <factory>, static: ColumnMapCast = <factory>) None[source]#
apply(lf: LazyFrame, *, is_static: bool) LazyFrame[source]#

Apply entity or static feature casts to lf (no-op when empty).

copy() SequenceFeatureCasts[source]#

Return a deep copy of the feature casts.

entity: ColumnMapCast[source]#
is_empty() bool[source]#

Return True when no entity and no static cast is registered.

probe(view, *, is_static: bool) None[source]#

Probe this candidate recipe on pre-scope raw data.

Feature casts run before entity scopes in the view pipeline. The probe must therefore use the same pre-scope data the cast will see at runtime.

probe_lf(lf: LazyFrame | None, *, is_static: bool) None[source]#

Force-evaluate the selected bucket on a view LazyFrame.

static: ColumnMapCast[source]#
class tanat.cast.StructuralCasts(id: ScalarCast = <factory>, time_index: ScalarCast = <factory>)[source]#

Bases: object

Shared ordered casts consumed by stores: id and time index.

__init__(id: ScalarCast = <factory>, time_index: ScalarCast = <factory>) None[source]#
append_id(dtype: DataType) StructuralCasts[source]#

Append dtype to the id recipe; reject closed-domain dtypes.

pl.Enum / pl.Categorical would conflict with any id outside the current view (the store consumes the cast on the full physical data). Materialise the view via save() first to narrow the domain.

append_time_index(dtype: DataType) StructuralCasts[source]#

Append dtype to the time_index recipe.

apply(lf: LazyFrame, *, id_col: str | None = None, time_cols: list[str] | None = None) LazyFrame[source]#

Apply id and (optionally) time-index structural casts to lf.

Parameters:
  • lf – Input LazyFrame.

  • id_col – Name of the id column to cast. None → skip.

  • time_cols – Names of time columns to cast. None / [] → skip.

copy() StructuralCasts[source]#

Return a deep copy of the structural casts.

id: ScalarCast[source]#
id_caster() Callable[[Expr], Expr] | None[source]#

Return the compiled caster for the id column, or None.

is_empty() bool[source]#

Return True when both id and time_index recipes are empty.

probe(view) None[source]#

Validate id and time_index recipes against full structural store data.

time_index: ScalarCast[source]#
time_index_caster() Callable[[Expr], Expr] | None[source]#

Return the compiled caster for the time_index column, or None.

class tanat.cast.TrajectoryCastRecipe(structural: StructuralCasts = <factory>, features: TrajectoryFeatureCasts = <factory>)[source]#

Bases: BaseCastRecipe

Type-cast overrides for a trajectory view.

Entity-level feature casts live in the trajectory’s sub-pools (see SequenceCastRecipe); at the trajectory layer only static features are observable directly.

__init__(structural: StructuralCasts = <factory>, features: TrajectoryFeatureCasts = <factory>) None[source]#
append(*, id: DataType | None = None, time_index: DataType | None = None, static: dict[str, DataType] | None = None, strict: bool = True) TrajectoryCastRecipe[source]#

Return a new recipe extended with one structural or feature cast.

Exactly one of id, time_index, or static must be provided per call. Bundling multiple fields in a single call is intentionally rejected to keep each recipe step traceable.

Parameters:

strict – Forwarded to ColumnMapCast.append() for the static feature bucket. Structural columns (id, time_index) are always cast strictly.

Raises:

ValueError – If zero or more than one field argument is provided.

feature_exprs() list[Expr][source]#

Return the with_columns expressions for static features.

features: TrajectoryFeatureCasts[source]#
probe(view) None[source]#

Validate structural and static feature casts against view.

structural: StructuralCasts[source]#
class tanat.cast.TrajectoryFeatureCasts(static: ColumnMapCast = <factory>)[source]#

Bases: object

Feature casts consumed by trajectory views (static only).

__init__(static: ColumnMapCast = <factory>) None[source]#
apply(lf: LazyFrame) LazyFrame[source]#

Apply static feature casts to lf (no-op when empty).

copy() TrajectoryFeatureCasts[source]#

Return a deep copy of the feature casts.

is_empty() bool[source]#

Return True when no static cast is registered.

probe(view) None[source]#

Probe this candidate recipe on top of the current trajectory view.

probe_lf(lf: LazyFrame | None) None[source]#

Force-evaluate the static bucket on a view LazyFrame.

static: ColumnMapCast[source]#
tanat.cast.apply_cast_exprs(lf: LazyFrame, exprs: list[Expr]) LazyFrame[source]#

Apply pre-built cast expressions to lf.

Returns lf unchanged when exprs is empty.

tanat.cast.probe_cast_recipe(lf: LazyFrame, recipes: dict[str, list[CastStep]], n_rows: int = 10) None[source]#

Validate multi-step cast recipes on a small sample of lf.

Each column is cast through its recipe in order (T0 T1 Tn). Absent columns are silently skipped. Steps with strict=False do not raise on incompatible values; they only verify structural type acceptance.

Raises:

TypeError – If any strict step fails, with column name and full chain in the message.