Updating multiple Pydantic fields that are validated together

Viewed 41

How do you update multiple properties on a pydantic model that are validated together and dependent upon each other?

Here is a contrived but simple example:

from pydantic import BaseModel, root_validator

class Example(BaseModel):
    a: int
    b: int

    @root_validator
    def test(cls, values):
        if values['a'] != values['b']:
            raise ValueError('a and b must be equal')  
        return values

    class Config:
        validate_assignment = True

example = Example(a=1, b=1)

example.a = 2 # <-- error raised here because a is 2 and b is still 1
example.b = 2 # <-- don't get a chance to do this

Error:

ValidationError: 1 validation error for Example
__root__
  a and b must be equal (type=value_error)

Both a and b having a value of 2 is valid, but they can't be updated one at a time without triggering the validation error.

Is there a way to put the validation on hold until both are set? Or a way to somehow update both of them at the same time? Thanks!

1 Answers

You can make a workaround building a setter.

from pydantic import BaseModel, root_validator


class Example(BaseModel):
    a: int
    b: int


    @root_validator
    def test(cls, values):
        if values['a'] != values['b']:
            raise ValueError('a and b must be equal')
        return values

    class Config:
        validate_assignment = True

    def set_a_and_b(self, value):
        self.Config.validate_assignment = False
        self.a, self.b = value, value
        self.Config.validate_assignment = True

PoC:

>>> example = Example(a=1, b=1)
>>> example.a = 2
Traceback (most recent call last):
  File "D:\temp\venv\lib\site-packages\IPython\core\interactiveshell.py", line 3398, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-4-950b5db07c46>", line 1, in <cell line: 1>
    example.a =2
  File "pydantic\main.py", line 393, in pydantic.main.BaseModel.__setattr__
pydantic.error_wrappers.ValidationError: 1 validation error for Example
__root__
  a and b must be equal (type=value_error)

>>> example.set_a_and_b(2) # <========= workaround 
>>> example
Example(a=2, b=2)
>>> example.a = 3
Traceback (most recent call last):
  File "D:\temp\venv\lib\site-packages\IPython\core\interactiveshell.py", line 3398, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-8-d93e8eb8a0e3>", line 1, in <cell line: 1>
    example.a = 3
  File "pydantic\main.py", line 393, in pydantic.main.BaseModel.__setattr__
pydantic.error_wrappers.ValidationError: 1 validation error for Example
__root__
  a and b must be equal (type=value_error)

But maybe in your real case you should use some setters and getters instead (or with) standard validation

Related