support overwriting dunder attributes of BaseModel instances (#3907)

* support overwriting dunder attributes of `BaseModel` instances

closes #3777

* suggestion from @adriangb

Co-authored-by: Samuel Colvin <s@muelcolvin.com>
This commit is contained in:
Eric Jolibois
2022-08-08 17:15:01 +02:00
committed by GitHub
parent cf16f7c388
commit da8f0c034e
4 changed files with 33 additions and 10 deletions
+1
View File
@@ -0,0 +1 @@
support overwriting dunder attributes of `BaseModel` instances
+5 -2
View File
@@ -53,6 +53,7 @@ from .typing import (
update_model_forward_refs,
)
from .utils import (
DUNDER_ATTRIBUTES,
ROOT_KEY,
ClassAttribute,
GetterDict,
@@ -350,7 +351,7 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
@no_type_check
def __setattr__(self, name, value): # noqa: C901 (ignore complexity)
if name in self.__private_attributes__:
if name in self.__private_attributes__ or name in DUNDER_ATTRIBUTES:
return object_setattr(self, name, value)
if self.__config__.extra is not Extra.allow and name not in self.__fields__:
@@ -891,7 +892,9 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
def __repr_args__(self) -> 'ReprArgs':
return [
(k, v) for k, v in self.__dict__.items() if k not in self.__fields__ or self.__fields__[k].field_info.repr
(k, v)
for k, v in self.__dict__.items()
if k not in DUNDER_ATTRIBUTES and (k not in self.__fields__ or self.__fields__[k].field_info.repr)
]
+13 -8
View File
@@ -78,6 +78,7 @@ __all__ = (
'ROOT_KEY',
'get_unique_discriminator_alias',
'get_discriminator_alias_and_values',
'DUNDER_ATTRIBUTES',
'LimitedDict',
)
@@ -691,15 +692,19 @@ def is_valid_field(name: str) -> bool:
return ROOT_KEY == name
DUNDER_ATTRIBUTES = {
'__annotations__',
'__classcell__',
'__doc__',
'__module__',
'__orig_bases__',
'__orig_class__',
'__qualname__',
}
def is_valid_private_name(name: str) -> bool:
return not is_valid_field(name) and name not in {
'__annotations__',
'__classcell__',
'__doc__',
'__module__',
'__orig_bases__',
'__qualname__',
}
return not is_valid_field(name) and name not in DUNDER_ATTRIBUTES
_EMPTY = object()
+14
View File
@@ -19,6 +19,7 @@ from typing import (
from uuid import UUID, uuid4
import pytest
from typing_extensions import Annotated
from pydantic import (
BaseConfig,
@@ -2174,6 +2175,19 @@ def test_new_union_origin():
}
def test_annotated_class():
class PydanticModel(BaseModel):
foo: str = '123'
PydanticAlias = Annotated[PydanticModel, 'bar baz']
pa = PydanticAlias()
assert isinstance(pa, PydanticModel)
pa.__doc__ = 'qwe'
assert repr(pa) == "PydanticModel(foo='123')"
assert pa.__doc__ == 'qwe'
@pytest.mark.parametrize(
'ann',
[Final, Final[int]],