diff --git a/pydantic/fields.py b/pydantic/fields.py index ba7eb60dbb..449dd55d4c 100644 --- a/pydantic/fields.py +++ b/pydantic/fields.py @@ -106,7 +106,8 @@ class FieldInfo(Representation): 'extra', ) - __field_constraints__ = { # field constraints with the default value + # field constraints with the default value, it's also used in update_from_config below + __field_constraints__ = { 'min_length': None, 'max_length': None, 'regex': None, @@ -164,7 +165,7 @@ def update_from_config(self, from_config: Dict[str, Any]) -> None: # attr_name is not an attribute of FieldInfo, it should therefore be added to extra self.extra[attr_name] = value else: - if current_value is None: + if current_value is self.__field_constraints__.get(attr_name, None): setattr(self, attr_name, value) def _validate(self) -> None: diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py index c48c194cac..2ce66334e8 100644 --- a/tests/test_edge_cases.py +++ b/tests/test_edge_cases.py @@ -1814,13 +1814,28 @@ class Config: def test_config_field_info_allow_mutation(): - """ - allow_mutation cannot be customised via Config.field because it has a default which is not None - """ class Foo(BaseModel): a: str = Field(...) class Config: - fields = {'a': {'allow_mutation': False}} + validate_assignment = True assert Foo.__fields__['a'].field_info.allow_mutation is True + + f = Foo(a='x') + f.a = 'y' + assert f.dict() == {'a': 'y'} + + class Bar(BaseModel): + a: str = Field(...) + + class Config: + fields = {'a': {'allow_mutation': False}} + validate_assignment = True + + assert Bar.__fields__['a'].field_info.allow_mutation is False + + b = Bar(a='x') + with pytest.raises(TypeError): + b.a = 'y' + assert b.dict() == {'a': 'x'}