diff options
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | astroid/brain/brain_attrs.py | 5 | ||||
-rw-r--r-- | tests/brain/test_attr.py | 34 |
3 files changed, 40 insertions, 2 deletions
@@ -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 acb069e3..7afcc8ab 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 d9a65f90..0648109e 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) |