pydantic: [PYD-136] ModelAfterValidator causing warnings from Pylance and mypy
Initial Checks
- I confirm that I’m using Pydantic V2 installed directly from the
main
branch, or equivalent
Description
I want to use an ModelAvterValidator via the model_validator
decorator, however, both Pylance and mypy are issuing warnings when doing so. To make sure I was using it correctly, I tried using the example code from the documentation and I am experiencing the same issues there.
The code below results in the following two warnings:
Argument 1 has incompatible type "Callable[[UserModel, UserModel], Any]"; expected "Union[ModelAfterValidator, ModelAfterValidatorWithoutInfo]" [arg-type] (mypy)
Argument of type "(cls: Self@UserModel, m: UserModel) -> UserModel" cannot be assigned to parameter of type "_AnyModeAfterValidator"
Type "(cls: Self@UserModel, m: UserModel) -> UserModel" cannot be assigned to type "_AnyModeAfterValidator"
Type "(cls: Self@UserModel, m: UserModel) -> UserModel" cannot be assigned to type "(self: _ModelType@__call__, __info: ValidationInfo) -> _ModelType@__call__"
Parameter name mismatch: "self" versus "cls"
Parameter 2: type "ValidationInfo" cannot be assigned to type "UserModel"
"ValidationInfo" is incompatible with "UserModel"
Type "(cls: Self@UserModel, m: UserModel) -> UserModel" cannot be assigned to type "(self: _ModelType@__call__) -> _ModelType@__call__"
Parameter name mismatch: "self" versus "cls" (pylance)
When changing the parameter name cls
to self
as suggested by Pylance, the corresponding lines in the latter warning disappear, but nothing else happens and I am not sure whether that is what I am supposed to do there.
As my IDE I use VS Code OSS with the python, pylance, and mypy extensions, among others.
Example Code
from pydantic import BaseModel, model_validator
class UserModel(BaseModel):
username: str
password1: str
password2: str
@model_validator(mode="after")
def check_passwords_match(cls, m: "UserModel"):
pw1 = m.password1
pw2 = m.password2
if pw1 is not None and pw2 is not None and pw1 != pw2:
raise ValueError("passwords do not match")
return m
Python, Pydantic & OS Version
pydantic version: 2.0b3
pydantic-core version: 0.39.0 release build profile
install path: <path-to-workspace>/env/lib/python3.11/site-packages/pydantic
python version: 3.11.3 (main, Jun 5 2023, 09:32:32) [GCC 13.1.1 20230429]
platform: Linux-6.3.9-arch1-1-x86_64-with-glibc2.37
optional deps. installed: ['typing-extensions']
Selected Assignee: @hramezani
Selected Assignee: @Kludex
Selected Assignee: @lig
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 4
- Comments: 18 (13 by maintainers)
+1, played around with this for a bit but can’t get any model validators to work with mypy on V2
Yes please open a separate issue, thanks!
My bad, looks like my mypy cache was playing up, sorry.
Tested in a clean repo and seems to be working!
It seems like this works with pyright but not mypy. @Kludex if you didn’t already try the above, can you look into why it works with pyright but not mypy? It might be worth asking on the mypy issue tracker.
Can you use this instead?
@Kludex even with the
@classmethod
decorator,mypy
is still unhappy:(example taken from docs,
mypy 1.4.1
)Looking at the excepted signatures:
https://github.com/pydantic/pydantic/blob/e0c0fe8cd6b6a1a5fdd43ab92d9814b278e324ad/pydantic/functional_validators.py#L402-L422
They doesn’t seem to match the one used in the example (for reference, the callback protocols defined for
wrap
andbefore
seem to be working, and they don’t have the@staticmethod
decorator)Thank you, it seems I missed this documentation then.
You can add the decorator
@classmethod
, and the IDE will be happy. 🙏We’ve already documented this behavior.