'How do I pass kwargs to pydantic validator
I'm trying to write pydantic
validators, but I can't seem to understand how to make use of the kwargs
argument that is mentioned in the docs. I would like to pass conditional parameters for validation. Here's a toy example:
from pydantic import validator
import pydantic.dataclasses as pyd_dc
@pyd_dc.dataclass
class Point_t:
x: int = 0
y: int = 1
@validator("y")
def quadrant(cls, val, values, **kwargs):
pt = x, y = values.get("x", None), val
if x is None:
raise ValueError(f"invalid point: {x}, {y}")
signs = kwargs.get("signs", None)
if signs is None:
raise ValueError("'signs' parameter missing")
if all(c * s >= 0 for c, s in zip(pt, signs) if s != 0):
return val
raise ValueError(f"{pt} not in quadrant: {signs}")
This doesn't seem to work, instantiating a Point_t
object leads to a validation error:
ValidationError: 1 validation error for Point_t
y
'signs' parameter missing (type=value_error)
How do I pass on the signs
parameter in the above example? If there's no way, what's the point of allowing for **kwargs
? What am I missing?
Solution 1:[1]
Because Pydantic.validators are class methods here.
what's the point of allowing for **kwargs?
Since validators are “class methods”,and full signature here is equal to
(cls, value, *, values, config, field)
In other word, your def quadrant(..., **kwargs):
is euqal to config, field
How do I pass kwargs to pydantic validator
1) Create custom config and read from config
2) Fields hack
class Point_t:
signs = dict
x: int = 0
def quadrant(cls, val, values, **kwargs):
signs = values[signs]
if signs is None:
raise ValueError("'signs' parameter missing")
if all(c * s >= 0 for c, s in zip(pt, signs) if s != 0):
return val
Solution 2:[2]
I solved this using Config
on the pydantic model. This is especially relevant when creating reusable validators.
from pydantic import validator
import pydantic.dataclasses as pyd_dc
def name_must_match(cls, v: str) -> str:
"""
Throw an error if the provided value does not match
the class name (`cls.Config.name`)
Note: for this validator to work, provided pydantic model (`cls`)
must have a Config attribute, with a `name` attribute.
"""
if v != cls.Config.name:
raise ValueError('value does not equal class name')
return v
# Now to use the validator
@pyd_dc.dataclass
class Point:
"""Some pydantic model"""
class Config:
"""Store extra info here"""
name = 'foo'
# define your fields
name: str = 'foo'
x: int = 0
y: int = 1
# Fields with underscores can be hidden from json encoder
_name = validator('name',
allow_reuse=True,
pre=True,
always=True
)(name_must_match)
# To test it out
>> Point(name='foo', x=1, y=2)
Point(name='foo', x=1, y=2)
>> Point(name='bar', x=3, y=4)
pydantic.error_wrappers.ValidationError: 1 validation error for Point
name
value does not equal class name (type=value_error)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Tyler |
Solution 2 | ybressler_simon |