Failures and limits#
The error classes#
Error |
Import from |
Base |
Raised when |
|---|---|---|---|
|
|
|
a declaration is invalid, unsupported, or reached Pydantic with no entry point |
|
|
|
an array disagrees with its declared requirement |
|
|
|
a dimension lookup found no extent. Its |
|
|
|
a backend cannot inspect a declared property of this value, such as |
|
|
|
a transform returned an array that broke its preservation contract |
Where the error is raised decides how you catch it. Pydantic wraps a ValueError raised
inside its own validation callbacks, and Tenspec’s check runs in one of those. So a
TensorMismatch, and a BindingError raised while a value is being checked, arrive inside a
ValidationError. A model validator is one of those callbacks too. An error raised in the body
of a checked function is not: it propagates as itself. axis_size in a function body, or
outside every boundary, therefore raises BindingError directly, as
Axis scope and axis_size shows.
TensorMismatch keeps its parts readable, and it holds no array:
from typing import Literal as Shape
import numpy as np
from pydantic import ValidationError
from tenspec import NonEmpty, validate
from tenspec.errors import TensorMismatch
from tenspec.numpy import Float
try:
validate((np.ones(3), np.ones(5)), tuple[Float[Shape["rows"]], Float[Shape["rows"]]])
except ValidationError as refusal:
entry = refusal.errors()[0]
original = entry["ctx"]["error"]
print(entry["loc"], isinstance(original, TensorMismatch))
print(original.requirement, "|", original.observed, "|", original.bindings)
try:
validate(np.zeros((2, 0)), Float[Shape["rows cols"], NonEmpty])
except ValidationError as refusal:
print(refusal.errors()[0]["msg"])
What this release does not check#
Case |
What happens |
|---|---|
an |
|
a callable that is not a plain Python function |
|
a union of alternative tensor structures |
|
a tensor alias that contains its own name |
|
a device requirement on NumPy |
|
a Tenspec declaration on a model without the mixin |
|
A declaration relates values inside one boundary. It does not relate the length of a Python sequence to an axis, and it does not relate an axis of a nested model to one of its parent. Write those by hand, as in A relation the declaration cannot express.
What a declaration does not promise#
No immutability.
CopyReadOnlyandReadOnlycontrol a copy and a flag, not access through a base array.No promise about a later value. A check happens at its boundary. See An owned computed result.
Nothing about what an outer validator returns. An
AfterValidatorruns after the check and owns its own result.No byte order. A logical alias such as
Float64accepts either byte order. Transform preservation compares the native dtype, so a transform may not change it.No claim about operability. A backend that represents a format says nothing about whether your installed NumPy or Torch can compute with it.
No static shape check. No type checker compares two shapes.