Skip to content

Commit

Permalink
Allow subclasses to overwrite attributes (#229)
Browse files Browse the repository at this point in the history
Simply filter out all attributes from super classes that are present in the
current class.

Fixes #221
  • Loading branch information
hynek authored and Tinche committed Aug 20, 2017
1 parent 37a421e commit 4faf5f9
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
1 change: 1 addition & 0 deletions changelog.d/221.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Subclasses now can overwrite attribute definitions of their superclass.
16 changes: 11 additions & 5 deletions src/attr/_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions tests/test_dark_magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,15 @@ def compute(self):
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()

0 comments on commit 4faf5f9

Please sign in to comment.