Allow subclasses to overwrite attributes (#229)
Simply filter out all attributes from super classes that are present in the current class. Fixes #221
This commit is contained in:
parent
37a421e559
commit
4faf5f9c26
|
@ -0,0 +1 @@
|
||||||
|
Subclasses now can overwrite attribute definitions of their superclass.
|
|
@ -181,11 +181,6 @@ def _transform_attrs(cls, these):
|
||||||
|
|
||||||
If *these* is passed, use that and don't look for them on the class.
|
If *these* is passed, use that and don't look for them on the class.
|
||||||
"""
|
"""
|
||||||
super_cls = []
|
|
||||||
for c in reversed(cls.__mro__[1:-1]):
|
|
||||||
sub_attrs = getattr(c, "__attrs_attrs__", None)
|
|
||||||
if sub_attrs is not None:
|
|
||||||
super_cls.extend(a for a in sub_attrs if a not in super_cls)
|
|
||||||
if these is None:
|
if these is None:
|
||||||
ca_list = [(name, attr)
|
ca_list = [(name, attr)
|
||||||
for name, attr
|
for name, attr
|
||||||
|
@ -201,6 +196,17 @@ def _transform_attrs(cls, these):
|
||||||
for attr_name, ca
|
for attr_name, ca
|
||||||
in sorted(ca_list, key=lambda e: e[1].counter)
|
in sorted(ca_list, key=lambda e: e[1].counter)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
super_cls = []
|
||||||
|
non_super_names = set(a.name for a in non_super_attrs)
|
||||||
|
for c in reversed(cls.__mro__[1:-1]):
|
||||||
|
sub_attrs = getattr(c, "__attrs_attrs__", None)
|
||||||
|
if sub_attrs is not None:
|
||||||
|
super_cls.extend(
|
||||||
|
a for a in sub_attrs
|
||||||
|
if a not in super_cls and a.name not in non_super_names
|
||||||
|
)
|
||||||
|
|
||||||
attr_names = [a.name for a in super_cls + non_super_attrs]
|
attr_names = [a.name for a in super_cls + non_super_attrs]
|
||||||
|
|
||||||
AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
|
AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
|
||||||
|
|
|
@ -271,3 +271,15 @@ class TestDarkMagic(object):
|
||||||
return self.x + 1
|
return self.x + 1
|
||||||
|
|
||||||
assert C(1, 2) == C()
|
assert C(1, 2) == C()
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("slots", [True, False])
|
||||||
|
@pytest.mark.parametrize("frozen", [True, False])
|
||||||
|
def test_attrib_overwrite(self, slots, frozen):
|
||||||
|
"""
|
||||||
|
Subclasses can overwrite attributes of their superclass.
|
||||||
|
"""
|
||||||
|
@attr.s(slots=slots, frozen=frozen)
|
||||||
|
class SubOverwrite(Super):
|
||||||
|
x = attr.ib(default=attr.Factory(list))
|
||||||
|
|
||||||
|
assert SubOverwrite([]) == SubOverwrite()
|
||||||
|
|
Loading…
Reference in New Issue