diff options
| author | Sylvain Thénault <sylvain.thenault@logilab.fr> | 2007-02-16 19:21:21 +0100 |
|---|---|---|
| committer | Sylvain Thénault <sylvain.thenault@logilab.fr> | 2007-02-16 19:21:21 +0100 |
| commit | 401631ff4e15b37f763e15e9d6be8c791194bfa8 (patch) | |
| tree | b47a62f6d9b36cbf953d8755f271b9255a36456e | |
| parent | cc1226bbaf27c10870456c8366cee0ed543adf0c (diff) | |
| download | astroid-git-401631ff4e15b37f763e15e9d6be8c791194bfa8.tar.gz | |
* fix lookup of name in method bug (#3289)
* fix decorator lookup bug (#3261)
| -rw-r--r-- | ChangeLog | 3 | ||||
| -rw-r--r-- | lookup.py | 10 | ||||
| -rw-r--r-- | nodes.py | 12 | ||||
| -rw-r--r-- | test/unittest_lookup.py | 54 |
4 files changed, 67 insertions, 12 deletions
@@ -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) @@ -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) @@ -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() |
