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:
Hynek Schlawack 2017-08-21 00:39:34 +02:00 committed by Tin Tvrtković
parent 37a421e559
commit 4faf5f9c26
3 changed files with 24 additions and 5 deletions

View File

@ -0,0 +1 @@
Subclasses now can overwrite attribute definitions of their superclass.

View File

@ -181,11 +181,6 @@ def _transform_attrs(cls, these):
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:
ca_list = [(name, attr)
for name, attr
@ -201,6 +196,17 @@ def _transform_attrs(cls, these):
for attr_name, ca
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]
AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)

View File

@ -271,3 +271,15 @@ class TestDarkMagic(object):
return self.x + 1
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()