summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--__init__.py89
-rw-r--r--__pkginfo__.py2
-rw-r--r--_nodes_ast.py194
-rw-r--r--_nodes_compiler.py161
-rw-r--r--inference.py28
-rw-r--r--infutils.py282
-rw-r--r--lookup.py31
-rw-r--r--manager.py4
-rw-r--r--nodes.py197
-rw-r--r--nodes_as_string.py10
-rw-r--r--protocols.py40
-rw-r--r--rebuilder.py23
-rw-r--r--scoped_nodes.py12
-rw-r--r--test/unittest_builder.py8
-rw-r--r--test/unittest_inference.py38
-rw-r--r--test/unittest_inspector.py14
-rw-r--r--test/unittest_scoped_nodes.py4
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'
+
+
diff --git a/lookup.py b/lookup.py
index 1343a1a1..3f69abed 100644
--- a/lookup.py
+++ b/lookup.py
@@ -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
diff --git a/manager.py b/manager.py
index 0157ccf5..362ed9f6 100644
--- a/manager.py
+++ b/manager.py
@@ -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,
diff --git a/nodes.py b/nodes.py
index 795f9fe5..f843c214 100644
--- a/nodes.py
+++ b/nodes.py
@@ -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')