Skip to content

Commit e005459

Browse files
jacobbogdanovDanielNoordPierre-Sassoulas
authored
Add support for attrs v21.3.0+ (#1331)
* 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 <[email protected]> Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent 9363c34 commit e005459

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

astroid/brain/brain_attrs.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
from astroid.nodes.node_classes import AnnAssign, Assign, AssignName, Call, Unknown
1111
from astroid.nodes.scoped_nodes import ClassDef
1212

13-
ATTRIB_NAMES = frozenset(("attr.ib", "attrib", "attr.attrib", "attr.field", "field"))
13+
ATTRIB_NAMES = frozenset(
14+
("attr.ib", "attrib", "attr.attrib", "attr.field", "attrs.field", "field")
15+
)
1416
ATTRS_NAMES = frozenset(
1517
(
1618
"attr.s",
@@ -20,6 +22,9 @@
2022
"attr.define",
2123
"attr.mutable",
2224
"attr.frozen",
25+
"attrs.define",
26+
"attrs.mutable",
27+
"attrs.frozen",
2328
)
2429
)
2530

tests/unittest_brain.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,6 +2211,73 @@ class Eggs:
22112211
should_be_unknown = next(module.getattr(name)[0].infer()).getattr("d")[0]
22122212
self.assertIsInstance(should_be_unknown, astroid.Unknown)
22132213

2214+
def test_attrs_transform(self) -> None:
2215+
"""Test brain for decorators of the 'attrs' package.
2216+
2217+
Package added support for 'attrs' a long side 'attr' in v21.3.0.
2218+
See: https://github.com/python-attrs/attrs/releases/tag/21.3.0
2219+
"""
2220+
module = astroid.parse(
2221+
"""
2222+
import attrs
2223+
from attrs import field, mutable, frozen
2224+
2225+
@attrs.define
2226+
class Foo:
2227+
2228+
d = attrs.field(attrs.Factory(dict))
2229+
2230+
f = Foo()
2231+
f.d['answer'] = 42
2232+
2233+
@attrs.define(slots=True)
2234+
class Bar:
2235+
d = field(attrs.Factory(dict))
2236+
2237+
g = Bar()
2238+
g.d['answer'] = 42
2239+
2240+
@attrs.mutable
2241+
class Bah:
2242+
d = field(attrs.Factory(dict))
2243+
2244+
h = Bah()
2245+
h.d['answer'] = 42
2246+
2247+
@attrs.frozen
2248+
class Bai:
2249+
d = attrs.field(attrs.Factory(dict))
2250+
2251+
i = Bai()
2252+
i.d['answer'] = 42
2253+
2254+
@attrs.define
2255+
class Spam:
2256+
d = field(default=attrs.Factory(dict))
2257+
2258+
j = Spam(d=1)
2259+
j.d['answer'] = 42
2260+
2261+
@attrs.mutable
2262+
class Eggs:
2263+
d = attrs.field(default=attrs.Factory(dict))
2264+
2265+
k = Eggs(d=1)
2266+
k.d['answer'] = 42
2267+
2268+
@attrs.frozen
2269+
class Eggs:
2270+
d = attrs.field(default=attrs.Factory(dict))
2271+
2272+
l = Eggs(d=1)
2273+
l.d['answer'] = 42
2274+
"""
2275+
)
2276+
2277+
for name in ("f", "g", "h", "i", "j", "k", "l"):
2278+
should_be_unknown = next(module.getattr(name)[0].infer()).getattr("d")[0]
2279+
self.assertIsInstance(should_be_unknown, astroid.Unknown)
2280+
22142281
def test_special_attributes(self) -> None:
22152282
"""Make sure special attrs attributes exist"""
22162283

0 commit comments

Comments
 (0)