diff options
author | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-02-09 14:27:40 +0200 |
---|---|---|
committer | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-02-09 14:27:40 +0200 |
commit | 3dec19f758e25a3067ab8e1c816404448666d59a (patch) | |
tree | 36b316e5861e11c2bbe4f7550c3d4294ee3c5933 | |
parent | c4846d5ad12ba1e84c09fb97abec3b0fde3589c6 (diff) | |
download | astroid-3dec19f758e25a3067ab8e1c816404448666d59a.tar.gz |
Improve the scope_lookup method for Classes.
This patch improves the scope lookup for Classes, regarding qualified
objects, with an attribute name exactly as one provided in the
class itself.
For example, a class containing an attribute 'first',
which was also an import and which had, as a base, a qualified name
or a Gettattr node, in the form 'module.first', then Pylint would
have inferred the `first` name as the function from the Class,
not the import. Closes Pylint issue #466.
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | astroid/scoped_nodes.py | 16 | ||||
-rw-r--r-- | astroid/tests/unittest_inference.py | 16 |
3 files changed, 41 insertions, 1 deletions
@@ -13,6 +13,16 @@ Change log for the astroid package (used to be astng) * Fix a crash which occurred when a class was the ancestor of itself. Closes issue #78. + + * Improve the scope_lookup method for Classes regarding qualified + objects, with an attribute name exactly as one provided in the + class itself. + + For example, a class containing an attribute 'first', + which was also an import and which had, as a base, a qualified name + or a Gettattr node, in the form 'module.first', then Pylint would + have inferred the `first` name as the function from the Class, + not the import. Closes Pylint issue #466. 2015-01-17 -- 1.3.4 diff --git a/astroid/scoped_nodes.py b/astroid/scoped_nodes.py index 88e4fe1..2bbd2c2 100644 --- a/astroid/scoped_nodes.py +++ b/astroid/scoped_nodes.py @@ -1036,7 +1036,21 @@ class Class(Statement, LocalsDictNodeNG, FilterStmtsMixin): yield Instance(self) def scope_lookup(self, node, name, offset=0): - if node in self.bases: + if any(node == base or base.parent_of(node) + for base in self.bases): + # Handle the case where we have either a name + # in the bases of a class, which exists before + # the actual definition or the case where we have + # a Getattr node, with that name. + # + # name = ... + # class A(name): + # def name(self): ... + # + # import name + # class A(name.Name): + # def name(self): ... + frame = self.parent.frame() # line offset to avoid that class A(A) resolve the ancestor to # the defined class diff --git a/astroid/tests/unittest_inference.py b/astroid/tests/unittest_inference.py index 84d0414..1a53b05 100644 --- a/astroid/tests/unittest_inference.py +++ b/astroid/tests/unittest_inference.py @@ -1624,5 +1624,21 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): for i in range(16, 19): self.assertInferConst(ast[i], 0) + def test_scope_lookup_same_attributes(self): + code = ''' + import collections + class Second(collections.Counter): + def collections(self): + return "second" + + ''' + ast = test_utils.build_module(code, __name__) + bases = ast['Second'].bases[0] + inferred = next(bases.infer()) + self.assertTrue(inferred) + self.assertIsInstance(inferred, nodes.Class) + self.assertEqual(inferred.qname(), 'collections.Counter') + + if __name__ == '__main__': unittest.main() |