Skip to content

Commit bc4092b

Browse files
PrettyWoodart049
authored andcommitted
fix: update all modified field values in root_validator when validate_assignment is on (#2119)
* fix: update all modified field values in `root_validator` when `validate_assignment` is on closes #2116 * chore: update root_validator name Co-authored-by: Arthur Pastel <[email protected]> Co-authored-by: Arthur Pastel <[email protected]>
1 parent 0b5d74e commit bc4092b

File tree

3 files changed

+29
-1
lines changed

3 files changed

+29
-1
lines changed

changes/2116-PrettyWood.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fix: update all modified field values in `root_validator` when `validate_assignment` is on

pydantic/main.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,12 @@ def __setattr__(self, name, value): # noqa: C901 (ignore complexity)
406406
if errors:
407407
raise ValidationError(errors, self.__class__)
408408

409-
self.__dict__[name] = value
409+
# update the whole __dict__ as other values than just `value`
410+
# may be changed (e.g. with `root_validator`)
411+
object_setattr(self, '__dict__', new_values)
412+
else:
413+
self.__dict__[name] = value
414+
410415
self.__fields_set__.add(name)
411416

412417
def __getstate__(self) -> 'DictAny':

tests/test_main.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,28 @@ def current_lessequal_500(cls, values):
666666
]
667667

668668

669+
def test_root_validator_many_values_change():
670+
"""It should run root_validator on assignment and update ALL concerned fields"""
671+
672+
class Rectangle(BaseModel):
673+
width: float
674+
height: float
675+
area: float = None
676+
677+
class Config:
678+
validate_assignment = True
679+
680+
@root_validator
681+
def set_area(cls, values):
682+
values['area'] = values['width'] * values['height']
683+
return values
684+
685+
r = Rectangle(width=1, height=1)
686+
assert r.area == 1
687+
r.height = 5
688+
assert r.area == 5
689+
690+
669691
def test_enum_values():
670692
FooEnum = Enum('FooEnum', {'foo': 'foo', 'bar': 'bar'})
671693

0 commit comments

Comments
 (0)