summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <cpopa@cloudbasesolutions.com>2015-02-09 14:27:40 +0200
committerClaudiu Popa <cpopa@cloudbasesolutions.com>2015-02-09 14:27:40 +0200
commit3dec19f758e25a3067ab8e1c816404448666d59a (patch)
tree36b316e5861e11c2bbe4f7550c3d4294ee3c5933
parentc4846d5ad12ba1e84c09fb97abec3b0fde3589c6 (diff)
downloadastroid-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--ChangeLog10
-rw-r--r--astroid/scoped_nodes.py16
-rw-r--r--astroid/tests/unittest_inference.py16
3 files changed, 41 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 54ecc08..5adc6a6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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()