summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Thénault <sylvain.thenault@logilab.fr>2007-02-16 19:21:21 +0100
committerSylvain Thénault <sylvain.thenault@logilab.fr>2007-02-16 19:21:21 +0100
commit401631ff4e15b37f763e15e9d6be8c791194bfa8 (patch)
treeb47a62f6d9b36cbf953d8755f271b9255a36456e
parentcc1226bbaf27c10870456c8366cee0ed543adf0c (diff)
downloadastroid-git-401631ff4e15b37f763e15e9d6be8c791194bfa8.tar.gz
* fix lookup of name in method bug (#3289)
* fix decorator lookup bug (#3261)
-rw-r--r--ChangeLog3
-rw-r--r--lookup.py10
-rw-r--r--nodes.py12
-rw-r--r--test/unittest_lookup.py54
4 files changed, 67 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index da8bca5b..d92e8c73 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,9 @@ Change log for the astng package
* api change to be able to infer using a context (used to infer function call
result only for now)
* fix a living object astng building bug, which was making "open" uninferable
+ * fix lookup of name in method bug (#3289)
+ * fix decorator lookup bug (#3261)
+
2006-11-23 -- 0.16.3
* enhance inference for the subscription notation (motivated by a patch from Amaury)
diff --git a/lookup.py b/lookup.py
index 9d490fb4..81a21027 100644
--- a/lookup.py
+++ b/lookup.py
@@ -33,7 +33,7 @@ __docformat__ = "restructuredtext en"
import __builtin__
from logilab.astng.utils import are_exclusive
-from logilab.astng import MANAGER, _infer_stmts, copy_context
+from logilab.astng import nodes, MANAGER, _infer_stmts, copy_context
def lookup(self, name):
@@ -58,7 +58,12 @@ def scope_lookup(self, node, name, offset=0):
if stmts:
return self, stmts
if self.parent:
- return self.parent.scope().scope_lookup(node, name)
+ # nested scope: if parent scope is a function, that's fine
+ # else jump to the module
+ pscope = self.parent.scope()
+ if not isinstance(pscope, nodes.Function):
+ pscope = pscope.root()
+ return pscope.scope_lookup(node, name)
return builtin_lookup(name)
def class_scope_lookup(self, node, name, offset=0):
@@ -79,6 +84,7 @@ def function_scope_lookup(self, node, name, offset=0):
# value to the defined function
offset = -1
else:
+ # check this is not used in function decorators
frame = self
return scope_lookup(frame, node, name, offset)
diff --git a/nodes.py b/nodes.py
index 782df543..43092d32 100644
--- a/nodes.py
+++ b/nodes.py
@@ -66,6 +66,13 @@ except:
class GenExprInner:
"""dummy GenExprInner node, shouldn't be used since py < 2.4"""
+try:
+ # introduced in python 2.4
+ from compiler.ast import Decorators
+except:
+ class Decorators:
+ """dummy Decorators node, shouldn't be used since py < 2.4"""
+
from logilab.astng._exceptions import NotFoundError, InferenceError
from logilab.astng.utils import extend_class
@@ -244,6 +251,11 @@ extend_class(Node, NodeNG)
Const.eq = lambda self, value: self.value == value
+def decorators_scope(self):
+ # skip the function node to go directly to the upper level scope
+ return self.parent.parent.scope()
+Decorators.scope = decorators_scope
+
# block range overrides #######################################################
def object_block_range(node, lineno):
diff --git a/test/unittest_lookup.py b/test/unittest_lookup.py
index 62cbd22f..18d903c8 100644
--- a/test/unittest_lookup.py
+++ b/test/unittest_lookup.py
@@ -11,19 +11,15 @@
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""tests for the astng variable lookup capabilities
-
-Copyright (c) 2005-2006 LOGILAB S.A. (Paris, FRANCE).
-http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
-__revision__ = "$Id: unittest_lookup.py,v 1.2 2006-03-03 09:29:50 syt Exp $"
-
from os.path import join, abspath
+from logilab.common.testlib import TestCase, unittest_main
from logilab.astng import builder, nodes, scoped_nodes, \
InferenceError, NotFoundError
-#from logilab.astng import builder, nodes, inference, utils, YES
-from logilab.common.testlib import TestCase, unittest_main
+
+from unittest_inference import get_name_node
builder = builder.ASTNGBuilder()
MODULE = builder.file_build('data/module.py', 'data.module')
@@ -65,7 +61,7 @@ def func():
none = astng.ilookup('None').next()
self.assertEquals(none.value, None)
obj = astng.ilookup('object').next()
- self.assert_(isinstance(obj, nodes.Class))
+ self.assertIsInstance(obj, nodes.Class)
self.assertEquals(obj.name, 'object')
self.assertRaises(InferenceError, astng.ilookup('YOAA').next)
@@ -106,11 +102,11 @@ class A(A):
klass = MODULE['YOUPI']
#print klass.getattr('MY_DICT')
my_dict = klass.ilookup('MY_DICT').next()
- self.assert_(isinstance(my_dict, nodes.Dict))
+ self.assertIsInstance(my_dict, nodes.Dict)
none = klass.ilookup('None').next()
self.assertEquals(none.value, None)
obj = klass.ilookup('object').next()
- self.assert_(isinstance(obj, nodes.Class))
+ self.assertIsInstance(obj, nodes.Class)
self.assertEquals(obj.name, 'object')
self.assertRaises(InferenceError, klass.ilookup('YOAA').next)
@@ -118,5 +114,43 @@ class A(A):
ccc = NONREGR['Ccc']
self.assertEquals(ccc.ilookup('Ddd').next().name, 'Ddd')
+ def test_nonregr_method_lookup(self):
+ data = '''
+class FileA:
+ @staticmethod
+ def funcA():
+ return 4
+
+
+class Test:
+ FileA = [1,2,3]
+
+ def __init__(self):
+ print FileA.funcA()
+ '''
+ astng = builder.string_build(data, __name__, __file__)
+ it = astng['Test']['__init__'].ilookup('FileA')
+ obj = it.next()
+ self.assertIsInstance(obj, nodes.Class)
+ self.assertRaises(StopIteration, it.next)
+
+ def test_nonregr_decorator_member_lookup(self):
+ data = '''
+class FileA:
+ def decorator(bla):
+ return bla
+
+ @decorator
+ def funcA():
+ return 4
+ '''
+ astng = builder.string_build(data, __name__, __file__)
+ decname = get_name_node(astng['FileA'], 'decorator')
+ it = decname.infer()
+ obj = it.next()
+ self.assertIsInstance(obj, nodes.Function)
+ self.assertRaises(StopIteration, it.next)
+
+
if __name__ == '__main__':
unittest_main()