diff options
author | sylvain thenault <sylvain.thenault@logilab.fr> | 2009-03-19 12:46:06 +0100 |
---|---|---|
committer | sylvain thenault <sylvain.thenault@logilab.fr> | 2009-03-19 12:46:06 +0100 |
commit | 0f8763549b85bf7d872ed71797c783f6cc6968be (patch) | |
tree | fea57de5f8ee1335c5766801c098231f70e87d30 /utils.py | |
parent | 72054c730aab597b7708acffd588a735db500e90 (diff) | |
parent | 0b6c831c11dd2d19137743f76742487da3880477 (diff) | |
download | astroid-0f8763549b85bf7d872ed71797c783f6cc6968be.tar.gz |
(painful) merge
Diffstat (limited to 'utils.py')
-rw-r--r-- | utils.py | 326 |
1 files changed, 254 insertions, 72 deletions
@@ -14,26 +14,250 @@ extract information from it :author: Sylvain Thenault -:copyright: 2003-2007 LOGILAB S.A. (Paris, FRANCE) +:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE) :contact: http://www.logilab.fr/ -- mailto:python-projects@logilab.org -:copyright: 2003-2007 Sylvain Thenault +:copyright: 2003-2009 Sylvain Thenault :contact: mailto:thenault@gmail.com """ __docformat__ = "restructuredtext en" -from logilab.common.compat import enumerate -from logilab.astng import Instance, IgnoreChild +from logilab.astng._exceptions import IgnoreChild def extend_class(original, addons): """add methods and attribute defined in the addons class to the original class """ brain = addons.__dict__.copy() - for special_key in ('__doc__', '__module__'): + for special_key in ('__doc__', '__module__', '__dict__'): if special_key in addons.__dict__: del brain[special_key] - original.__dict__.update(brain) + try: + original.__dict__.update(brain) + except AttributeError: + # dictproxy object + for k, v in brain.iteritems(): + setattr(original, k, v) + + +class ASTVisitor(object): + """Abstract Base Class for Python AST Visitors. + + Visitors inheritating from ASTVisitors could visit + compiler.ast, _ast or astng trees. + + Not all methods will have to be implemented; + so some methods are just empty interfaces for catching + cases where we don't want to do anything on the + concerned node. + """ + + def visit_arguments(self, node): + """dummy method for visiting an Arguments node""" + + def visit_assattr(self, node): + """dummy method for visiting an AssAttr node""" + + def visit_assert(self, node): + """dummy method for visiting an Assert node""" + + def visit_assign(self, node): + """dummy method for visiting an Assign node""" + + def visit_assname(self, node): + """dummy method for visiting an AssName node""" + + def visit_augassign(self, node): + """dummy method for visiting an AugAssign node""" + + def visit_backquote(self, node): + """dummy method for visiting an Backquote node""" + + def visit_binop(self, node): + """dummy method for visiting an BinOp node""" + + def visit_boolop(self, node): + """dummy method for visiting an BoolOp node""" + + def visit_break(self, node): + """dummy method for visiting an Break node""" + + def visit_callfunc(self, node): + """dummy method for visiting an CallFunc node""" + + def visit_class(self, node): + """dummy method for visiting an Class node""" + + def visit_compare(self, node): + """dummy method for visiting an Compare node""" + + def visit_comprehension(self, node): + """dummy method for visiting an Comprehension node""" + + def visit_const(self, node): + """dummy method for visiting an Const node""" + + def visit_continue(self, node): + """dummy method for visiting an Continue node""" + + def visit_decorators(self, node): + """dummy method for visiting an Decorators node""" + + def visit_delattr(self, node): + """dummy method for visiting an DelAttr node""" + + def visit_delete(self, node): + """dummy method for visiting an Delete node""" + + def visit_delname(self, node): + """dummy method for visiting an DelName node""" + + def visit_dict(self, node): + """dummy method for visiting an Dict node""" + + def visit_discard(self, node): + """dummy method for visiting an Discard node""" + + def visit_emptynode(self, node): + """dummy method for visiting an EmptyNode node""" + + def visit_excepthandler(self, node): + """dummy method for visiting an ExceptHandler node""" + + def visit_ellipsis(self, node): + """dummy method for visiting an Ellipsis node""" + + def visit_empty(self, node): + """dummy method for visiting an Empty node""" + + def visit_exec(self, node): + """dummy method for visiting an Exec node""" + + def visit_extslice(self, node): + """dummy method for visiting an ExtSlice node""" + + def visit_for(self, node): + """dummy method for visiting an For node""" + + def visit_from(self, node): + """dummy method for visiting an From node""" + + def visit_function(self, node): + """dummy method for visiting an Function node""" + + def visit_genexpr(self, node): + """dummy method for visiting an ListComp node""" + + def visit_getattr(self, node): + """dummy method for visiting an Getattr node""" + + def visit_global(self, node): + """dummy method for visiting an Global node""" + + def visit_if(self, node): + """dummy method for visiting an If node""" + + def visit_ifexp(self, node): + """dummy method for visiting an IfExp node""" + + def visit_import(self, node): + """dummy method for visiting an Import node""" + + def visit_index(self, node): + """dummy method for visiting an Index node""" + + def visit_keyword(self, node): + """dummy method for visiting an Keyword node""" + + def visit_lambda(self, node): + """dummy method for visiting an Lambda node""" + + def visit_list(self, node): + """dummy method for visiting an List node""" + + def visit_listcomp(self, node): + """dummy method for visiting an ListComp node""" + + def visit_module(self, node): + """dummy method for visiting an Module node""" + + def visit_name(self, node): + """dummy method for visiting an Name node""" + + def visit_pass(self, node): + """dummy method for visiting an Pass node""" + + def visit_print(self, node): + """dummy method for visiting an Print node""" + + def visit_raise(self, node): + """dummy method for visiting an Raise node""" + + def visit_return(self, node): + """dummy method for visiting an Return node""" + + def visit_slice(self, node): + """dummy method for visiting an Slice node""" + + def visit_subscript(self, node): + """dummy method for visiting an Subscript node""" + + def visit_tryexcept(self, node): + """dummy method for visiting an TryExcept node""" + + def visit_tryfinally(self, node): + """dummy method for visiting an TryFinally node""" + + def visit_tuple(self, node): + """dummy method for visiting an Tuple node""" + + def visit_unaryop(self, node): + """dummy method for visiting an UnaryOp node""" + + def visit_while(self, node): + """dummy method for visiting an While node""" + + def visit_with(self, node): + """dummy method for visiting an With node""" + + def visit_yield(self, node): + """dummy method for visiting an Yield node""" + + +REDIRECT = {'Attribute': 'Getattr', + 'Call': 'CallFunc', + 'ClassDef': 'Class', + "ListCompFor": 'Comprehension', + "GenExprFor": 'Comprehension', + 'excepthandler': 'ExceptHandler', + 'Expr': 'Discard', + 'FunctionDef': 'Function', + 'GeneratorExp': 'GenExpr', + 'ImportFrom': 'From', + 'keyword': 'Keyword', + 'Repr': 'Backquote', + + 'Add': 'BinOp', + 'Bitand': 'BinOp', + 'Bitor': 'BinOp', + 'Bitxor': 'BinOp', + 'Div': 'BinOp', + 'FloorDiv': 'BinOp', + 'LeftShift': 'BinOp', + 'Mod': 'BinOp', + 'Mul': 'BinOp', + 'Power': 'BinOp', + 'RightShift': 'BinOp', + 'Sub': 'BinOp', + + 'And': 'BoolOp', + 'Or': 'BoolOp', + + 'UnaryAdd': 'UnaryOp', + 'UnarySub': 'UnaryOp', + 'Not': 'UnaryOp', + 'Invert': 'UnaryOp' + } class ASTWalker: """a walker visiting a tree in preorder, calling on the handler: @@ -44,31 +268,42 @@ class ASTWalker: * leave_<class name> on leaving a node, where class name is the class of the node in lower case """ + REDIRECTION = REDIRECT + def __init__(self, handler): self.handler = handler self._cache = {} - - def walk(self, node): - """walk on the tree from <node>, getting callbacks from handler - """ + + def walk(self, node, _done=None): + """walk on the tree from <node>, getting callbacks from handler""" + if _done is None: + _done = set() + if node in _done: + raise AssertionError((id(node), node, node.parent)) + _done.add(node) try: self.visit(node) except IgnoreChild: pass else: - for child_node in node.getChildNodes(): - self.walk(child_node) + try: + for child_node in node.get_children(): + self.handler.set_context(node, child_node) + assert child_node is not node + self.walk(child_node, _done) + except AttributeError: + print node.__class__, id(node.__class__) + raise self.leave(node) + assert node.parent is not node def get_callbacks(self, node): - """get callbacks from handler for the visited node - """ + """get callbacks from handler for the visited node""" klass = node.__class__ methods = self._cache.get(klass) if methods is None: handler = self.handler - kid = klass.__name__.lower() - # enter, leave + kid = self.REDIRECTION.get(klass.__name__, klass.__name__).lower() e_method = getattr(handler, 'visit_%s' % kid, getattr(handler, 'visit_default', None)) l_method = getattr(handler, 'leave_%s' % kid, @@ -110,65 +345,12 @@ class LocalsVisitor(ASTWalker): except IgnoreChild: recurse = 0 if recurse: - if hasattr(node, 'locals') and not isinstance(node, Instance): + if 'locals' in node.__dict__: # skip Instance and other proxy for name, local_node in node.items(): self.visit(local_node) if methods[1] is not None: return methods[1](node) -def are_exclusive(stmt1, stmt2): - """return true if the two given statement are mutually exclusive +__all__ = ('REDIRECT', 'LocalsVisitor', 'ASTWalker', 'ASTVisitor', + 'extend_class') - algorithm : - 1) index stmt1's parents - 2) climb among stmt2's parents until we find a common parent - 3) if the common parent is a If or TryExcept statement, look if nodes are - in exclusive branchs - """ - from logilab.astng.nodes import If, TryExcept - # index stmt1's parents - stmt1_parents = {} - children = {} - node = stmt1.parent - previous = stmt1 - while node: - stmt1_parents[node] = 1 - children[node] = previous - previous = node - node = node.parent - # climb among stmt2's parents until we find a common parent - node = stmt2.parent - previous = stmt2 - while node: - if stmt1_parents.has_key(node): - # if the common parent is a If or TryExcept statement, look if - # nodes are in exclusive branchs - if isinstance(node, If): - if previous != children[node]: - return True - elif isinstance(node, TryExcept): - stmt1_previous = children[node] - if not previous is stmt1_previous: - stmt1_branch, stmt1_num = _try_except_from_branch(node, stmt1_previous) - stmt2_branch, stmt2_num = _try_except_from_branch(node, previous) - if stmt1_branch != stmt1_branch: - if not ((stmt2_branch == 'body' and stmt1_branch == 'else') or - (stmt1_branch == 'body' and stmt2_branch == 'else') or - (stmt2_branch == 'body' and stmt1_branch == 'except') or - (stmt1_branch == 'body' and stmt2_branch == 'except')): - return True - elif stmt1_num != stmt2_num: - return True - return False - previous = node - node = node.parent - return False - -def _try_except_from_branch(node, stmt): - if stmt is node.body: - return 'body', 1 - if stmt is node.else_: - return 'else', 1 - for i, block_nodes in enumerate(node.handlers): - if stmt in block_nodes: - return 'except', i |