# Copyright (c) 2009-2014 LOGILAB S.A. (Paris, FRANCE) # Copyright (c) 2013-2016 Claudiu Popa # Copyright (c) 2015-2016 Cara Vinson # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER """this module contains utilities for rebuilding a ast tree in order to get a single Astroid representation """ import ast import collections import sys import astroid from astroid import nodes _BIN_OP_CLASSES = {ast.Add: '+', ast.BitAnd: '&', ast.BitOr: '|', ast.BitXor: '^', ast.Div: '/', ast.FloorDiv: '//', ast.Mod: '%', ast.Mult: '*', ast.Pow: '**', ast.Sub: '-', ast.LShift: '<<', ast.RShift: '>>', } if sys.version_info >= (3, 5): _BIN_OP_CLASSES[ast.MatMult] = '@' _BOOL_OP_CLASSES = {ast.And: 'and', ast.Or: 'or', } _UNARY_OP_CLASSES = {ast.UAdd: '+', ast.USub: '-', ast.Not: 'not', ast.Invert: '~', } _CMP_OP_CLASSES = {ast.Eq: '==', ast.Gt: '>', ast.GtE: '>=', ast.In: 'in', ast.Is: 'is', ast.IsNot: 'is not', ast.Lt: '<', ast.LtE: '<=', ast.NotEq: '!=', ast.NotIn: 'not in', } # Ellipsis is also one of these but has its own node BUILTIN_NAMES = {'None': None, 'NotImplemented': NotImplemented, 'True': True, 'False': False} REDIRECT = {'arguments': 'Arguments', 'comprehension': 'Comprehension', "ListCompFor": 'Comprehension', "GenExprFor": 'Comprehension', 'excepthandler': 'ExceptHandler', 'keyword': 'Keyword', } PY3 = sys.version_info >= (3, 0) PY34 = sys.version_info >= (3, 4) CONTEXTS = {ast.Load: astroid.Load, ast.Store: astroid.Store, ast.Del: astroid.Del, ast.Param: astroid.Store} def _get_doc(node): try: if isinstance(node.body[0], ast.Expr) and isinstance(node.body[0].value, ast.Str): doc = node.body[0].value.s node.body = node.body[1:] return node, doc else: return node, None except IndexError: return node, None def _visit_or_none(node, attr, visitor, parent, visit='visit', **kws): """If the given node has an attribute, visits the attribute, and otherwise returns None. """ value = getattr(node, attr, None) if value: return getattr(visitor, visit)(value, parent, **kws) else: return None def _get_context(node): return CONTEXTS.get(type(node.ctx), astroid.Load) class ParameterVisitor(object): """A visitor which is used for building the components of Arguments node.""" def __init__(self, visitor): self._visitor = visitor def visit(self, param_node, *args): cls_name = param_node.__class__.__name__ visit_name = 'visit_' + REDIRECT.get(cls_name, cls_name).lower() visit_method = getattr(self, visit_name) return visit_method(param_node, *args) def visit_arg(self, param_node, *args): name = param_node.arg return self._build_parameter(param_node, name, *args) def visit_name(self, param_node, *args): name = param_node.id return self._build_parameter(param_node, name, *args) def visit_tuple(self, param_node, parent, default): # We're not supporting nested arguments anymore, but in order to # simply not crash when running on Python 2, we're unpacking the elements # before hand. We simply don't want to support this feature anymore, # so it's possible to be broken. converted_node = self._visitor.visit(param_node, parent) for element in converted_node.elts: param = nodes.Parameter(name=element.name, lineno=param_node.lineno, col_offset=param_node.col_offset, parent=parent) param.postinit(default=default, annotation=nodes.Empty) yield param def _build_parameter(self, param_node, name, parent, default): param = nodes.Parameter(name=name, lineno=getattr(param_node, 'lineno', None), col_offset=getattr(param_node, 'col_offset', None), parent=parent) annotation = nodes.Empty param_annotation = getattr(param_node, 'annotation', None) if param_annotation: annotation = self._visitor.visit(param_annotation, param) param.postinit(default=default, annotation=annotation) yield param class TreeRebuilder(object): """Rebuilds the ast tree to become an Astroid tree""" def __init__(self): self._global_names = [] self._visit_meths = {} def visit_module(self, node, modname, modpath, package): """visit a Module node by returning a fresh instance of it""" node, doc = _get_doc(node) newnode = nodes.Module(name=modname, doc=doc, package=package, pure_python=True, source_file=modpath) newnode.postinit([self.visit(child, newnode) for child in node.body]) return newnode def visit(self, node, parent): cls = node.__class__ if cls in self._visit_meths: visit_method = self._visit_meths[cls] else: cls_name = cls.__name__ visit_name = 'visit_' + REDIRECT.get(cls_name, cls_name).lower() visit_method = getattr(self, visit_name) self._visit_meths[cls] = visit_method return visit_method(node, parent) def visit_arguments(self, node, parent): """visit a Arguments node by returning a fresh instance of it""" def _build_variadic(field_name): param = nodes.Empty variadic = getattr(node, field_name) if variadic: # Various places to get the name from. try: param_name = variadic.id except AttributeError: try: param_name = variadic.arg except AttributeError: param_name = variadic lineno = getattr(variadic, 'lineno', newnode.lineno) col_offset = getattr(variadic, 'col_offset', newnode.col_offset) param = nodes.Parameter(name=param_name, lineno=lineno, col_offset=col_offset, parent=newnode) # Get the annotation of the variadic node. annotation = nodes.Empty default = nodes.Empty variadic_annotation = getattr(variadic, 'annotation', None) if variadic_annotation is None: # Support for Python 3.3. variadic_annotation = getattr(node, field_name + 'annotation', None) if variadic_annotation: annotation = self.visit(variadic_annotation, param) param.postinit(default=default, annotation=annotation) return param def _build_args(params, defaults): # Pad the list of defaults so that each arguments gets a default. defaults = collections.deque(defaults) while len(defaults) != len(params): defaults.appendleft(nodes.Empty) param_visitor = ParameterVisitor(self) for parameter in params: default = defaults.popleft() if default: default = self.visit(default, newnode) for param in param_visitor.visit(parameter, newnode, default): yield param newnode = nodes.Arguments(parent=parent) # Build the arguments list. positional_args = list(_build_args(node.args, node.defaults)) kwonlyargs = list(_build_args(getattr(node, 'kwonlyargs', ()), getattr(node, 'kw_defaults', ()))) # Build vararg and kwarg. vararg = _build_variadic('vararg') kwarg = _build_variadic('kwarg') # Prepare the arguments new node. newnode.postinit(args=positional_args, vararg=vararg, kwarg=kwarg, keyword_only=kwonlyargs, positional_only=[]) return newnode def visit_assert(self, node, parent): """visit a Assert node by returning a fresh instance of it""" newnode = nodes.Assert(node.lineno, node.col_offset, parent) if node.msg: msg = self.visit(node.msg, newnode) else: msg = None newnode.postinit(self.visit(node.test, newnode), msg) return newnode def visit_assign(self, node, parent): """visit a Assign node by returning a fresh instance of it""" newnode = nodes.Assign(node.lineno, node.col_offset, parent) newnode.postinit([self.visit(child, newnode) for child in node.targets], self.visit(node.value, newnode)) return newnode def visit_assignname(self, node, parent, node_name=None): '''visit a node and return a AssignName node''' newnode = nodes.AssignName(node_name, getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) return newnode def visit_augassign(self, node, parent): """visit a AugAssign node by returning a fresh instance of it""" newnode = nodes.AugAssign(_BIN_OP_CLASSES[type(node.op)] + "=", node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.target, newnode), self.visit(node.value, newnode)) return newnode def visit_repr(self, node, parent): """visit a Backquote node by returning a fresh instance of it""" newnode = nodes.Repr(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.value, newnode)) return newnode def visit_binop(self, node, parent): """visit a BinOp node by returning a fresh instance of it""" newnode = nodes.BinOp(_BIN_OP_CLASSES[type(node.op)], node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.left, newnode), self.visit(node.right, newnode)) return newnode def visit_boolop(self, node, parent): """visit a BoolOp node by returning a fresh instance of it""" newnode = nodes.BoolOp(_BOOL_OP_CLASSES[type(node.op)], node.lineno, node.col_offset, parent) newnode.postinit([self.visit(child, newnode) for child in node.values]) return newnode def visit_break(self, node, parent): """visit a Break node by returning a fresh instance of it""" return nodes.Break(getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) def visit_call(self, node, parent): """visit a CallFunc node by returning a fresh instance of it""" newnode = nodes.Call(node.lineno, node.col_offset, parent) starargs = _visit_or_none(node, 'starargs', self, newnode) kwargs = _visit_or_none(node, 'kwargs', self, newnode) args = [self.visit(child, newnode) for child in node.args] if node.keywords: keywords = [self.visit(child, newnode) for child in node.keywords] else: keywords = None if starargs: new_starargs = nodes.Starred(col_offset=starargs.col_offset, lineno=starargs.lineno, parent=starargs.parent) new_starargs.postinit(value=starargs) args.append(new_starargs) if kwargs: new_kwargs = nodes.Keyword(arg=None, col_offset=kwargs.col_offset, lineno=kwargs.lineno, parent=kwargs.parent) new_kwargs.postinit(value=kwargs) if keywords: keywords.append(new_kwargs) else: keywords = [new_kwargs] newnode.postinit(self.visit(node.func, newnode), args, keywords) return newnode def visit_classdef(self, node, parent, newstyle=None): """visit a ClassDef node to become astroid""" node, doc = _get_doc(node) newnode = nodes.ClassDef(node.name, doc, node.lineno, node.col_offset, parent) metaclass = None if PY3: for keyword in node.keywords: if keyword.arg == 'metaclass': metaclass = self.visit(keyword, newnode).value break if node.decorator_list: decorators = self.visit_decorators(node, newnode) else: decorators = None newnode.postinit([self.visit(child, newnode) for child in node.bases], [self.visit(child, newnode) for child in node.body], decorators, newstyle, metaclass, [self.visit(kwd, newnode) for kwd in node.keywords if kwd.arg != 'metaclass'] if PY3 else []) return newnode def visit_const(self, node, parent): """visit a Const node by returning a fresh instance of it""" return nodes.Const(node.value, getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) def visit_continue(self, node, parent): """visit a Continue node by returning a fresh instance of it""" return nodes.Continue(getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) def visit_compare(self, node, parent): """visit a Compare node by returning a fresh instance of it""" newnode = nodes.Compare([_CMP_OP_CLASSES[type(op)] for op in node.ops], node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.left, newnode), [self.visit(expr, newnode) for expr in node.comparators]) return newnode def visit_comprehension(self, node, parent): """visit a Comprehension node by returning a fresh instance of it""" newnode = nodes.Comprehension(parent) newnode.postinit(self.visit(node.target, newnode), self.visit(node.iter, newnode), [self.visit(child, newnode) for child in node.ifs]) return newnode def visit_decorators(self, node, parent): """visit a Decorators node by returning a fresh instance of it""" # /!\ node is actually a ast.FunctionDef node while # parent is a astroid.nodes.FunctionDef node newnode = nodes.Decorators(node.lineno, node.col_offset, parent) newnode.postinit([self.visit(child, newnode) for child in node.decorator_list]) return newnode def visit_delete(self, node, parent): """visit a Delete node by returning a fresh instance of it""" newnode = nodes.Delete(node.lineno, node.col_offset, parent) newnode.postinit([self.visit(child, newnode) for child in node.targets]) return newnode def _visit_dict_items(self, node, parent, newnode): for key, value in zip(node.keys, node.values): rebuilt_value = self.visit(value, newnode) if not key: # Python 3.5 and extended unpacking rebuilt_key = nodes.DictUnpack(rebuilt_value.lineno, rebuilt_value.col_offset, parent) else: rebuilt_key = self.visit(key, newnode) yield rebuilt_key, rebuilt_value def visit_dict(self, node, parent): """visit a Dict node by returning a fresh instance of it""" newnode = nodes.Dict(node.lineno, node.col_offset, parent) items = list(self._visit_dict_items(node, parent, newnode)) if items: keys, values = zip(*items) else: keys, values = [], [] newnode.postinit(keys, values) return newnode def visit_dictcomp(self, node, parent): """visit a DictComp node by returning a fresh instance of it""" newnode = nodes.DictComp(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.key, newnode), self.visit(node.value, newnode), [self.visit(child, newnode) for child in node.generators]) return newnode def visit_expr(self, node, parent): """visit a Expr node by returning a fresh instance of it""" newnode = nodes.Expr(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.value, newnode)) return newnode def visit_ellipsis(self, node, parent): """visit an Ellipsis node by returning a fresh instance of it""" return nodes.Ellipsis(getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) def visit_excepthandler(self, node, parent): """visit an ExceptHandler node by returning a fresh instance of it""" newnode = nodes.ExceptHandler(node.lineno, node.col_offset, parent) # /!\ node.name can be a tuple newnode.postinit(_visit_or_none(node, 'type', self, newnode), _visit_or_none(node, 'name', self, newnode), [self.visit(child, newnode) for child in node.body]) return newnode def visit_exec(self, node, parent): """visit an Exec node by returning a fresh instance of it""" newnode = nodes.Exec(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.body, newnode), _visit_or_none(node, 'globals', self, newnode), _visit_or_none(node, 'locals', self, newnode)) return newnode def visit_extslice(self, node, parent): """visit an ExtSlice node by returning a fresh instance of it""" newnode = nodes.ExtSlice(parent=parent) newnode.postinit([self.visit(dim, newnode) for dim in node.dims]) return newnode def _visit_for(self, cls, node, parent): """visit a For node by returning a fresh instance of it""" newnode = cls(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.target, newnode), self.visit(node.iter, newnode), [self.visit(child, newnode) for child in node.body], [self.visit(child, newnode) for child in node.orelse]) return newnode def visit_for(self, node, parent): return self._visit_for(nodes.For, node, parent) def visit_importfrom(self, node, parent): """visit an ImportFrom node by returning a fresh instance of it""" names = [(alias.name, alias.asname) for alias in node.names] newnode = nodes.ImportFrom(node.module or '', names, node.level or None, getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) return newnode def _visit_functiondef(self, cls, node, parent): """visit an FunctionDef node to become astroid""" self._global_names.append({}) node, doc = _get_doc(node) newnode = cls(node.name, doc, node.lineno, node.col_offset, parent) if node.decorator_list: decorators = self.visit_decorators(node, newnode) else: decorators = None if PY3 and node.returns: returns = self.visit(node.returns, newnode) else: returns = None newnode.postinit(self.visit(node.args, newnode), [self.visit(child, newnode) for child in node.body], decorators, returns) self._global_names.pop() return newnode def visit_functiondef(self, node, parent): return self._visit_functiondef(nodes.FunctionDef, node, parent) def visit_generatorexp(self, node, parent): """visit a GeneratorExp node by returning a fresh instance of it""" newnode = nodes.GeneratorExp(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.elt, newnode), [self.visit(child, newnode) for child in node.generators]) return newnode def visit_attribute(self, node, parent): """visit an Attribute node by returning a fresh instance of it""" context = _get_context(node) if context == astroid.Del: # FIXME : maybe we should reintroduce and visit_delattr ? # for instance, deactivating assign_ctx newnode = nodes.DelAttr(node.attr, node.lineno, node.col_offset, parent) elif context == astroid.Store: newnode = nodes.AssignAttr(node.attr, node.lineno, node.col_offset, parent) else: newnode = nodes.Attribute(node.attr, node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.value, newnode)) return newnode def visit_global(self, node, parent): """visit a Global node to become astroid""" newnode = nodes.Global(node.names, getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) if self._global_names: # global at the module level, no effect for name in node.names: self._global_names[-1].setdefault(name, []).append(newnode) return newnode def visit_if(self, node, parent): """visit an If node by returning a fresh instance of it""" newnode = nodes.If(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.test, newnode), [self.visit(child, newnode) for child in node.body], [self.visit(child, newnode) for child in node.orelse]) return newnode def visit_ifexp(self, node, parent): """visit a IfExp node by returning a fresh instance of it""" newnode = nodes.IfExp(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.test, newnode), self.visit(node.body, newnode), self.visit(node.orelse, newnode)) return newnode def visit_import(self, node, parent): """visit a Import node by returning a fresh instance of it""" names = [(alias.name, alias.asname) for alias in node.names] newnode = nodes.Import(names, getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) return newnode def visit_index(self, node, parent): """visit a Index node by returning a fresh instance of it""" newnode = nodes.Index(parent=parent) newnode.postinit(self.visit(node.value, newnode)) return newnode def visit_keyword(self, node, parent): """visit a Keyword node by returning a fresh instance of it""" newnode = nodes.Keyword(node.arg, parent=parent) newnode.postinit(self.visit(node.value, newnode)) return newnode def visit_lambda(self, node, parent): """visit a Lambda node by returning a fresh instance of it""" newnode = nodes.Lambda(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.args, newnode), self.visit(node.body, newnode)) return newnode def visit_list(self, node, parent): """visit a List node by returning a fresh instance of it""" context = _get_context(node) newnode = nodes.List(ctx=context, lineno=node.lineno, col_offset=node.col_offset, parent=parent) newnode.postinit([self.visit(child, newnode) for child in node.elts]) return newnode def visit_listcomp(self, node, parent): """visit a ListComp node by returning a fresh instance of it""" newnode = nodes.ListComp(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.elt, newnode), [self.visit(child, newnode) for child in node.generators]) return newnode def visit_name(self, node, parent): """visit a Name node by returning a fresh instance of it""" context = _get_context(node) # True and False can be assigned to something in py2x, so we have to # check first the context. if context == astroid.Del: newnode = nodes.DelName(node.id, node.lineno, node.col_offset, parent) elif context == astroid.Store: newnode = nodes.AssignName(node.id, node.lineno, node.col_offset, parent) elif node.id in BUILTIN_NAMES: newnode = nodes.NameConstant(BUILTIN_NAMES[node.id], getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) return newnode else: newnode = nodes.Name(node.id, node.lineno, node.col_offset, parent) return newnode def visit_str(self, node, parent): """visit a String/Bytes node by returning a fresh instance of Const""" return nodes.Const(node.s, getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) visit_bytes = visit_str def visit_num(self, node, parent): """visit a Num node by returning a fresh instance of Const""" return nodes.Const(node.n, getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) def visit_pass(self, node, parent): """visit a Pass node by returning a fresh instance of it""" return nodes.Pass(node.lineno, node.col_offset, parent) def visit_print(self, node, parent): """visit a Print node by returning a fresh instance of it""" newnode = nodes.Print(node.nl, node.lineno, node.col_offset, parent) newnode.postinit(_visit_or_none(node, 'dest', self, newnode), [self.visit(child, newnode) for child in node.values]) return newnode def visit_raise(self, node, parent): """visit a Raise node by returning a fresh instance of it""" newnode = nodes.Raise(node.lineno, node.col_offset, parent) newnode.postinit(_visit_or_none(node, 'type', self, newnode), _visit_or_none(node, 'inst', self, newnode), _visit_or_none(node, 'tback', self, newnode)) return newnode def visit_return(self, node, parent): """visit a Return node by returning a fresh instance of it""" newnode = nodes.Return(node.lineno, node.col_offset, parent) if node.value is not None: newnode.postinit(self.visit(node.value, newnode)) return newnode def visit_set(self, node, parent): """visit a Set node by returning a fresh instance of it""" newnode = nodes.Set(node.lineno, node.col_offset, parent) newnode.postinit([self.visit(child, newnode) for child in node.elts]) return newnode def visit_setcomp(self, node, parent): """visit a SetComp node by returning a fresh instance of it""" newnode = nodes.SetComp(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.elt, newnode), [self.visit(child, newnode) for child in node.generators]) return newnode def visit_slice(self, node, parent): """visit a Slice node by returning a fresh instance of it""" newnode = nodes.Slice(parent=parent) newnode.postinit(_visit_or_none(node, 'lower', self, newnode), _visit_or_none(node, 'upper', self, newnode), _visit_or_none(node, 'step', self, newnode)) return newnode def visit_subscript(self, node, parent): """visit a Subscript node by returning a fresh instance of it""" context = _get_context(node) newnode = nodes.Subscript(ctx=context, lineno=node.lineno, col_offset=node.col_offset, parent=parent) newnode.postinit(self.visit(node.value, newnode), self.visit(node.slice, newnode)) return newnode def visit_tryexcept(self, node, parent): """visit a TryExcept node by returning a fresh instance of it""" newnode = nodes.TryExcept(node.lineno, node.col_offset, parent) newnode.postinit([self.visit(child, newnode) for child in node.body], [self.visit(child, newnode) for child in node.handlers], [self.visit(child, newnode) for child in node.orelse]) return newnode def visit_tryfinally(self, node, parent): """visit a TryFinally node by returning a fresh instance of it""" newnode = nodes.TryFinally(node.lineno, node.col_offset, parent) newnode.postinit([self.visit(child, newnode) for child in node.body], [self.visit(n, newnode) for n in node.finalbody]) return newnode def visit_tuple(self, node, parent): """visit a Tuple node by returning a fresh instance of it""" context = _get_context(node) newnode = nodes.Tuple(ctx=context, lineno=node.lineno, col_offset=node.col_offset, parent=parent) newnode.postinit([self.visit(child, newnode) for child in node.elts]) return newnode def visit_unaryop(self, node, parent): """visit a UnaryOp node by returning a fresh instance of it""" newnode = nodes.UnaryOp(_UNARY_OP_CLASSES[node.op.__class__], node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.operand, newnode)) return newnode def visit_while(self, node, parent): """visit a While node by returning a fresh instance of it""" newnode = nodes.While(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.test, newnode), [self.visit(child, newnode) for child in node.body], [self.visit(child, newnode) for child in node.orelse]) return newnode def visit_with(self, node, parent): newnode = nodes.With(node.lineno, node.col_offset, parent) with_item = nodes.WithItem(node.context_expr.lineno, node.context_expr.col_offset, newnode) context_expr = self.visit(node.context_expr, with_item) optional_vars = _visit_or_none(node, 'optional_vars', self, with_item) with_item.postinit(context_expr, optional_vars) newnode.postinit([with_item], [self.visit(child, newnode) for child in node.body]) return newnode def visit_yield(self, node, parent): """visit a Yield node by returning a fresh instance of it""" newnode = nodes.Yield(node.lineno, node.col_offset, parent) if node.value is not None: newnode.postinit(self.visit(node.value, newnode)) return newnode class TreeRebuilder3(TreeRebuilder): """extend and overwrite TreeRebuilder for python3k""" def visit_nameconstant(self, node, parent): # in Python 3.4 we have NameConstant for True / False / None return nodes.NameConstant(node.value, getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) def visit_excepthandler(self, node, parent): """visit an ExceptHandler node by returning a fresh instance of it""" newnode = nodes.ExceptHandler(node.lineno, node.col_offset, parent) if node.name: name = self.visit_assignname(node, newnode, node.name) else: name = None newnode.postinit(_visit_or_none(node, 'type', self, newnode), name, [self.visit(child, newnode) for child in node.body]) return newnode def visit_nonlocal(self, node, parent): """visit a Nonlocal node and return a new instance of it""" return nodes.Nonlocal(node.names, getattr(node, 'lineno', None), getattr(node, 'col_offset', None), parent) def visit_raise(self, node, parent): """visit a Raise node by returning a fresh instance of it""" newnode = nodes.Raise(node.lineno, node.col_offset, parent) # no traceback; anyway it is not used in Pylint newnode.postinit(_visit_or_none(node, 'exc', self, newnode), _visit_or_none(node, 'cause', self, newnode)) return newnode def visit_starred(self, node, parent): """visit a Starred node and return a new instance of it""" context = _get_context(node) newnode = nodes.Starred(ctx=context, lineno=node.lineno, col_offset=node.col_offset, parent=parent) newnode.postinit(self.visit(node.value, newnode)) return newnode def visit_try(self, node, parent): # python 3.3 introduce a new Try node replacing # TryFinally/TryExcept nodes if node.finalbody: newnode = nodes.TryFinally(node.lineno, node.col_offset, parent) if node.handlers: body = [self.visit_tryexcept(node, newnode)] else: body = [self.visit(child, newnode) for child in node.body] newnode.postinit(body, [self.visit(n, newnode) for n in node.finalbody]) return newnode elif node.handlers: return self.visit_tryexcept(node, parent) def visit_with(self, node, parent, constructor=nodes.With): newnode = constructor(node.lineno, node.col_offset, parent) newnode.postinit([self.visit(item, newnode) for item in node.items], [self.visit(child, newnode) for child in node.body]) return newnode def visit_withitem(self, node, parent): newnode = nodes.WithItem(node.context_expr.lineno, node.context_expr.col_offset, parent) context_expr = self.visit(node.context_expr, newnode) optional_vars = _visit_or_none(node, 'optional_vars', self, newnode) newnode.postinit(context_expr=context_expr, optional_vars=optional_vars) return newnode def visit_yieldfrom(self, node, parent): newnode = nodes.YieldFrom(node.lineno, node.col_offset, parent) if node.value is not None: newnode.postinit(self.visit(node.value, newnode)) return newnode def visit_classdef(self, node, parent, newstyle=True): return super(TreeRebuilder3, self).visit_classdef(node, parent, newstyle=newstyle) # Async structs added in Python 3.5 def visit_asyncfunctiondef(self, node, parent): return self._visit_functiondef(nodes.AsyncFunctionDef, node, parent) def visit_asyncfor(self, node, parent): return self._visit_for(nodes.AsyncFor, node, parent) def visit_await(self, node, parent): newnode = nodes.Await(node.lineno, node.col_offset, parent) newnode.postinit(value=self.visit(node.value, newnode)) return newnode def visit_asyncwith(self, node, parent): return self.visit_with(node, parent, constructor=nodes.AsyncWith) def visit_joinedstr(self, node, parent): newnode = nodes.JoinedStr(node.lineno, node.col_offset, parent) newnode.postinit([self.visit(child, newnode) for child in node.values]) return newnode def visit_formattedvalue(self, node, parent): newnode = nodes.FormattedValue(node.lineno, node.col_offset, parent) newnode.postinit(self.visit(node.value, newnode), node.conversion, _visit_or_none(node, 'format_spec', self, newnode)) return newnode if sys.version_info >= (3, 0): TreeRebuilder = TreeRebuilder3