Skip to content

Commit

Permalink
Add support for attrs v21.3.0+ (#1331)
Browse files Browse the repository at this point in the history
* Add support for attrs v21.3.0+

Since version [21.3.0](https://github.com/python-attrs/attrs/releases/tag/21.3.0)
you can now `import attrs` instead of just `import attr`.

This patch adds support so that astroid doesn't barf on classes created
using `@attrs.define`.

Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
  • Loading branch information
3 people committed Jan 20, 2022
1 parent 9363c34 commit e005459
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 1 deletion.
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")
)
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:
"""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

0 comments on commit e005459

Please sign in to comment.