diff options
-rw-r--r-- | __init__.py | 89 | ||||
-rw-r--r-- | __pkginfo__.py | 2 | ||||
-rw-r--r-- | _nodes_ast.py | 194 | ||||
-rw-r--r-- | _nodes_compiler.py | 161 | ||||
-rw-r--r-- | inference.py | 28 | ||||
-rw-r--r-- | infutils.py | 282 | ||||
-rw-r--r-- | lookup.py | 31 | ||||
-rw-r--r-- | manager.py | 4 | ||||
-rw-r--r-- | nodes.py | 197 | ||||
-rw-r--r-- | nodes_as_string.py | 10 | ||||
-rw-r--r-- | protocols.py | 40 | ||||
-rw-r--r-- | rebuilder.py | 23 | ||||
-rw-r--r-- | scoped_nodes.py | 12 | ||||
-rw-r--r-- | test/unittest_builder.py | 8 | ||||
-rw-r--r-- | test/unittest_inference.py | 38 | ||||
-rw-r--r-- | test/unittest_inspector.py | 14 | ||||
-rw-r--r-- | test/unittest_scoped_nodes.py | 4 |
17 files changed, 573 insertions, 564 deletions
diff --git a/__init__.py b/__init__.py index 603c5555..46f7a194 100644 --- a/__init__.py +++ b/__init__.py @@ -41,96 +41,21 @@ Main modules are: :copyright: 2003-2009 Sylvain Thenault :contact: mailto:thenault@gmail.com """ - -from __future__ import generators - __doctype__ = "restructuredtext en" -from logilab.common.compat import chain, imap - # WARNING: internal imports order matters ! +# make all exception classes accessible from astng package from logilab.astng._exceptions import * - - -def unpack_infer(stmt, context=None): - """return an iterator on nodes infered by the given statement if the infered - value is a list or a tuple, recurse on it to get values infered by its - content - """ - if isinstance(stmt, (List, Tuple)): - # XXX loosing context - return chain(*imap(unpack_infer, stmt.elts)) - infered = stmt.infer(context).next() - if infered is stmt: - return iter( (stmt,) ) - return chain(*imap(unpack_infer, stmt.infer(context))) - -def copy_context(context): - if context is not None: - return context.clone() - else: - return InferenceContext() - -# decorators ################################################################## - -def path_wrapper(func): - """return the given infer function wrapped to handle the path""" - def wrapped(node, context=None, _func=func, **kwargs): - """wrapper function handling context""" - if context is None: - context = InferenceContext(node) - context.push(node) - yielded = [] - try: - for res in _func(node, context, **kwargs): - # unproxy only true instance, not const, tuple, dict... - if res.__class__ is Instance: - ares = res._proxied - else: - ares = res - if not ares in yielded: - yield res - yielded.append(ares) - context.pop() - except: - context.pop() - raise - return wrapped - -def yes_if_nothing_infered(func): - def wrapper(*args, **kwargs): - infered = False - for node in func(*args, **kwargs): - infered = True - yield node - if not infered: - yield YES - return wrapper - -def raise_if_nothing_infered(func): - def wrapper(*args, **kwargs): - infered = False - for node in func(*args, **kwargs): - infered = True - yield node - if not infered: - raise InferenceError() - return wrapper - - -# imports ##################################################################### - -from logilab.common.decorators import classproperty - +# make a manager singleton as well as Project and Package classes accessible +# from astng package from logilab.astng.manager import ASTNGManager, Project, Package MANAGER = ASTNGManager() +del ASTNGManager +# make all node classes accessible from astng package from logilab.astng.nodes import * -from logilab.astng.scoped_nodes import * - -from logilab.astng import lookup -lookup._decorate(nodes) -from logilab.astng import inference +# trigger extra monkey-patching +from logilab.astng import scoped_nodes, lookup, inference diff --git a/__pkginfo__.py b/__pkginfo__.py index da942f27..22522094 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -47,7 +47,7 @@ them astng ;) by visiting an existant ast tree or by inspecting living object. Methods are added by monkey patching ast classes.""" -web = "http://www.logilab.org/project/name/%s" % distname +web = "http://www.logilab.org/project/%s" % distname ftp = "ftp://ftp.logilab.org/pub/%s" % modname mailinglist = "mailto://python-projects@lists.logilab.org" diff --git a/_nodes_ast.py b/_nodes_ast.py index ed2afd9c..a8a4aaed 100644 --- a/_nodes_ast.py +++ b/_nodes_ast.py @@ -21,8 +21,9 @@ __docformat__ = "restructuredtext en" +# "as is" nodes from _ast import (Assert, Assign, AugAssign, - Break, + BinOp, BoolOp, Break, Compare, Continue, Delete, Dict, Ellipsis, Exec, @@ -36,31 +37,49 @@ from _ast import (Assert, Assign, AugAssign, Raise, Return, Slice, Sub, Subscript, TryExcept, TryFinally, Tuple, + UnaryOp, While, With, Yield, - ) - + ) +# aliased nodes from _ast import (AST as Node, Attribute as Getattr, Call as CallFunc, ClassDef as Class, + Expr as Discard, FunctionDef as Function, GeneratorExp as GenExpr, - Repr as Backquote, - - Expr as Discard, ImportFrom as From, - excepthandler as ExceptHandler, + Repr as Backquote, + arguments as Arguments, comprehension as Comprehension, - keyword as Keyword + keyword as Keyword, + excepthandler as ExceptHandler, ) +# nodes which are not part of astng +from _ast import ( + # binary operators + Add as _Add, Div as _Div, FloorDiv as _FloorDiv, + Mod as _Mod, Mult as _Mult, Pow as _Pow, Sub as _Sub, + BitAnd as _BitAnd, BitOr as _BitOr, BitXor as _BitXor, + LShift as _LShift, RShift as _RShift, + # logical operators + And as _And, Or as _Or, + # unary operators + UAdd as _UAdd, USub as _USub, Not as _Not, Invert as _Invert, + # comparison operators + Eq as _Eq, Gt as _Gt, GtE as _GtE, In as _In, Is as _Is, + IsNot as _IsNot, Lt as _Lt, LtE as _LtE, NotEq as _NotEq, + NotIn as _NotIn , + # other nodes which are not part of astng + Str as _Str, Load as _Load, Store as _Store, Del as _Del, + ) + +from logilab.astng.utils import ASTVisitor + -from _ast import Num, Str, Eq, alias, arguments as Arguments +Proxy_ = object -from _ast import (Add as _Add, Div as _Div, FloorDiv as _FloorDiv, - Mod as _Mod, Mult as _Mult, Pow as _Pow, Sub as _Sub, - BitAnd as _BitAnd, BitOr as _BitOr, BitXor as _BitXor, - LShift as _LShift, RShift as _RShift) BIN_OP_CLASSES = {_Add: '+', _BitAnd: '&', _BitOr: '|', @@ -74,22 +93,14 @@ BIN_OP_CLASSES = {_Add: '+', _LShift: '<<', _RShift: '>>'} - -from _ast import And as _And, Or as _Or BOOL_OP_CLASSES = {_And: 'and', _Or: 'or'} -from _ast import UAdd as _UAdd, USub as _USub, Not as _Not, Invert as _Invert UNARY_OP_CLASSES = {_UAdd: '+', _USub: '-', _Not: 'not', _Invert: '~'} -from _ast import BinOp, BoolOp, UnaryOp - -from _ast import (Eq as _Eq, Gt as _Gt, GtE as _GtE, In as _In, Is as _Is, - IsNot as _IsNot, Lt as _Lt, LtE as _LtE, NotEq as _NotEq, - NotIn as _NotIn) CMP_OP_CLASSES = {_Eq: '==', _Gt: '>', _GtE: '>=', @@ -102,8 +113,57 @@ CMP_OP_CLASSES = {_Eq: '==', _NotIn: 'not in', } -from logilab.astng.utils import ASTVisitor +def _init_set_doc(node): + node.doc = None + try: + if isinstance(node.body[0], Discard) and isinstance(node.body[0].value, _Str): + node.tolineno = node.body[0].lineno + node.doc = node.body[0].value.s + node.body = node.body[1:] + except IndexError: + pass # ast built from scratch + + +def native_repr_tree(node, indent='', _done=None): + if _done is None: + _done = set() + if node in _done: + print ('loop in tree: %r (%s)' % (node, getattr(node, 'lineno', None))) + return + _done.add(node) + print indent + str(node) + if type(node) is str: # XXX crash on Globals + return + indent += ' ' + d = node.__dict__ + if hasattr(node, '_attributes'): + for a in node._attributes: + attr = d[a] + if attr is None: + continue + print indent + a, repr(attr) + for f in node._fields or (): + attr = d[f] + if attr is None: + continue + if type(attr) is list: + if not attr: continue + print indent + f + ' [' + for elt in attr: + native_repr_tree(elt, indent, _done) + print indent + ']' + continue + if isinstance(attr, (_Load, _Store, _Del)): + continue + if isinstance(attr, Node): + print indent + f + native_repr_tree(attr, indent, _done) + else: + print indent + f, repr(attr) + + +# some astng nodes unexistant in _ast ######################################### class AssAttr(Node): """represent Attribute Assignment statements""" @@ -131,36 +191,11 @@ class Decorators(Node): def __init__(self, nodes): self.nodes = nodes -## some auxiliary functions ########################## - -def _recurse_if(ifnode, tests, orelse): - """recurse on nested If nodes""" - tests.append( (ifnode.test, ifnode.body) ) - del ifnode.test, ifnode.body - if ifnode.orelse: - if isinstance( ifnode.orelse[0], If): - tests, orelse = _recurse_if(ifnode.orelse[0], tests, orelse) - del ifnode.orelse[0] - else: - orelse = ifnode.orelse - return tests, orelse - -def _init_set_doc(node): - node.doc = None - try: - if isinstance(node.body[0], Discard) and isinstance(node.body[0].value, Str): - node.tolineno = node.body[0].lineno - node.doc = node.body[0].value.s - node.body = node.body[1:] - except IndexError: - pass # ast built from scratch - +# _ast rebuilder ############################################################## class TreeRebuilder(ASTVisitor): """REbuilds the _ast tree to become an ASTNG tree""" - # # visit_<node> methods # # ########################################## - def __init__(self, rebuild_visitor): self.visitor = rebuild_visitor @@ -192,7 +227,6 @@ class TreeRebuilder(ASTVisitor): def visit_exec(self, node): node.expr = node.body - node.globals, node.locals = node.locals, node.globals # XXX ? del node.body def visit_function(self, node): @@ -270,25 +304,16 @@ class TreeRebuilder(ASTVisitor): node.parent.parent.replace(parent, node) del parent + # raw building ################################################################ -def _add_docstring(node, doc): - node.doc = doc -# if doc: -# expr = Expr() -# node.body.append(expr) -# expr.parent = None -# docstr = Str() -# docstr.s = doc -# expr.value = docstr -# docstr.parent = expr - def module_factory(doc): node = Module() node.body = [] - _add_docstring(node, doc) + node.doc = doc return node + def import_from_factory(modname, membername): node = From() node.level = 0 @@ -296,6 +321,7 @@ def import_from_factory(modname, membername): node.names = [(membername, None)] return node + def _const_factory(value): if isinstance(value, (int, long, complex, float, basestring)): node = Const() @@ -303,6 +329,7 @@ def _const_factory(value): raise Exception(type(value)) node.value = value return node + def function_factory(name, args, defaults, flag=0, doc=None): """create and initialize a astng Function node""" @@ -324,7 +351,7 @@ def function_factory(name, args, defaults, flag=0, doc=None): argsnode.kwarg = None argsnode.vararg = None argsnode.parent = node - _add_docstring(node, doc) + node.doc = doc return node @@ -340,46 +367,5 @@ def class_factory(name, basenames=(), doc=None): basenode.name = base node.bases.append(basenode) basenode.parent = node - _add_docstring(node, doc) + node.doc = doc return node - -class Proxy_(object): pass - - -from _ast import Load as _Load, Store as _Store, Del as _Del -def native_repr_tree(node, indent='', _done=None): - if _done is None: - _done = set() - if node in _done: - print ('loop in tree: %r (%s)' % (node, getattr(node, 'lineno', None))) - return - _done.add(node) - print indent + str(node) - if type(node) is str: # XXX crash on Globals - return - indent += ' ' - d = node.__dict__ - if hasattr(node, '_attributes'): - for a in node._attributes: - attr = d[a] - if attr is None: - continue - print indent + a, repr(attr) - for f in node._fields or (): - attr = d[f] - if attr is None: - continue - if type(attr) is list: - if not attr: continue - print indent + f + ' [' - for elt in attr: - native_repr_tree(elt, indent, _done) - print indent + ']' - continue - if isinstance(attr, (_Load, _Store, _Del)): - continue - if isinstance(attr, Node): - print indent + f - native_repr_tree(attr, indent, _done) - else: - print indent + f, repr(attr) diff --git a/_nodes_compiler.py b/_nodes_compiler.py index d397fd0e..283db2ef 100644 --- a/_nodes_compiler.py +++ b/_nodes_compiler.py @@ -16,16 +16,16 @@ [1] http://docs.python.org/lib/module-compiler.ast.html :author: Sylvain Thenault -:copyright: 2008-2009 LOGILAB S.A. (Paris, FRANCE) +:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE) :contact: http://www.logilab.fr/ -- mailto:python-projects@logilab.org -:copyright: 2008-2009 Sylvain Thenault +:copyright: 2003-2009 Sylvain Thenault :contact: mailto:thenault@gmail.com """ -from __future__ import generators __docformat__ = "restructuredtext en" import sys +from compiler import ast from compiler.ast import AssAttr, AssList, AssName, \ AssTuple, Assert, Assign, AugAssign, \ Backquote, Break, CallFunc, Class, \ @@ -38,34 +38,6 @@ from compiler.ast import AssAttr, AssList, AssName, \ Sliceobj, Stmt, Subscript, TryExcept, TryFinally, Tuple, \ While, Yield -# modify __repr__ of all Nodes as they are not compatible with ASTNG - -def generic__repr__(self): - """simple representation method to override compiler.ast's methods""" - return "<%s at 0x%x>" % (self.__class__.__name__, id(self)) - -from compiler import ast -for name, value in ast.__dict__.items(): - try: - if issubclass(value, ast.Node): - value.__repr__ = generic__repr__ - except: - pass -del ast - -def init_noargs(self, *args, **kwargs): - if not (args or kwargs): - self._orig_init([]) - else: - self._orig_init(*args, **kwargs) -# we have to be able to instantiate Tuple, Dict and List without any argument -Tuple._orig_init = Tuple.__init__ -Tuple.__init__ = init_noargs -List._orig_init = List.__init__ -List.__init__ = init_noargs -Dict._orig_init = Dict.__init__ -Dict.__init__ = init_noargs - try: # introduced in python 2.4 from compiler.ast import GenExpr, GenExprIf, GenExprInner @@ -90,7 +62,50 @@ class With: but we need it for the other astng modules """ -# additional nodes +# introduced in python 2.5 +From.level = 0 # will be overiden by instance attribute with py>=2.5 + + +from logilab.astng.utils import ASTVisitor +from logilab.astng._exceptions import NodeRemoved + +class Proxy_: pass + + +def native_repr_tree(node, indent='', _done=None): + """enhanced compiler.ast tree representation""" + if _done is None: + _done = set() + if node in _done: + print ('loop in tree: %r (%s)' % (node, getattr(node, 'lineno', None))) + return + _done.add(node) + print indent + "<%s>" % node.__class__ + indent += ' ' + if not hasattr(node, "__dict__"): # XXX + return + for field, attr in node.__dict__.items(): + if attr is None or field == "_proxied": + continue + if type(attr) is list: + if not attr: continue + print indent + field + ' [' + for elt in attr: + if type(elt) is tuple: + for val in elt: + native_repr_tree(val, indent, _done) + else: + native_repr_tree(elt, indent, _done) + print indent + ']' + continue + if isinstance(attr, Node): + print indent + field + native_repr_tree(attr, indent, _done) + else: + print indent + field, repr(attr) + + +# some astng nodes unexistant in compiler ##################################### class ExceptHandler(Node): def __init__(self, exc_type, name, body, parent): @@ -105,6 +120,7 @@ class ExceptHandler(Node): self.fromlineno = self.lineno self.tolineno = self.body[-1].tolineno + class BinOp(Node): """replace Add, Div, FloorDiv, Mod, Mul, Power, Sub nodes""" from compiler.ast import Add, Div, FloorDiv, Mod, Mul, Power, Sub @@ -123,6 +139,7 @@ class BinOp(Node): RightShift: '>>'} BIT_CLASSES = {'&': Bitand, '|': Bitor, '^': Bitxor} + class BoolOp(Node): """replace And, Or""" from compiler.ast import And, Or @@ -138,8 +155,6 @@ class UnaryOp(Node): Invert: '~'} -from logilab.astng.utils import ASTVisitor - class Delete(Node): """represent del statements""" @@ -156,18 +171,37 @@ class Arguments(Node): self.vararg = vararg self.kwarg = kwarg -############################################################################### - +# modify __repr__ of all Nodes as they are not compatible with ASTNG ########## +def generic__repr__(self): + """simple representation method to override compiler.ast's methods""" + return "<%s at 0x%x>" % (self.__class__.__name__, id(self)) -Const.eq = lambda self, value: self.value == value +for name, value in ast.__dict__.items(): + try: + if issubclass(value, ast.Node): + value.__repr__ = generic__repr__ + except: + pass +del ast -# introduced in python 2.5 -From.level = 0 # will be overiden by instance attribute with py>=2.5 +# we have to be able to instantiate Tuple, Dict and List without any argument # +def init_noargs(self, *args, **kwargs): + if not (args or kwargs): + self._orig_init([]) + else: + self._orig_init(*args, **kwargs) -## some auxiliary functions ########################## +Tuple._orig_init = Tuple.__init__ +Tuple.__init__ = init_noargs +List._orig_init = List.__init__ +List.__init__ = init_noargs +Dict._orig_init = Dict.__init__ +Dict.__init__ = init_noargs + +# compiler rebuilder ########################################################## def _init_else_node(node): """remove Stmt node if exists""" @@ -210,8 +244,6 @@ def args_compiler_to_ast(node): del node.defaults -from logilab.astng._exceptions import NodeRemoved - class TreeRebuilder(ASTVisitor): """Rebuilds the compiler tree to become an ASTNG tree""" @@ -338,7 +370,10 @@ class TreeRebuilder(ASTVisitor): # dummy Const(None) introducted when statement is ended by a semi-colon node.parent.child_sequence(node).remove(node) raise NodeRemoved - + + def visit_exec(self, node): + node.locals, node.globals = node.globals, node.locals + def visit_for(self, node): node.target = node.assign del node.assign @@ -467,6 +502,7 @@ class TreeRebuilder(ASTVisitor): node.body = node.body.nodes _init_else_node(node) + # raw building ################################################################ def module_factory(doc): @@ -475,6 +511,7 @@ def module_factory(doc): node.body = [] return node + if sys.version_info < (2, 5): def import_from_factory(modname, membername): return From(modname, ( (membername, None), ) ) @@ -482,9 +519,11 @@ else: def import_from_factory(modname, membername): return From(modname, ( (membername, None), ), 0) + def _const_factory(value): return Const(value) + # introduction of decorators has changed the Function initializer arguments if sys.version_info >= (2, 4): def function_factory(name, args, defaults, flag=0, doc=None): @@ -505,6 +544,7 @@ else: args_compiler_to_ast(func) return func + def class_factory(name, basenames=(), doc=None): """create and initialize a astng Class node""" node = Class(name, [], doc, None) @@ -515,38 +555,3 @@ def class_factory(name, basenames=(), doc=None): base.parent = node node.bases = bases return node - -class Proxy_: pass - - -def native_repr_tree(node, indent='', _done=None): - """enhanced compiler.ast tree representation""" - if _done is None: - _done = set() - if node in _done: - print ('loop in tree: %r (%s)' % (node, getattr(node, 'lineno', None))) - return - _done.add(node) - print indent + "<%s>" % node.__class__ - indent += ' ' - if not hasattr(node, "__dict__"): # XXX - return - for field, attr in node.__dict__.items(): - if attr is None or field == "_proxied": - continue - if type(attr) is list: - if not attr: continue - print indent + field + ' [' - for elt in attr: - if type(elt) is tuple: - for val in elt: - native_repr_tree(val, indent, _done) - else: - native_repr_tree(elt, indent, _done) - print indent + ']' - continue - if isinstance(attr, Node): - print indent + field - native_repr_tree(attr, indent, _done) - else: - print indent + field, repr(attr) diff --git a/inference.py b/inference.py index c849a801..2a725702 100644 --- a/inference.py +++ b/inference.py @@ -24,20 +24,18 @@ from __future__ import generators __doctype__ = "restructuredtext en" from copy import copy -from types import NoneType from logilab.common.compat import imap, chain, set -from logilab.astng import nodes, raw_building, MANAGER, \ - unpack_infer, copy_context, path_wrapper, raise_if_nothing_infered +from logilab.astng import MANAGER, nodes, raw_building from logilab.astng import ASTNGError, InferenceError, UnresolvableName, \ NoDefault, NotFoundError, ASTNGBuildingException -from logilab.astng.nodes import _infer_stmts, YES, InferenceContext, Instance, \ - Generator +from logilab.astng.infutils import YES, Instance, Generator, InferenceContext, \ + _infer_stmts, unpack_infer, copy_context, path_wrapper, raise_if_nothing_infered from logilab.astng.protocols import _arguments_infer_argname _CONST_PROXY = { - NoneType: raw_building.build_class('NoneType'), + type(None): raw_building.build_class('NoneType'), bool: MANAGER.astng_from_class(bool), int: MANAGER.astng_from_class(int), long: MANAGER.astng_from_class(long), @@ -46,7 +44,7 @@ _CONST_PROXY = { str: MANAGER.astng_from_class(str), unicode: MANAGER.astng_from_class(unicode), } -_CONST_PROXY[NoneType].parent = _CONST_PROXY[bool].parent +_CONST_PROXY[type(None)].parent = _CONST_PROXY[bool].parent def _set_proxied(const): if not hasattr(const, '__proxied'): @@ -239,6 +237,12 @@ def infer_import(self, context=None, asname=True): yield _imported_module_astng(self, name) nodes.Import.infer = path_wrapper(infer_import) +def infer_name_module(node, name): + context = InferenceContext(node) + context.lookupname = name + return node.infer(context, asname=False) +nodes.Import.infer_name_module = infer_name_module + def infer_from(self, context=None, asname=True): """infer a From nodes: return the imported module/object""" @@ -259,7 +263,6 @@ nodes.From.infer = path_wrapper(infer_from) def infer_getattr(self, context=None): """infer a Getattr node by using getattr on the associated object""" - # XXX #context = context.clone() for owner in self.expr.infer(context): if owner is YES: @@ -271,10 +274,10 @@ def infer_getattr(self, context=None): yield obj context.boundnode = None except (NotFoundError, InferenceError): - continue + context.boundnode = None except AttributeError: # XXX method / function - continue + context.boundnode = None nodes.Getattr.infer = path_wrapper(raise_if_nothing_infered(infer_getattr)) @@ -289,8 +292,7 @@ nodes.Global.infer = path_wrapper(infer_global) def infer_subscript(self, context=None): - """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1] - """ + """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]""" if len(self.subs) == 1: index = self.subs[0].infer(context).next() if index is YES: @@ -398,7 +400,7 @@ def infer_ass(self, context=None): assign node """ stmts = list(self.assigned_stmts(context=context)) - return nodes._infer_stmts(stmts, context) + return _infer_stmts(stmts, context) nodes.AssName.infer = path_wrapper(infer_ass) nodes.AssAttr.infer = path_wrapper(infer_ass) # no infer method on DelName and DelAttr (expected InferenceError) diff --git a/infutils.py b/infutils.py new file mode 100644 index 00000000..365df00c --- /dev/null +++ b/infutils.py @@ -0,0 +1,282 @@ +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +"""Inference utilities + +:author: Sylvain Thenault +:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE) +:contact: http://www.logilab.fr/ -- mailto:python-projects@logilab.org +:copyright: 2003-2009 Sylvain Thenault +:contact: mailto:thenault@gmail.com +""" +from __future__ import generators + +__doctype__ = "restructuredtext en" + +from logilab.common.compat import chain, imap + +from logilab.astng._exceptions import InferenceError, NotFoundError, UnresolvableName +from logilab.astng.nodes import Proxy_, List, Tuple, Function + +class Proxy(Proxy_): + """a simple proxy object""" + _proxied = None + + def __init__(self, proxied=None): + if proxied is not None: + self._proxied = proxied + + def __getattr__(self, name): + if name == '_proxied': + return getattr(self.__class__, '_proxied') + if name in self.__dict__: + return self.__dict__[name] + return getattr(self._proxied, name) + + def infer(self, context=None): + yield self + + +class InferenceContext(object): + __slots__ = ('startingfrom', 'path', 'lookupname', 'callcontext', 'boundnode') + + def __init__(self, node=None, path=None): + self.startingfrom = node # XXX useful ? + if path is None: + self.path = [] + else: + self.path = path + self.lookupname = None + self.callcontext = None + self.boundnode = None + + def push(self, node): + name = self.lookupname + if (node, name) in self.path: + raise StopIteration() + self.path.append( (node, name) ) + + def pop(self): + return self.path.pop() + + def clone(self): + # XXX copy lookupname/callcontext ? + clone = InferenceContext(self.startingfrom, self.path) + clone.callcontext = self.callcontext + clone.boundnode = self.boundnode + return clone + + +def unpack_infer(stmt, context=None): + """return an iterator on nodes infered by the given statement if the infered + value is a list or a tuple, recurse on it to get values infered by its + content + """ + if isinstance(stmt, (List, Tuple)): + # XXX loosing context + return chain(*imap(unpack_infer, stmt.elts)) + infered = stmt.infer(context).next() + if infered is stmt: + return iter( (stmt,) ) + return chain(*imap(unpack_infer, stmt.infer(context))) + +def copy_context(context): + if context is not None: + return context.clone() + else: + return InferenceContext() + +def _infer_stmts(stmts, context, frame=None): + """return an iterator on statements infered by each statement in <stmts> + """ + stmt = None + infered = False + if context is not None: + name = context.lookupname + context = context.clone() + else: + name = None + context = InferenceContext() + for stmt in stmts: + if stmt is YES: + yield stmt + infered = True + continue + context.lookupname = stmt._infer_name(frame, name) + try: + for infered in stmt.infer(context): + yield infered + infered = True + except UnresolvableName: + continue + except InferenceError: + yield YES + infered = True + if not infered: + raise InferenceError(str(stmt)) + +class _Yes(object): + """a yes object""" + def __repr__(self): + return 'YES' + def __getattribute__(self, name): + return self + def __call__(self, *args, **kwargs): + return self + + +# decorators ################################################################## + +def path_wrapper(func): + """return the given infer function wrapped to handle the path""" + def wrapped(node, context=None, _func=func, **kwargs): + """wrapper function handling context""" + if context is None: + context = InferenceContext(node) + context.push(node) + yielded = [] + try: + for res in _func(node, context, **kwargs): + # unproxy only true instance, not const, tuple, dict... + if res.__class__ is Instance: + ares = res._proxied + else: + ares = res + if not ares in yielded: + yield res + yielded.append(ares) + context.pop() + except: + context.pop() + raise + return wrapped + +def yes_if_nothing_infered(func): + def wrapper(*args, **kwargs): + infered = False + for node in func(*args, **kwargs): + infered = True + yield node + if not infered: + yield YES + return wrapper + +def raise_if_nothing_infered(func): + def wrapper(*args, **kwargs): + infered = False + for node in func(*args, **kwargs): + infered = True + yield node + if not infered: + raise InferenceError() + return wrapper + + +# special inference objects (e.g. may be returned as nodes by .infer()) ####### + +YES = _Yes() +del _Yes + + +class Instance(Proxy): + """a special node representing a class instance""" + def getattr(self, name, context=None, lookupclass=True): + try: + return self._proxied.instance_attr(name, context) + except NotFoundError: + if name == '__class__': + return [self._proxied] + if name == '__name__': + # access to __name__ gives undefined member on class + # instances but not on class objects + raise NotFoundError(name) + if lookupclass: + return self._proxied.getattr(name, context) + raise NotFoundError(name) + + def igetattr(self, name, context=None): + """infered getattr""" + try: + # XXX frame should be self._proxied, or not ? + return _infer_stmts( + self._wrap_attr(self.getattr(name, context, lookupclass=False)), + context, frame=self) + except NotFoundError: + try: + # fallback to class'igetattr since it has some logic to handle + # descriptors + return self._wrap_attr(self._proxied.igetattr(name, context)) + except NotFoundError: + raise InferenceError(name) + + def _wrap_attr(self, attrs): + """wrap bound methods of attrs in a InstanceMethod proxies""" + # Guess which attrs are used in inference. + def wrap(attr): + if isinstance(attr, Function) and attr.type == 'method': + return InstanceMethod(attr) + else: + return attr + return imap(wrap, attrs) + + def infer_call_result(self, caller, context=None): + """infer what's a class instance is returning when called""" + infered = False + for node in self._proxied.igetattr('__call__', context): + for res in node.infer_call_result(caller, context): + infered = True + yield res + if not infered: + raise InferenceError() + + def __repr__(self): + return '<Instance of %s.%s at 0x%s>' % (self._proxied.root().name, + self._proxied.name, + id(self)) + def __str__(self): + return 'Instance of %s.%s' % (self._proxied.root().name, + self._proxied.name) + + def callable(self): + try: + self._proxied.getattr('__call__') + return True + except NotFoundError: + return False + + def pytype(self): + return self._proxied.qname() + + +class InstanceMethod(Proxy): + """a special node representing a function bound to an instance""" + def __repr__(self): + instance = self._proxied.parent.frame() + return '<Bound method %s of %s.%s at 0x%s' % (self._proxied.name, + instance.root().name, + instance.name, + id(self)) + __str__ = __repr__ + + def is_bound(self): + return True + + +class Generator(Proxy): + """a special node representing a generator""" + def callable(self): + return True + + def pytype(self): + return '__builtin__.generator' + + @@ -26,14 +26,13 @@ ilookup returns an iterator on infered values. :contact: mailto:thenault@gmail.com """ -from __future__ import generators - __docformat__ = "restructuredtext en" import __builtin__ -from logilab.astng import nodes, MANAGER, copy_context +from logilab.astng import MANAGER, nodes from logilab.astng.utils import are_exclusive +from logilab.astng.infutils import copy_context, _infer_stmts def decorators_scope(self): @@ -115,7 +114,7 @@ def ilookup(self, name, context=None): frame, stmts = self.lookup(name) context = copy_context(context) context.lookupname = name - return nodes._infer_stmts(stmts, context, frame) + return _infer_stmts(stmts, context, frame) def _filter_stmts(self, stmts, frame, offset): @@ -223,17 +222,15 @@ def _filter_stmts(self, stmts, frame, offset): return _stmts -def _decorate(astmodule): - """add this module functionalities to necessary nodes""" - for klass in (astmodule.Name, astmodule.AssName, astmodule.DelName, - astmodule.Module, astmodule.Class, - astmodule.Function, astmodule.Lambda): - klass.ilookup = ilookup - klass.lookup = lookup - klass._filter_stmts = _filter_stmts - astmodule.Class.scope_lookup = class_scope_lookup - astmodule.Function.scope_lookup = function_scope_lookup - astmodule.Lambda.scope_lookup = function_scope_lookup - astmodule.Module.scope_lookup = scope_lookup - astmodule.GenExpr.scope_lookup = scope_lookup +for klass in (nodes.Name, nodes.AssName, nodes.DelName, + nodes.Module, nodes.Class, + nodes.Function, nodes.Lambda): + klass.ilookup = ilookup + klass.lookup = lookup + klass._filter_stmts = _filter_stmts +nodes.Class.scope_lookup = class_scope_lookup +nodes.Function.scope_lookup = function_scope_lookup +nodes.Lambda.scope_lookup = function_scope_lookup +nodes.Module.scope_lookup = scope_lookup +nodes.GenExpr.scope_lookup = scope_lookup @@ -33,7 +33,7 @@ from logilab.common.modutils import NoSourceFile, is_python_source, \ get_module_files, get_source_file from logilab.common.configuration import OptionsProviderMixIn -from logilab.astng import ASTNGBuildingException, nodes +from logilab.astng import ASTNGBuildingException, nodes, infutils def astng_wrapper(func, modname): """wrapper to give to ASTNGManager.project_from_files""" @@ -220,7 +220,7 @@ class ASTNGManager(OptionsProviderMixIn): modastng = self.astng_from_module_name(modname) for infered in modastng.igetattr(name, context): if klass is not obj and isinstance(infered, nodes.Class): - infered = nodes.Instance(infered) + infered = infutils.Instance(infered) yield infered def project_from_files(self, files, func_wrapper=astng_wrapper, @@ -475,206 +475,9 @@ def real_name(node, asname): if asname == _asname: return name raise NotFoundError(asname) - From.real_name = real_name Import.real_name = real_name -def infer_name_module(node, name): - context = InferenceContext(node) - context.lookupname = name - return node.infer(context, asname=False) -Import.infer_name_module = infer_name_module - - -# special inference objects ################################################### - -class Yes(object): - """a yes object""" - def __repr__(self): - return 'YES' - def __getattribute__(self, name): - return self - def __call__(self, *args, **kwargs): - return self - -YES = Yes() - -class Proxy(Proxy_): - """a simple proxy object""" - _proxied = None - - def __init__(self, proxied=None): - if proxied is not None: - self._proxied = proxied - - def __getattr__(self, name): - if name == '_proxied': - return getattr(self.__class__, '_proxied') - if name in self.__dict__: - return self.__dict__[name] - return getattr(self._proxied, name) - - def infer(self, context=None): - yield self - - -class InstanceMethod(Proxy): - """a special node representing a function bound to an instance""" - def __repr__(self): - instance = self._proxied.parent.frame() - return '<Bound method %s of %s.%s at 0x%s' % (self._proxied.name, - instance.root().name, - instance.name, - id(self)) - __str__ = __repr__ - - def is_bound(self): - return True - - -class Instance(Proxy): - """a special node representing a class instance""" - def getattr(self, name, context=None, lookupclass=True): - try: - return self._proxied.instance_attr(name, context) - except NotFoundError: - if name == '__class__': - return [self._proxied] - if name == '__name__': - # access to __name__ gives undefined member on class - # instances but not on class objects - raise NotFoundError(name) - if lookupclass: - return self._proxied.getattr(name, context) - raise NotFoundError(name) - - def igetattr(self, name, context=None): - """infered getattr""" - try: - # XXX frame should be self._proxied, or not ? - return _infer_stmts( - self._wrap_attr(self.getattr(name, context, lookupclass=False)), - context, frame=self) - except NotFoundError: - try: - # fallback to class'igetattr since it has some logic to handle - # descriptors - return self._wrap_attr(self._proxied.igetattr(name, context)) - except NotFoundError: - raise InferenceError(name) - - def _wrap_attr(self, attrs): - """wrap bound methods of attrs in a InstanceMethod proxies""" - # Guess which attrs are used in inference. - def wrap(attr): - if isinstance(attr, Function) and attr.type == 'method': - return InstanceMethod(attr) - else: - return attr - return imap(wrap, attrs) - - def infer_call_result(self, caller, context=None): - """infer what's a class instance is returning when called""" - infered = False - for node in self._proxied.igetattr('__call__', context): - for res in node.infer_call_result(caller, context): - infered = True - yield res - if not infered: - raise InferenceError() - - def __repr__(self): - return '<Instance of %s.%s at 0x%s>' % (self._proxied.root().name, - self._proxied.name, - id(self)) - def __str__(self): - return 'Instance of %s.%s' % (self._proxied.root().name, - self._proxied.name) - - def callable(self): - try: - self._proxied.getattr('__call__') - return True - except NotFoundError: - return False - - def pytype(self): - return self._proxied.qname() - -class Generator(Proxy): - """a special node representing a generator""" - def callable(self): - return True - - def pytype(self): - return '__builtin__.generator' - -CONST_NAME_TRANSFORMS = {'None': (Const, None), - 'True': (Const, True), - 'False': (Const, False)} - - -# inference utilities ######################################################### - -class InferenceContext(object): - __slots__ = ('startingfrom', 'path', 'lookupname', 'callcontext', 'boundnode') - - def __init__(self, node=None, path=None): - self.startingfrom = node # XXX useful ? - if path is None: - self.path = [] - else: - self.path = path - self.lookupname = None - self.callcontext = None - self.boundnode = None - - def push(self, node): - name = self.lookupname - if (node, name) in self.path: - raise StopIteration() - self.path.append( (node, name) ) - - def pop(self): - return self.path.pop() - - def clone(self): - # XXX copy lookupname/callcontext ? - clone = InferenceContext(self.startingfrom, self.path) - clone.callcontext = self.callcontext - clone.boundnode = self.boundnode - return clone - - -def _infer_stmts(stmts, context, frame=None): - """return an iterator on statements infered by each statement in <stmts> - """ - stmt = None - infered = False - if context is not None: - name = context.lookupname - context = context.clone() - else: - name = None - context = InferenceContext() - for stmt in stmts: - if stmt is YES: - yield stmt - infered = True - continue - context.lookupname = stmt._infer_name(frame, name) - try: - for infered in stmt.infer(context): - yield infered - infered = True - except UnresolvableName: - continue - except InferenceError: - yield YES - infered = True - if not infered: - raise InferenceError(str(stmt)) - def repr_tree(node, indent='', _done=None): if _done is None: diff --git a/nodes_as_string.py b/nodes_as_string.py index 4c461910..174a33f9 100644 --- a/nodes_as_string.py +++ b/nodes_as_string.py @@ -185,13 +185,13 @@ class AsStringVisitor(ASTVisitor): def visit_exec(self, node): """return an astng.Exec node as string""" - if node.globals: - return 'exec %s in %s, %s' % (node.expr.accept(self), - node.locals.accept(self), - node.globals.accept(self)) if node.locals: + return 'exec %s in %s, %s' % (node.expr.accept(self), + node.locals.accept(self), + node.globals.accept(self)) + if node.globals: return 'exec %s in %s' % (node.expr.accept(self), - node.locals.accept(self)) + node.globals.accept(self)) return 'exec %s' % node.expr.accept(self) def visit_for(self, node): diff --git a/protocols.py b/protocols.py index 7449d35c..595f3971 100644 --- a/protocols.py +++ b/protocols.py @@ -24,15 +24,17 @@ from __future__ import generators __doctype__ = "restructuredtext en" -from logilab.astng import nodes, raise_if_nothing_infered, yes_if_nothing_infered -from logilab.astng import InferenceError, NoDefault, copy_context, unpack_infer -from logilab.astng.nodes import YES, Instance, Const, Class +from logilab.astng import InferenceError, NoDefault, nodes +from logilab.astng.infutils import copy_context, unpack_infer, \ + raise_if_nothing_infered, yes_if_nothing_infered, Instance, Generator, YES +from logilab.astng.nodes import Const, Class, Function, Tuple, List, \ + const_factory # unary operations ############################################################ def tl_infer_unary_op(self, operator): if operator == 'not': - return nodes.const_factory(not bool(self.elts)) + return const_factory(not bool(self.elts)) raise TypeError() # XXX log unsupported operation nodes.Tuple.infer_unary_op = tl_infer_unary_op nodes.List.infer_unary_op = tl_infer_unary_op @@ -40,19 +42,19 @@ nodes.List.infer_unary_op = tl_infer_unary_op def dict_infer_unary_op(self, operator): if operator == 'not': - return nodes.const_factory(not bool(self.items)) + return const_factory(not bool(self.items)) raise TypeError() # XXX log unsupported operation nodes.Dict.infer_unary_op = dict_infer_unary_op def const_infer_unary_op(self, operator): if operator == 'not': - return nodes.const_factory(not self.value) + return const_factory(not self.value) # XXX log potentialy raised TypeError elif operator == '+': - return nodes.const_factory(+self.value) + return const_factory(+self.value) else: # operator == '-': - return nodes.const_factory(-self.value) + return const_factory(-self.value) nodes.Const.infer_unary_op = const_infer_unary_op @@ -68,8 +70,8 @@ BIN_OP_IMPL = {'+': lambda a,b: a+b, '&': lambda a,b: a&b, '|': lambda a,b: a|b, '^': lambda a,b: a^b, - '<<': lambda a,b: a^b, - '>>': lambda a,b: a^b, + '<<': lambda a,b: a^b, + '>>': lambda a,b: a^b, } def const_infer_binary_op(self, operator, other, context): @@ -77,7 +79,7 @@ def const_infer_binary_op(self, operator, other, context): if isinstance(other, Const): try: impl = BIN_OP_IMPL[operator] - yield nodes.const_factory(impl(self.value, other.value)) + yield const_factory(impl(self.value, other.value)) except TypeError: # XXX log TypeError continue @@ -172,7 +174,7 @@ def _resolve_looppart(parts, asspath, context): def for_assigned_stmts(self, node, context=None, asspath=None): if asspath is None: for lst in self.iter.infer(context): - if isinstance(lst, (nodes.Tuple, nodes.List)): + if isinstance(lst, (Tuple, List)): for item in lst.elts: yield item else: @@ -213,10 +215,10 @@ def _arguments_infer_argname(self, name, context): yield self.parent.parent.frame() return if name == self.vararg: - yield nodes.const_factory(()) + yield const_factory(()) return if name == self.kwarg: - yield nodes.const_factory({}) + yield const_factory({}) return # if there is a default value, yield it. And then yield YES to reflect # we can't guess given argument value @@ -285,7 +287,7 @@ def _resolve_asspart(parts, asspath, context): def excepthandler_assigned_stmts(self, node, context=None, asspath=None): for assigned in unpack_infer(self.type): - if isinstance(assigned, nodes.Class): + if isinstance(assigned, Class): assigned = Instance(assigned) yield assigned nodes.ExceptHandler.assigned_stmts = raise_if_nothing_infered(excepthandler_assigned_stmts) @@ -294,7 +296,7 @@ nodes.ExceptHandler.assigned_stmts = raise_if_nothing_infered(excepthandler_assi def with_assigned_stmts(self, node, context=None, asspath=None): if asspath is None: for lst in self.vars.infer(context): - if isinstance(lst, (nodes.Tuple, nodes.List)): + if isinstance(lst, (Tuple, List)): for item in lst.nodes: yield item nodes.With.assigned_stmts = raise_if_nothing_infered(with_assigned_stmts) @@ -348,9 +350,9 @@ nodes.Class.callable = callable_true def infer_call_result_function(self, caller, context=None): """infer what a function is returning when called""" if self.is_generator(): - yield nodes.Generator(self) + yield Generator(self) return - returns = self.nodes_of_class(nodes.Return, skip_klass=nodes.Function) + returns = self.nodes_of_class(nodes.Return, skip_klass=Function) for returnnode in returns: if returnnode.value is None: yield None @@ -415,7 +417,7 @@ def dict_getitem(self, key): for inferedkey in self.items[i].infer(): if inferedkey is YES: continue - if inferedkey.eq(key): + if isinstance(inferedkey, Const) and inferekey.value == key: return self.items[i+1] raise IndexError(key) nodes.Dict.getitem = dict_getitem diff --git a/rebuilder.py b/rebuilder.py index 3715cc5e..c5104410 100644 --- a/rebuilder.py +++ b/rebuilder.py @@ -10,7 +10,8 @@ # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -"""this module contains exceptions used in the astng library +"""this module contains utilities for rebuilding a compiler.ast or _ast tree in +order to get a single ASTNG representation :author: Sylvain Thenault :copyright: 2008-2009 LOGILAB S.A. (Paris, FRANCE) @@ -19,16 +20,17 @@ :contact: mailto:thenault@gmail.com """ -"""this module contains utilities for rebuilding a compiler.ast -or _ast tree in order to get a single ASTNG representation -""" from logilab.astng import ASTNGBuildingException, InferenceError, NodeRemoved from logilab.astng import nodes from logilab.astng.utils import ASTVisitor +from logilab.astng.infutils import YES, Instance from logilab.astng.raw_building import * -from logilab.astng.nodes_as_string import as_string +CONST_NAME_TRANSFORMS = {'None': (nodes.Const, None), + 'True': (nodes.Const, True), + 'False': (nodes.Const, False)} + class RebuildVisitor(ASTVisitor): """Visitor to transform an AST to an ASTNG """ @@ -54,6 +56,7 @@ class RebuildVisitor(ASTVisitor): def set_context(self, node, childnode): """set assignment /delete context needed later on by the childnode""" + # XXX refactor if isinstance(node, (nodes.Delete, nodes.Assign)): if childnode in node.targets: self.asscontext = node @@ -255,7 +258,7 @@ class RebuildVisitor(ASTVisitor): def visit_name(self, node): """visit an Name node to become astng""" try: - cls, value = nodes.CONST_NAME_TRANSFORMS[node.name] + cls, value = CONST_NAME_TRANSFORMS[node.name] node.__class__ = cls node.value = value except KeyError: @@ -273,20 +276,20 @@ class RebuildVisitor(ASTVisitor): try: frame = node.frame() for infered in node.expr.infer(): - if infered is nodes.YES: + if infered is YES: continue try: - if infered.__class__ is nodes.Instance: + if infered.__class__ is Instance: infered = infered._proxied iattrs = infered.instance_attrs - elif isinstance(infered, nodes.Instance): + elif isinstance(infered, Instance): # Const, Tuple, ... we may be wrong, may be not, but # anyway we don't want to pollute builtin's namespace continue else: iattrs = infered.locals except AttributeError: - # XXX + # XXX log error import traceback traceback.print_exc() continue diff --git a/scoped_nodes.py b/scoped_nodes.py index 401ff663..8cd4cb1c 100644 --- a/scoped_nodes.py +++ b/scoped_nodes.py @@ -12,7 +12,7 @@ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """This module extends ast "scoped" node, i.e. which are opening a new local scope in the language definition : Module, Class, Function (and -Lambda in some extends). +Lambda to some extends). Each new methods and attributes added on each class are documented below. @@ -32,13 +32,13 @@ import sys from logilab.common.compat import chain, set -from logilab.astng import MANAGER, InferenceContext, copy_context, \ - unpack_infer, Arguments, Class, Const, Dict, Function, GenExpr, Lambda, \ - Module, Name, Pass, Raise, Tuple, Yield, DelAttr, DelName -from logilab.astng import NotFoundError, NoDefault, ASTNGBuildingException, \ +from logilab.astng import MANAGER, NotFoundError, NoDefault, ASTNGBuildingException, \ InferenceError +from logilab.astng.nodes import Arguments, Class, Const, Dict, Function, GenExpr, \ + Lambda, Module, Name, Pass, Raise, Tuple, Yield, DelAttr, DelName from logilab.astng.utils import extend_class -from logilab.astng.nodes import YES, Instance, _infer_stmts +from logilab.astng.infutils import YES, InferenceContext, Instance, copy_context, \ + unpack_infer, _infer_stmts from logilab.astng.nodes_as_string import as_string diff --git a/test/unittest_builder.py b/test/unittest_builder.py index d16e22e9..401a2ef0 100644 --- a/test/unittest_builder.py +++ b/test/unittest_builder.py @@ -17,13 +17,15 @@ import sys from os.path import join, abspath, dirname from logilab.common.testlib import TestCase, unittest_main -from unittest_inference import get_name_node from pprint import pprint -from logilab.astng import builder, nodes, patchcomptransformer, MANAGER -from logilab.astng import Module, YES, InferenceError +from logilab.astng import builder, nodes, patchcomptransformer, MANAGER, InferenceError +from logilab.astng.nodes import Module +from logilab.astng.infutils import YES from logilab.astng.nodes_as_string import as_string +from unittest_inference import get_name_node + import data from data import module as test_module diff --git a/test/unittest_inference.py b/test/unittest_inference.py index 8a6257fb..c5c5433f 100644 --- a/test/unittest_inference.py +++ b/test/unittest_inference.py @@ -16,8 +16,8 @@ import sys from logilab.common.testlib import TestCase, unittest_main -from logilab.astng import builder, nodes, inference, YES, Instance, \ - InstanceMethod +from logilab.astng import InferenceError, builder, nodes, inference +from logilab.astng.infutils import YES, Instance, InstanceMethod, path_wrapper def get_name_node(start_from, name, index=0): return [n for n in start_from.nodes_of_class(nodes.Name) if n.name == name][index] @@ -30,9 +30,9 @@ builder = builder.ASTNGBuilder() class InferenceUtilsTC(TestCase): def test_path_wrapper(self): - infer_default = inference.path_wrapper(inference.infer_default) - infer_end = inference.path_wrapper(inference.infer_end) - self.failUnlessRaises(inference.InferenceError, + infer_default = path_wrapper(inference.infer_default) + infer_end = path_wrapper(inference.infer_end) + self.failUnlessRaises(InferenceError, infer_default(1).next) self.failUnlessEqual(infer_end(1).next(), 1) @@ -105,7 +105,7 @@ a, b= b, a # Gasp ! def test_tupleassign_name_inference(self): infered = self.astng['a'].infer() exc = infered.next() - self.assertIsInstance(exc, inference.Instance) + self.assertIsInstance(exc, Instance) self.failUnlessEqual(exc.name, 'Exception') self.failUnlessEqual(exc.root().name, 'exceptions') self.failUnlessRaises(StopIteration, infered.next) @@ -123,7 +123,7 @@ a, b= b, a # Gasp ! def test_listassign_name_inference(self): infered = self.astng['d'].infer() exc = infered.next() - self.assertIsInstance(exc, inference.Instance) + self.assertIsInstance(exc, Instance) self.failUnlessEqual(exc.name, 'Exception') self.failUnlessEqual(exc.root().name, 'exceptions') self.failUnlessRaises(StopIteration, infered.next) @@ -174,7 +174,7 @@ a, b= b, a # Gasp ! self.failUnlessRaises(StopIteration, infered.next) infered = self.astng.locals['b'][1].infer() exc = infered.next() - self.assertIsInstance(exc, inference.Instance) + self.assertIsInstance(exc, Instance) self.failUnlessEqual(exc.name, 'Exception') self.failUnlessEqual(exc.root().name, 'exceptions') self.failUnlessRaises(StopIteration, infered.next) @@ -182,7 +182,7 @@ a, b= b, a # Gasp ! def test_getattr_inference1(self): infered = self.astng['ex'].infer() exc = infered.next() - self.assertIsInstance(exc, inference.Instance) + self.assertIsInstance(exc, Instance) self.failUnlessEqual(exc.name, 'Exception') self.failUnlessEqual(exc.root().name, 'exceptions') self.failUnlessRaises(StopIteration, infered.next) @@ -211,7 +211,7 @@ a, b= b, a # Gasp ! def test_callfunc_inference(self): infered = self.astng['v'].infer() meth1 = infered.next() - self.assertIsInstance(meth1, inference.Instance) + self.assertIsInstance(meth1, Instance) self.failUnlessEqual(meth1.name, 'object') self.failUnlessEqual(meth1.root().name, '__builtin__') self.failUnlessRaises(StopIteration, infered.next) @@ -333,13 +333,13 @@ except Exception, ex: ex1 = astng['ex1'] ex1_infer = ex1.infer() ex1 = ex1_infer.next() - self.assertIsInstance(ex1, inference.Instance) + self.assertIsInstance(ex1, Instance) self.failUnlessEqual(ex1.name, 'NameError') self.failUnlessRaises(StopIteration, ex1_infer.next) ex2 = astng['ex2'] ex2_infer = ex2.infer() ex2 = ex2_infer.next() - self.assertIsInstance(ex2, inference.Instance) + self.assertIsInstance(ex2, Instance) self.failUnlessEqual(ex2.name, 'Exception') self.failUnlessRaises(StopIteration, ex2_infer.next) @@ -348,7 +348,7 @@ except Exception, ex: del undefined_attr ''' delete = builder.string_build(code, __name__, __file__).body[0] - self.failUnlessRaises(inference.InferenceError, delete.infer) + self.failUnlessRaises(InferenceError, delete.infer) def test_del2(self): code = ''' @@ -368,7 +368,7 @@ d = a self.failUnlessRaises(StopIteration, n_infer.next) n = astng['c'] n_infer = n.infer() - self.failUnlessRaises(inference.InferenceError, n_infer.next) + self.failUnlessRaises(InferenceError, n_infer.next) n = astng['d'] n_infer = n.infer() infered = n_infer.next() @@ -388,7 +388,7 @@ u = u'' n = astng['l'] infered = n.infer().next() self.assertIsInstance(infered, nodes.List) - self.assertIsInstance(infered, inference.Instance) + self.assertIsInstance(infered, Instance) self.failUnlessEqual(infered.getitem(0).value, 1) self.assertIsInstance(infered._proxied, nodes.Class) self.failUnlessEqual(infered._proxied.name, 'list') @@ -396,27 +396,27 @@ u = u'' n = astng['t'] infered = n.infer().next() self.assertIsInstance(infered, nodes.Tuple) - self.assertIsInstance(infered, inference.Instance) + self.assertIsInstance(infered, Instance) self.failUnlessEqual(infered.getitem(0).value, 2) self.assertIsInstance(infered._proxied, nodes.Class) self.failUnlessEqual(infered._proxied.name, 'tuple') n = astng['d'] infered = n.infer().next() self.assertIsInstance(infered, nodes.Dict) - self.assertIsInstance(infered, inference.Instance) + self.assertIsInstance(infered, Instance) self.assertIsInstance(infered._proxied, nodes.Class) self.failUnlessEqual(infered._proxied.name, 'dict') self.failUnless('get' in infered._proxied.locals) n = astng['s'] infered = n.infer().next() self.assertIsInstance(infered, nodes.Const) - self.assertIsInstance(infered, inference.Instance) + self.assertIsInstance(infered, Instance) self.failUnlessEqual(infered.name, 'str') self.failUnless('lower' in infered._proxied.locals) n = astng['u'] infered = n.infer().next() self.assertIsInstance(infered, nodes.Const) - self.assertIsInstance(infered, inference.Instance) + self.assertIsInstance(infered, Instance) self.failUnlessEqual(infered.name, 'unicode') self.failUnless('lower' in infered._proxied.locals) diff --git a/test/unittest_inspector.py b/test/unittest_inspector.py index ceb4cf18..f911a0db 100644 --- a/test/unittest_inspector.py +++ b/test/unittest_inspector.py @@ -20,8 +20,8 @@ unittest for the visitors.diadefs module import unittest import sys -from logilab import astng -from logilab.astng import ASTNGManager, nodes, inspector +from logilab.astng import MANAGER, nodes, inspector +from logilab.astng.infutils import Instance, YES def astng_wrapper(func, modname): return func(modname) @@ -30,7 +30,7 @@ def astng_wrapper(func, modname): class LinkerTC(unittest.TestCase): def setUp(self): - self.project = ASTNGManager().project_from_files(['data2'], astng_wrapper) + self.project = MANAGER.project_from_files(['data2'], astng_wrapper) self.linker = inspector.Linker(self.project) self.linker.visit(self.project) @@ -65,17 +65,17 @@ class LinkerTC(unittest.TestCase): keys = type_dict.keys() keys.sort() self.assertEqual(keys, ['_id', 'relation', 'toto']) - self.assert_(isinstance(type_dict['relation'][0], astng.Instance), type_dict['relation']) + self.assert_(isinstance(type_dict['relation'][0], Instance), type_dict['relation']) self.assertEqual(type_dict['relation'][0].name, 'DoNothing') - self.assert_(isinstance(type_dict['toto'][0], astng.Instance), type_dict['toto']) + self.assert_(isinstance(type_dict['toto'][0], Instance), type_dict['toto']) self.assertEqual(type_dict['toto'][0].name, 'Toto') - self.assert_(type_dict['_id'][0] is astng.YES, type_dict['_id']) + self.assert_(type_dict['_id'][0] is YES, type_dict['_id']) class LinkerTC2(LinkerTC): def setUp(self): - self.project = ASTNGManager().from_directory('data2') + self.project = MANAGER.from_directory('data2') self.linker = inspector.Linker(self.project) self.linker.visit(self.project) diff --git a/test/unittest_scoped_nodes.py b/test/unittest_scoped_nodes.py index ed54e998..2166d6a3 100644 --- a/test/unittest_scoped_nodes.py +++ b/test/unittest_scoped_nodes.py @@ -18,8 +18,10 @@ import sys from logilab.common.testlib import TestCase, unittest_main from logilab.common.compat import sorted + from logilab.astng import builder, nodes, scoped_nodes, \ InferenceError, NotFoundError +from logilab.astng.infutils import Instance abuilder = builder.ASTNGBuilder() MODULE = abuilder.file_build('data/module.py', 'data.module') @@ -325,7 +327,7 @@ class WebAppObject(object): astng = abuilder.string_build(data, __name__, __file__) cls = astng['WebAppObject'] # test del statement not returned by getattr - self.assertEquals(len(nodes.Instance(cls).getattr('appli')), 2) + self.assertEquals(len(Instance(cls).getattr('appli')), 2) __all__ = ('ModuleNodeTC', 'ImportNodeTC', 'FunctionNodeTC', 'ClassNodeTC') |