Skip to content
Draft
1 change: 1 addition & 0 deletions changelog.d/1616.change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a bug where `include()`/`exclude()` filters compared `Attribute` instances by value; they are now compared by identity so distinct attributes with equal fields are no longer conflated.
6 changes: 4 additions & 2 deletions src/attr/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ def include(*what):
cls, names, attrs = _split_what(what)

def include_(attribute, value):
"""Include."""
return (
value.__class__ in cls
or attribute.name in names
or attribute in attrs
or any(attribute is a for a in attrs)
)

return include_
Expand All @@ -63,10 +64,11 @@ def exclude(*what):
cls, names, attrs = _split_what(what)

def exclude_(attribute, value):
"""Exclude."""
return not (
value.__class__ in cls
or attribute.name in names
or attribute in attrs
or any(attribute is a for a in attrs)
)

return exclude_
38 changes: 38 additions & 0 deletions tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

@attr.s
class C:
"""C."""

a = attr.ib()
b = attr.ib()

Expand Down Expand Up @@ -124,3 +126,39 @@ def test_drop_class(self, excl, value):
"""
e = exclude(*excl)
assert e(fields(C).a, value) is False


@attr.s
class C2:
"""C2."""

a = attr.ib()
repeated = attr.ib()


@attr.s
class D2:
"""D2."""

b = attr.ib()
repeated = attr.ib()


class TestSameNameAcrossClasses:
"""
Two classes may define attributes with the same name but they are
different `Attribute` instances; excluding one must not exclude the
other (https://github.com/python-attrs/attrs/issues/864).
"""

def test_exclude_identity_not_equality(self):
"""Test Exclude identity not equality."""
e = exclude(fields(C2).repeated)
assert e(fields(C2).repeated, "x") is False
assert e(fields(D2).repeated, "x") is True

def test_include_identity_not_equality(self):
"""Test Include identity not equality."""
i = include(fields(C2).repeated)
assert i(fields(C2).repeated, "x") is True
assert i(fields(D2).repeated, "x") is False
Loading