Numpydantic
Numpydantic provides robust type and shape validation, and serialization capabilities for arbitrary array types (primarily NumPy arrays) within Pydantic models. It enables developers to define strict data contracts for numerical data, integrating seamlessly with Pydantic v1.x and v2.x. The current version is 1.8.1, with a consistent, active release cadence.
Warnings
- gotcha When serializing a Pydantic model containing `NDArray` fields (e.g., using `model_dump_json`), NumPy arrays are, by default, converted into standard Python lists (list of lists). For very large arrays, this can be extremely inefficient, consume significant memory, and result in large JSON payloads.
- gotcha `numpydantic` heavily relies on `typing.Annotated` for specifying array shape and data type constraints. Incorrectly structuring these annotations (e.g., providing a plain tuple instead of `NDArray[(shape_tuple), (dtype_string)]`) will lead to validation errors or unexpected behavior.
- gotcha While `numpydantic` aims for compatibility with both Pydantic v1.x and v2.x, subtle behavioral differences in Pydantic's core validation and serialization mechanisms might exist. For instance, `model.json()` is deprecated in Pydantic v2 in favor of `model.model_dump_json()`.
Install
-
pip install numpydantic
Imports
- NDArray
from numpydantic import NDArray
Quickstart
from typing import Annotated
import numpy as np
from pydantic import BaseModel
from numpydantic import NDArray
class MyModel(BaseModel):
image: Annotated[NDArray[("width", "height"), "uint8"], "Image data"]
matrix: Annotated[NDArray["*,*", float], "Arbitrary float matrix"]
vector: Annotated[NDArray[3, int], "3-element integer vector"]
# Example usage:
try:
model = MyModel(
image=np.zeros((100, 200), dtype=np.uint8),
matrix=np.ones((2, 2), dtype=float),
vector=np.array([1, 2, 3], dtype=int)
)
print("Model created successfully:")
print(model.model_dump_json(indent=2))
# Example of validation error
print("\nAttempting invalid data:")
MyModel(
image=np.zeros((50, 50), dtype=np.float32), # Wrong dtype
matrix=np.array([1, 2, 3]), # Wrong dimensions
vector=np.array([1, 2], dtype=int) # Wrong size
)
except Exception as e:
print(f"Caught expected error: {type(e).__name__}: {e}")