Pydantic has support for validators (docs) which allow transforming an input value before storing it in the model. It seems like the @field_validator decorator pattern should be supported (see prior issues like #589), but the Annotated[T, *V] pattern is not.
As a very simple example:
from typing import Annotated, Any
from pydantic import BaseModel, BeforeValidator
def ensure_str(v: Any) -> str:
return str(v)
class MyModel(BaseModel):
field: Annotated[str, BeforeValidator(ensure_str)]
MyModel(field=5) # You can pass in other things here, but Pyrefly doesn't allow it
The example above can take in any value, convert it to a string, and store it as such in the model field. Pyrefly, however, only looks at the str argument of the Annotated type, and completely ignores the validators that come after. It only allows assigning a str to this field, even though I should be able to pass in whatever I want.
If validators are supplied, Pyrefly should let you assign whichever value the first validator allows. In my example above this would be Any, but that doesn't have to be the case. Ideally, this would respect model_config.validate_assignment to correctly typecheck on assignment after __init__ as well.
Similarly, it would make sense to have a check for the output value of the validator to be compatible with the supposed type of the field, meaning that -> str is assignable to Annotated[str, ...].
It could go further and check that chained validators are compatible with eachother, but that might be out of scope for this issue as it seems quite complicated.
Why not just use the decorator pattern?
This allows extracting the validators out to a custom type that you can attach to fields, rather than having to write a validator function for every single field every single time. For large models that have a lot of fields that need pre-processing, this saves a lot of effort.
Pydantic has support for
validators(docs) which allow transforming an input value before storing it in the model. It seems like the@field_validatordecorator pattern should be supported (see prior issues like #589), but theAnnotated[T, *V]pattern is not.As a very simple example:
The example above can take in any value, convert it to a string, and store it as such in the model field. Pyrefly, however, only looks at the
strargument of theAnnotatedtype, and completely ignores the validators that come after. It only allows assigning astrto this field, even though I should be able to pass in whatever I want.If validators are supplied, Pyrefly should let you assign whichever value the first validator allows. In my example above this would be
Any, but that doesn't have to be the case. Ideally, this would respectmodel_config.validate_assignmentto correctly typecheck on assignment after__init__as well.Similarly, it would make sense to have a check for the output value of the validator to be compatible with the supposed type of the field, meaning that
-> stris assignable toAnnotated[str, ...].It could go further and check that chained validators are compatible with eachother, but that might be out of scope for this issue as it seems quite complicated.
Why not just use the decorator pattern?
This allows extracting the validators out to a custom type that you can attach to fields, rather than having to write a validator function for every single field every single time. For large models that have a lot of fields that need pre-processing, this saves a lot of effort.