From 276ada6760e3c49954bbad4ccd806cee7fb64c7c Mon Sep 17 00:00:00 2001 From: Tomas Novak Date: Sun, 15 Sep 2019 23:56:19 +0200 Subject: [PATCH] Allow annotated assign with attrs --- ChangeLog | 4 ++++ astroid/brain/brain_attrs.py | 10 ++++++++-- astroid/tests/unittest_brain.py | 13 +++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1ceba6e002..666b320057 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,10 @@ Release Date: TBA attributes, but rather virtual ones, thus an operation such as `getattr()` does not make sense for them. +* Update attr brain to partly understand annotated attributes + + Close #656 + What's New in astroid 2.3.0? ============================ diff --git a/astroid/brain/brain_attrs.py b/astroid/brain/brain_attrs.py index a9241281a5..670736fe42 100644 --- a/astroid/brain/brain_attrs.py +++ b/astroid/brain/brain_attrs.py @@ -37,14 +37,19 @@ def attr_attributes_transform(node): node.locals["__attrs_attrs__"] = [astroid.Unknown(parent=node)] for cdefbodynode in node.body: - if not isinstance(cdefbodynode, astroid.Assign): + if not isinstance(cdefbodynode, (astroid.Assign, astroid.AnnAssign)): continue if isinstance(cdefbodynode.value, astroid.Call): if cdefbodynode.value.func.as_string() not in ATTRIB_NAMES: continue else: continue - for target in cdefbodynode.targets: + targets = ( + cdefbodynode.targets + if hasattr(cdefbodynode, "targets") + else [cdefbodynode.target] + ) + for target in targets: rhs_node = astroid.Unknown( lineno=cdefbodynode.lineno, @@ -52,6 +57,7 @@ def attr_attributes_transform(node): parent=cdefbodynode, ) node.locals[target.name] = [rhs_node] + node.instance_attrs[target.name] = [rhs_node] MANAGER.register_transform( diff --git a/astroid/tests/unittest_brain.py b/astroid/tests/unittest_brain.py index 9b29a2808c..8aab37a854 100644 --- a/astroid/tests/unittest_brain.py +++ b/astroid/tests/unittest_brain.py @@ -1187,6 +1187,19 @@ class Foo: """ next(astroid.extract_node(code).infer()) + @test_utils.require_version(minver="3.6") + def test_attrs_with_annotation(self): + code = """ + import attr + + @attr.s + class Foo: + bar: int = attr.ib(default=5) + Foo() + """ + should_be_unknown = next(astroid.extract_node(code).infer()).getattr("bar")[0] + self.assertIsInstance(should_be_unknown, astroid.Unknown) + class RandomSampleTest(unittest.TestCase): def test_inferred_successfully(self):