Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for attrs v21.3.0+ #1331

Merged
merged 9 commits into from Jan 20, 2022
7 changes: 6 additions & 1 deletion astroid/brain/brain_attrs.py
Expand Up @@ -10,7 +10,9 @@
from astroid.nodes.node_classes import AnnAssign, Assign, AssignName, Call, Unknown
from astroid.nodes.scoped_nodes import ClassDef

ATTRIB_NAMES = frozenset(("attr.ib", "attrib", "attr.attrib", "attr.field", "field"))
ATTRIB_NAMES = frozenset(
("attr.ib", "attrib", "attr.attrib", "attr.field", "attrs.field", "field")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could discuss if attrib and field should be in this list but that ship has sailed I think.

Thanks for removing define! 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right, it's also a problem.

Suggested change
("attr.ib", "attrib", "attr.attrib", "attr.field", "attrs.field", "field")
("attr.ib", "attr.attrib", "attr.field", "attrs.field")

Suggestion done in order to check if it's causing test fails. Imo we can most probably not infer the value as aliasing of attrs must be rare considering it's a small name, but we also should infer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like it breaks the existing test_attr_transform as well as the newly added test_attrs_transform.

        @attrs
        class Bah:
            d = attrib(attr.Factory(dict))

Also there's a regression test in pylint that also relies on the existing attrib; https://github.com/PyCQA/pylint/blob/main/tests/functional/r/regression/regression_4439.py

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Pierre-Sassoulas Let's revert then. Thanks @jacobbogdanov for checking this out.

)
ATTRS_NAMES = frozenset(
(
"attr.s",
Expand All @@ -20,6 +22,9 @@
"attr.define",
"attr.mutable",
"attr.frozen",
"attrs.define",
"attrs.mutable",
"attrs.frozen",
)
)

Expand Down
67 changes: 67 additions & 0 deletions tests/unittest_brain.py
Expand Up @@ -2211,6 +2211,73 @@ class Eggs:
should_be_unknown = next(module.getattr(name)[0].infer()).getattr("d")[0]
self.assertIsInstance(should_be_unknown, astroid.Unknown)

def test_attrs_transform(self) -> None:
jacobbogdanov marked this conversation as resolved.
Show resolved Hide resolved
"""Test brain for decorators of the 'attrs' package.

Package added support for 'attrs' a long side 'attr' in v21.3.0.
See: https://github.com/python-attrs/attrs/releases/tag/21.3.0
"""
module = astroid.parse(
"""
import attrs
from attrs import field, mutable, frozen

@attrs.define
class Foo:

d = attrs.field(attrs.Factory(dict))

f = Foo()
f.d['answer'] = 42

@attrs.define(slots=True)
class Bar:
d = field(attrs.Factory(dict))

g = Bar()
g.d['answer'] = 42

@attrs.mutable
class Bah:
d = field(attrs.Factory(dict))

h = Bah()
h.d['answer'] = 42

@attrs.frozen
class Bai:
d = attrs.field(attrs.Factory(dict))

i = Bai()
i.d['answer'] = 42

@attrs.define
class Spam:
d = field(default=attrs.Factory(dict))

j = Spam(d=1)
j.d['answer'] = 42

@attrs.mutable
class Eggs:
d = attrs.field(default=attrs.Factory(dict))

k = Eggs(d=1)
k.d['answer'] = 42

@attrs.frozen
class Eggs:
d = attrs.field(default=attrs.Factory(dict))

l = Eggs(d=1)
l.d['answer'] = 42
"""
)

for name in ("f", "g", "h", "i", "j", "k", "l"):
should_be_unknown = next(module.getattr(name)[0].infer()).getattr("d")[0]
self.assertIsInstance(should_be_unknown, astroid.Unknown)

def test_special_attributes(self) -> None:
"""Make sure special attrs attributes exist"""

Expand Down