Skip to content

Commit 0b7b855

Browse files
authored
Track extra fields set after init in model_fields_set (pydantic#12817)
1 parent fc68422 commit 0b7b855

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

pydantic/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ def _setattr_handler(self, name: str, value: Any) -> Callable[[BaseModel, str, A
10961096
elif attr is None:
10971097
# attribute does not exist, so put it in extra
10981098
self.__pydantic_extra__[name] = value
1099+
self.__pydantic_fields_set__.add(name)
10991100
return None # Can not return memoized handler with possibly freeform attr names
11001101
else:
11011102
# attribute _does_ exist, and was not in extra, so update it

tests/test_edge_cases.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3135,3 +3135,22 @@ def my_model_validator(self):
31353135
@classmethod
31363136
def __get_validators__(cls):
31373137
raise AssertionError('This should not be called')
3138+
3139+
3140+
def test_model_fields_set_includes_extra_after_assignment():
3141+
"""Regression test for https://github.com/pydantic/pydantic/issues/11134.
3142+
3143+
Extra fields set after initialization should be included in model_fields_set.
3144+
"""
3145+
from pydantic import BaseModel, ConfigDict
3146+
3147+
class Model(BaseModel):
3148+
model_config = ConfigDict(extra='allow')
3149+
field: int
3150+
3151+
m = Model.model_validate({'field': 1, 'extra_at_init': 2})
3152+
assert m.model_fields_set == {'field', 'extra_at_init'}
3153+
3154+
m.extra_after_init = 3
3155+
assert m.model_fields_set == {'field', 'extra_at_init', 'extra_after_init'}
3156+
assert m.model_extra == {'extra_at_init': 2, 'extra_after_init': 3}

0 commit comments

Comments
 (0)