mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
Fix duplicate calls to __set_name__ for non-private attributes in BaseModel.__new__ (#4410)
* fix: double call for public attrs, extend test * add changes * remove change file, update 4407 file
This commit is contained in:
@@ -1 +1 @@
|
||||
Fix PEP487 protocol in `BaseModel`: call `__set_name__` on namespace values that implement the method.
|
||||
Fix PEP487 `__set_name__` protocol in `BaseModel` for PrivateAttrs.
|
||||
|
||||
+5
-3
@@ -287,10 +287,12 @@ class ModelMetaclass(ABCMeta):
|
||||
cls.__try_update_forward_refs__()
|
||||
|
||||
# preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487
|
||||
# for attributes not in `new_namespace` (e.g. private attributes)
|
||||
for name, obj in namespace.items():
|
||||
set_name = getattr(obj, '__set_name__', None)
|
||||
if callable(set_name):
|
||||
set_name(cls, name)
|
||||
if name not in new_namespace:
|
||||
set_name = getattr(obj, '__set_name__', None)
|
||||
if callable(set_name):
|
||||
set_name(cls, name)
|
||||
|
||||
return cls
|
||||
|
||||
|
||||
@@ -225,10 +225,11 @@ def test_generics_model():
|
||||
assert result.__config__.orm_mode is True
|
||||
|
||||
|
||||
def test_set_name():
|
||||
@pytest.mark.parametrize('base', [ModelPrivateAttr, object])
|
||||
def test_set_name(base):
|
||||
calls = []
|
||||
|
||||
class class_deco(ModelPrivateAttr):
|
||||
class class_deco(base):
|
||||
def __init__(self, fn):
|
||||
super().__init__()
|
||||
self.fn = fn
|
||||
@@ -236,9 +237,22 @@ def test_set_name():
|
||||
def __set_name__(self, owner, name):
|
||||
calls.append((owner, name))
|
||||
|
||||
def __get__(self, obj, type=None):
|
||||
return self.fn(obj) if obj else self
|
||||
|
||||
class A(BaseModel):
|
||||
x: int
|
||||
|
||||
@class_deco
|
||||
def _some_func(self):
|
||||
return self
|
||||
return self.x
|
||||
|
||||
assert calls == [(A, '_some_func')]
|
||||
a = A(x=2)
|
||||
|
||||
# we don't test whether calling the method on a PrivateAttr works:
|
||||
# attribute access on privateAttributes is more complicated, it doesn't
|
||||
# get added to the class namespace (and will also get set on the instance
|
||||
# with _init_private_attributes), so the descriptor protocol won't work.
|
||||
if base is object:
|
||||
assert a._some_func == 2
|
||||
|
||||
Reference in New Issue
Block a user