Closed MilanStaffehl closed 1 month ago
Making this work with typing is difficult at the moment, for multiple reasons:
TypeVarTuple
. The only way to use it would be NDArray[Shape[*tuple[int, ...]], np.int32]
. Ellipses are allowed exclusively in the tuple
class type parameters.tuple
directly instead of Shape
, type checkers will perceive a NDArray
parametrized with tuple[int, int]
not as a subtype of one with shape tuple[int, ...]
due to numpy having typed the array shape as invariant:
_ShapeType = TypeVar("_ShapeType", bound=Any) # <--- INVARIANT!
class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType_co]):
...
(from __init__.pyi
of numpy)
The latter means that the only way to make this work reliably would be to write one's own protocol for the numpy.ndarray
class, mirroring the behavior of the numpy implementation plus the covariance of the shape type var.
I will make the protocol class for numpy.ndarray
its own issue. This seems like a good addition as it will also make Literal
and named axes compatible with generic shapes. It will be a lot of boilerplate code, but ultimately it will enable accurate typing for Python < 3.12 so that makes it worthwhile, I think.
In the meantime, this issue and its PR should focus on just adding the validation for arrays of unspecified dimensionality to the pydantic validator annotation and removing Shape
from the library for this purpose. The invariance of the shape type parameter will be treated as an expected failure in the tests for now.
New issue for protocol is now #48.
Detect shapes of indetermined size and skip shape validation if first entry is
int
or anint
-like derivative. If the first entry was a Literal, verify that all axes have that exact same length, but skip verification of dimensionality.