-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pyright: operator not supported for NDArray #41
Comments
Ah, I see here that:
I will post back here with a simple example (once I've figured it out) in case someone else with the same misunderstanding comes along. |
And further reading leads me to understand this is a planned feature for the future. |
Sorry for the noise — spinning my gears a bit here. It seemed like this should be easy to fix with from typing import Annotated
import numpy.typing as npt
import numpydantic as npd
from pydantic import BaseModel
class TwoArrays(BaseModel):
x: Annotated[npt.NDArray, ...]
y: Annotated[npt.NDArray, ...]
def f(self):
return self.x.T + self.y.T This satisfies type checkers, which treat |
Apologies for the delay! was on holiday and just catching up on issues. yes! so there is a bit of awkwardness still before the planned 2.0 switch to using The basic problem is that we want to allow a bunch of different types of input to support a bunch of different types of arrays, but pydantic doesn't have an elegant way of handling differences between the input type - what is passed on creation - and the field type - the main thing that pydantic annotations specify, the thing that is actually contained by the model instance. So for example we want to support being able to use arrays on disk, or in formats like videos or images like this: class MyVideo(BaseModel):
video: NDArray[Shape["1920, 1080, 3"], np.uint8]
instance = MyVideo(video=Path("./my_video_file.mp4")) Pydantic will complain like "hey that's a string! that's not an array at all!" even if we convert it to an arraylike proxy class, so numpydantic tries to hack around that by autogenerating the Re: support for
so we would do something similar with I'm planning on getting the 2.0 work done sometime this spring, there are a few blockers upstream in pydantic but i think i understand how it works enough to monkeypatch them here (although pydantic is a bit of a moving target). Another thing that might be useful here is to provide specific annotations for specific interfaces. The initial purpose for this package was to be able to specify an abstract array specification that could be provided by arbitrary array backends, and that's the main implementation challenge. But if you don't care about that and just want to use numpy arrays, then it wouldn't be too hard to provide a specific The numpydantic/src/numpydantic/ndarray.py Lines 192 to 196 in 62f307f
So you could do something like this: # ...
from numpydantic.interface import NumpyInterface
# ...
class NumpyArray(NPTypingType, metaclass=NDArrayMeta):
@classmethod
def __get_pydantic_core_schema__(
cls,
_source_type: npt.NDArray,
_handler: "CallbackGetCoreSchemaHandler",
) -> core_schema.CoreSchema:
# ...
interface = NumpyInterface(shape, dtype)
# ...
return core_schema.with_info_plain_validator_function(
interface.validate,
serialization=core_schema.plain_serializer_function_ser_schema(
jsonize_array, when_used="json", info_arg=True
),
metadata=json_schema,
)
with a The way you could do this on your own with from typing import Annotated
import numpy.typing as npt
from numpydantic import NDArray
from pydantic import BaseModel, GetPydanticSchema
class MyModel(BaseModel)
array: Annotated[npt.NDArray, GetPydanticSchema(NDArray.__get_pydantic_core_schema__)] haven't tested it yet but that should work and is the direction that we're going for 2.0 anyway. That won't have the JSON Schema with it because of some quirks in how pydantic handles json schema generation we had to hack around (it's split off into a separate method, and when they are passed as annotation callables like this they behave differently than when defined with PRs welcome on all this if you get it to work <3 lmk if you have further troubles |
Wow! Thanks for this fantastic response! That last section is exactly what I was trying to figure out. I think it's not quite there: from typing import Annotated
import numpy as np
import numpy.typing as npt
from numpydantic import NDArray
from pydantic import BaseModel, GetPydanticSchema
type Array = Annotated[npt.NDArray, GetPydanticSchema(NDArray.__get_pydantic_core_schema__)]
class TwoArrays(BaseModel):
x: Array
y: Array
def f(self) -> Array:
return self.x.T + self.y.T Throws an exception at class definition:
In the meantime I hacked together a minimal serialization module that is fragile, has few features, and is hacky, but does 1) handle dataclasses with ndarray fields and 2) uses tagged unions for abstract types. You can tell how fragile it is by one function: def get_actual_type(obj: Any) -> Any:
# Strip off all type aliases.
while isinstance(obj, TypeAliasType):
obj = obj.__value__
# Go from a generic type to the underlying type.
if isinstance(obj, GenericAlias):
return get_origin(obj)
return obj Which will fail for I imagine I'll throw my code away and switch once you've got 2.0 running. My feeling is that the whole python typing ecosystem is moving very fast right now; I'm hesitant to spend much more effort on it while things are still in flux. E.g., pyright is OK with NDArray, but basedpyright complains about missing type arguments for the generic type. |
I was wrong; they'll both flag it, it's just they have different defaults. |
Given this code:
Pyright warns for the
return x + y
statement:Have I missed some obvious documentation?
numpydantic 1.6.6
pyright 1.1.391
pydantic 2.9.2
python 3.12.6
The text was updated successfully, but these errors were encountered: