summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralm <alonme@users.noreply.github.com>2023-04-01 11:45:56 +0300
committerGitHub <noreply@github.com>2023-04-01 10:45:56 +0200
commit489c90fb29970d9362f21f26247bd45a39832dcd (patch)
tree64fe13af7f7babf10c8790f02b139ca19edc0b17
parent6714f15531c78d98860d8b17123d4308205aecc6 (diff)
downloadastroid-git-489c90fb29970d9362f21f26247bd45a39832dcd.tar.gz
Support attrs decorators even if they are imported from attrs (#2059)
Use inference to determine membership of ``attr(s)`` module Co-authored-by: Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>
-rw-r--r--ChangeLog3
-rw-r--r--astroid/brain/brain_attrs.py5
-rw-r--r--tests/brain/test_attr.py34
3 files changed, 40 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 0f7f1384..216553c2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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?
diff --git a/astroid/brain/brain_attrs.py b/astroid/brain/brain_attrs.py
index 80d9a252..44f9572a 100644
--- a/astroid/brain/brain_attrs.py
+++ b/astroid/brain/brain_attrs.py
@@ -8,6 +8,7 @@ Astroid hook for the attrs library
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
@@ -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
diff --git a/tests/brain/test_attr.py b/tests/brain/test_attr.py
index c0838cbe..d1ebb920 100644
--- a/tests/brain/test_attr.py
+++ b/tests/brain/test_attr.py
@@ -90,7 +90,8 @@ class AttrsTest(unittest.TestCase):
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:
@@ -141,10 +142,39 @@ class AttrsTest(unittest.TestCase):
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)