Skip to content

Commit

Permalink
Make shadowing attributes a warning instead of an error (#7193)
Browse files Browse the repository at this point in the history
  • Loading branch information
adriangb committed Aug 22, 2023
1 parent 4d929eb commit caa7801
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
6 changes: 3 additions & 3 deletions pydantic/_internal/_fields.py
Expand Up @@ -151,9 +151,9 @@ def collect_model_fields( # noqa: C901
if base is generic_origin:
# Don't error when "shadowing" of attributes in parametrized generics
continue
raise NameError(
f'Field name "{ann_name}" shadows an attribute in parent "{base.__qualname__}"; '
f'you might want to use a different field name with "alias=\'{ann_name}\'".'
warnings.warn(
f'Field name "{ann_name}" shadows an attribute in parent "{base.__qualname__}"; ',
UserWarning,
)

try:
Expand Down
35 changes: 35 additions & 0 deletions tests/test_main.py
Expand Up @@ -2887,3 +2887,38 @@ class Model(BaseModel):
'ctx': {'max_length': 1},
}
]


def test_shadow_attribute() -> None:
"""https://github.com/pydantic/pydantic/issues/7108"""

class Model(BaseModel):
foo: str

@classmethod
def __pydantic_init_subclass__(cls, **kwargs: Any):
super().__pydantic_init_subclass__(**kwargs)
for key in cls.model_fields.keys():
setattr(cls, key, getattr(cls, key, '') + ' edited!')

class One(Model):
foo: str = 'abc'

with pytest.warns(UserWarning, match=r'"foo" shadows an attribute in parent ".*One"'):

class Two(One):
foo: str

with pytest.warns(UserWarning, match=r'"foo" shadows an attribute in parent ".*One"'):

class Three(One):
foo: str = 'xyz'

# unlike dataclasses BaseModel does not preserve the value of defaults
# so when we access the attribute in `Model.__pydantic_init_subclass__` there is no default
# and hence we append `edited!` to an empty string
# we've talked about changing this but this is the current behavior as of this test
assert getattr(Model, 'foo', None) is None
assert getattr(One, 'foo', None) == ' edited!'
assert getattr(Two, 'foo', None) == ' edited! edited!'
assert getattr(Three, 'foo', None) == ' edited! edited!'

0 comments on commit caa7801

Please sign in to comment.