Skip to content

Commit

Permalink
Support attrs decorators even if they are imported from attrs (#2059) (
Browse files Browse the repository at this point in the history
…#2073)

Use inference to determine membership of ``attr(s)`` module

Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
(cherry picked from commit 489c90f)

Co-authored-by: alm <alonme@users.noreply.github.com>
  • Loading branch information
Pierre-Sassoulas and alonme authored Apr 1, 2023
1 parent 1bc3e76 commit 895c6d7
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 2 deletions.
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ What's New in astroid 2.15.2?
=============================
Release date: TBA

* Support more possible usages of ``attrs`` decorators.

Closes pylint-dev/pylint#7884


What's New in astroid 2.15.1?
Expand Down
5 changes: 5 additions & 0 deletions astroid/brain/brain_attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
Without this hook pylint reports unsupported-assignment-operation
for attrs classes
"""
from astroid.helpers import safe_infer
from astroid.manager import AstroidManager
from astroid.nodes.node_classes import AnnAssign, Assign, AssignName, Call, Unknown
from astroid.nodes.scoped_nodes import ClassDef
Expand Down Expand Up @@ -40,6 +41,10 @@ def is_decorated_with_attrs(node, decorator_names=ATTRS_NAMES) -> bool:
decorator_attribute = decorator_attribute.func
if decorator_attribute.as_string() in decorator_names:
return True

inferred = safe_infer(decorator_attribute)
if inferred and inferred.root().name == "attr._next_gen":
return True
return False


Expand Down
34 changes: 32 additions & 2 deletions tests/brain/test_attr.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ def test_attrs_transform(self) -> None:
module = astroid.parse(
"""
import attrs
from attrs import field, mutable, frozen
from attrs import field, mutable, frozen, define
from attrs import mutable as my_mutable
@attrs.define
class Foo:
Expand Down Expand Up @@ -141,10 +142,39 @@ class Eggs:
l = Eggs(d=1)
l.d['answer'] = 42
@frozen
class Legs:
d = attrs.field(default=attrs.Factory(dict))
m = Legs(d=1)
m.d['answer'] = 42
@define
class FooBar:
d = attrs.field(default=attrs.Factory(dict))
n = FooBar(d=1)
n.d['answer'] = 42
@mutable
class BarFoo:
d = attrs.field(default=attrs.Factory(dict))
o = BarFoo(d=1)
o.d['answer'] = 42
@my_mutable
class FooFoo:
d = attrs.field(default=attrs.Factory(dict))
p = FooFoo(d=1)
p.d['answer'] = 42
"""
)

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

Expand Down

0 comments on commit 895c6d7

Please sign in to comment.