summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmile Anclin <emile.anclin@logilab.fr>2010-11-10 18:08:57 +0100
committerEmile Anclin <emile.anclin@logilab.fr>2010-11-10 18:08:57 +0100
commit0b95c6d89a5eb2d3855b2353bb9817cc7cae3ded (patch)
tree0a751054bb129071640921092f25e93cb26d9d2b
parent496e40ed0f16e9f90937dc49c82aa1f37652c1ba (diff)
downloadastroid-git-0b95c6d89a5eb2d3855b2353bb9817cc7cae3ded.tar.gz
cleanup: remove python < 2.5 support
-rw-r--r--_nodes_compiler.py761
-rw-r--r--builder.py13
-rw-r--r--patchcomptransformer.py159
-rw-r--r--rebuilder.py12
-rw-r--r--test/unittest_builder.py32
-rw-r--r--test/unittest_inference.py38
-rw-r--r--test/unittest_lookup.py8
-rw-r--r--test/unittest_nodes.py2
-rw-r--r--test/unittest_scoped_nodes.py2
9 files changed, 28 insertions, 999 deletions
diff --git a/_nodes_compiler.py b/_nodes_compiler.py
deleted file mode 100644
index 6a89caef..00000000
--- a/_nodes_compiler.py
+++ /dev/null
@@ -1,761 +0,0 @@
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU Lesser 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser 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.
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-# copyright 2003-2010 Sylvain Thenault, all rights reserved.
-# contact mailto:thenault@gmail.com
-#
-# This file is part of logilab-astng.
-#
-# logilab-astng is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by the
-# Free Software Foundation, either version 2.1 of the License, or (at your
-# option) any later version.
-#
-# logilab-astng 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 Lesser General Public License
-# for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with logilab-astng. If not, see <http://www.gnu.org/licenses/>.
-"""python < 2.5 compiler package compatibility module [1]
-
-
- [1] http://docs.python.org/lib/module-compiler.ast.html
-"""
-
-__docformat__ = "restructuredtext en"
-
-from compiler.ast import Const, Node, Sliceobj, Function
-import sys
-
-# nodes which are not part of astng
-from compiler.ast import And as _And, Or as _Or,\
- UnaryAdd as _UnaryAdd, UnarySub as _UnarySub, Not as _Not,\
- Invert as _Invert, Add as _Add, Div as _Div, FloorDiv as _FloorDiv,\
- Mod as _Mod, Mul as _Mul, Power as _Power, Sub as _Sub, Bitand as _Bitand,\
- Bitor as _Bitor, Bitxor as _Bitxor, LeftShift as _LeftShift,\
- RightShift as _RightShift
-
-
-from logilab.astng import nodes as new
-from logilab.astng.rebuilder import RebuildVisitor
-from logilab.common.compat import set
-
-CONST_NAME_TRANSFORMS = {'None': None,
- 'True': True,
- 'False': False}
-
-
-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 unexistent in compiler #####################################
-
-BinOp_OP_CLASSES = {_Add: '+',
- _Div: '/',
- _FloorDiv: '//',
- _Mod: '%',
- _Mul: '*',
- _Power: '**',
- _Sub: '-',
- _Bitand: '&',
- _Bitor: '|',
- _Bitxor: '^',
- _LeftShift: '<<',
- _RightShift: '>>'
- }
-BinOp_BIT_CLASSES = {'&': _Bitand,
- '|': _Bitor,
- '^': _Bitxor
- }
-
-
-BoolOp_OP_CLASSES = {_And: 'and',
- _Or: 'or'
- }
-
-UnaryOp_OP_CLASSES = {_UnaryAdd: '+',
- _UnarySub: '-',
- _Not: 'not',
- _Invert: '~'
- }
-
-
-# compiler rebuilder ##########################################################
-
-def _filter_none(node):
- """transform Const(None) to None"""
- if isinstance(node, Const) and node.value is None:
- return None
- else:
- return node
-
-
-class TreeRebuilder(RebuildVisitor):
- """Rebuilds the compiler tree to become an ASTNG tree"""
-
- def _init_else_node(self, node, newnode):
- """visit else block; replace None by empty list"""
- if not node.else_:
- return []
- return [self.visit(child, newnode) for child in node.else_.nodes]
-
- def _set_infos(self, oldnode, newnode, newparent):
- newnode.parent = newparent
- if hasattr(oldnode, 'lineno'):
- newnode.lineno = oldnode.lineno
- if hasattr(oldnode, 'fromlineno'):
- newnode.fromlineno = oldnode.fromlineno
- if hasattr(oldnode, 'tolineno'):
- newnode.tolineno = oldnode.tolineno
- if hasattr(oldnode, 'blockstart_tolineno'):
- newnode.blockstart_tolineno = oldnode.blockstart_tolineno
-
- def _check_del_node(self, node, parent, targets):
- """insert a Delete node if necessary.
-
- As for assignments we have a Assign (or For or ...) node, this method
- is only called in delete contexts. Hence we return a Delete node"""
- if self.asscontext is None:
- self.asscontext = "Del"
- newnode = new.Delete()
- self._set_infos(node, newnode, parent)
- newnode.targets = [self.visit(elt, newnode) for elt in targets]
- self.asscontext = None
- return newnode
- else:
- # this will trigger the visit_ass* methods to create the right nodes
- return False
-
- def _nodify_args(self, parent, values):
- """transform arguments and tuples or lists of arguments into astng nodes"""
- res = []
- for arg in values:
- if isinstance(arg, (tuple, list)):
- n = new.Tuple()
- self._set_infos(parent, n, parent)
- n.elts = self._nodify_args(n, arg)
- else:
- assert isinstance(arg, basestring)
- n = new.AssName()
- self._set_infos(parent, n, parent)
- n.name = arg
- self._save_assignment(n, n.name)
- res.append(n)
- return res
-
- def visit_arguments(self, node, parent):
- """visit an Arguments node by returning a fresh instance of it"""
- # /!\ incoming node is Function or Lambda, coming directly from visit_*
- if node.flags & 8:
- kwarg = node.argnames.pop()
- else:
- kwarg = None
- if node.flags & 4:
- vararg = node.argnames.pop()
- else:
- vararg = None
- newnode = new.Arguments(vararg, kwarg)
- newnode.parent = parent
- newnode.fromlineno = parent.fromlineno
- try:
- newnode.tolineno = parent.blockstart_tolineno
- except AttributeError: # lambda
- newnode.tolineno = parent.tolineno
- newnode.args = self._nodify_args(newnode, node.argnames)
- self._save_argument_name(newnode)
- newnode.defaults = [self.visit(n, newnode) for n in node.defaults]
- return newnode
-
- def visit_assattr(self, node, parent):
- """visit an AssAttr node by returning a fresh instance of it"""
- delnode = self._check_del_node(node, parent, [node])
- if delnode:
- return delnode
- elif self.asscontext == "Del":
- return self.visit_delattr(node, parent)
- elif self.asscontext in ("Ass", "Aug"):
- newnode = new.AssAttr()
- self._set_infos(node, newnode, parent)
- asscontext, self.asscontext = self.asscontext, None
- newnode.expr = self.visit(node.expr, newnode)
- self.asscontext = asscontext
- newnode.attrname = node.attrname
- self._delayed_assattr.append(newnode)
- return newnode
-
- def visit_assname(self, node, parent):
- """visit an AssName node by returning a fresh instance of it"""
- delnode = self._check_del_node(node, parent, [node])
- if delnode:
- return delnode
- elif self.asscontext == "Del":
- return self.visit_delname(node, parent)
- assert self.asscontext in ("Ass", "Aug")
- newnode = new.AssName()
- self._set_infos(node, newnode, parent)
- newnode.name = node.name
- self._save_assignment(newnode)
- return newnode
-
- def visit_assert(self, node, parent):
- """visit an Assert node by returning a fresh instance of it"""
- newnode = new.Assert()
- self._set_infos(node, newnode, parent)
- newnode.test = self.visit(node.test, newnode)
- newnode.fail = self.visit(node.fail, newnode)
- return newnode
-
- def visit_assign(self, node, parent):
- """visit an Assign node by returning a fresh instance of it"""
- newnode = new.Assign()
- self._set_infos(node, newnode, parent)
- self.asscontext = 'Ass'
- newnode.targets = [self.visit(child, newnode) for child in node.nodes]
- # /!\ Subscript can appear on both sides,
- # so we need 'Ass' in rhs to avoid inserting a Delete node
- newnode.value = self.visit(node.expr, newnode)
- self.asscontext = None
- self._set_assign_infos(newnode)
- return newnode
-
- def visit_asslist(self, node, parent):
- # FIXME : use self._check_del_node(node, [node]) more precise ?
- delnode = self._check_del_node(node, parent, node.nodes)
- if delnode:
- return delnode
- return self.visit_list(node, parent)
-
- def visit_asstuple(self, node, parent):
- delnode = self._check_del_node(node, parent, node.nodes)
- if delnode:
- return delnode
- return self.visit_tuple(node, parent)
-
- def visit_augassign(self, node, parent):
- """visit an AugAssign node by returning a fresh instance of it"""
- newnode = new.AugAssign()
- self._set_infos(node, newnode, parent)
- self.asscontext = "Aug"
- newnode.target = self.visit(node.node, newnode)
- self.asscontext = None
- newnode.op = node.op
- newnode.value = self.visit(node.expr, newnode)
- return newnode
-
- def visit_backquote(self, node, parent):
- """visit a Backquote node by returning a fresh instance of it"""
- newnode = new.Backquote()
- self._set_infos(node, newnode, parent)
- newnode.value = self.visit(node.expr, newnode)
- return newnode
-
- def visit_binop(self, node, parent):
- """visit a BinOp node by returning a fresh instance of it"""
- newnode = new.BinOp()
- self._set_infos(node, newnode, parent)
- newnode.op = BinOp_OP_CLASSES[node.__class__]
- if newnode.op in ('&', '|', '^'):
- newnode.right = self.visit(node.nodes[-1], newnode)
- bitop = BinOp_BIT_CLASSES[newnode.op]
- if len(node.nodes) > 2:
- # create a bitop node on the fly and visit it:
- # XXX can't we create directly the right node ?
- newnode.left = self.visit(bitop(node.nodes[:-1]), newnode)
- else:
- newnode.left = self.visit(node.nodes[0], newnode)
- else:
- newnode.left = self.visit(node.left, newnode)
- newnode.right = 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 = new.BoolOp()
- self._set_infos(node, newnode, parent)
- newnode.values = [self.visit(child, newnode) for child in node.nodes]
- newnode.op = BoolOp_OP_CLASSES[node.__class__]
- return newnode
-
- def visit_callfunc(self, node, parent):
- """visit a CallFunc node by returning a fresh instance of it"""
- newnode = new.CallFunc()
- self._set_infos(node, newnode, parent)
- newnode.func = self.visit(node.node, newnode)
- newnode.args = [self.visit(child, newnode) for child in node.args]
- if node.star_args:
- newnode.starargs = self.visit(node.star_args, newnode)
- if node.dstar_args:
- newnode.kwargs = self.visit(node.dstar_args, newnode)
- return newnode
-
- def _visit_class(self, node, parent):
- """visit a Class node by returning a fresh instance of it"""
- newnode = new.Class(node.name, node.doc)
- self._set_infos(node, newnode, parent)
- newnode.bases = [self.visit(child, newnode) for child in node.bases]
- newnode.body = [self.visit(child, newnode) for child in node.code.nodes]
- return newnode
-
- def visit_compare(self, node, parent):
- """visit a Compare node by returning a fresh instance of it"""
- newnode = new.Compare()
- self._set_infos(node, newnode, parent)
- newnode.left = self.visit(node.expr, newnode)
- newnode.ops = [(op, self.visit(child, newnode)) for op, child in node.ops]
- return newnode
-
- def visit_comprehension(self, node, parent):
- """visit a Comprehension node by returning a fresh instance of it"""
- newnode = new.Comprehension()
- self._set_infos(node, newnode, parent)
- self.asscontext = "Ass"
- newnode.target = self.visit(node.assign, newnode)
- self.asscontext = None
- if hasattr(node, 'list'):# ListCompFor
- iters = node.list
- else:# GenExprFor
- iters = node.iter
- newnode.iter = self.visit(iters, newnode)
- if node.ifs:
- newnode.ifs = [self.visit(iff.test, newnode) for iff in node.ifs]
- else:
- newnode.ifs = []
- return newnode
-
- def visit_decorators(self, node, parent):
- """visit a Decorators node by returning a fresh instance of it"""
- newnode = new.Decorators()
- self._set_infos(node, newnode, parent)
- newnode.nodes = [self.visit(child, newnode) for child in node.nodes]
- return newnode
-
- def visit_delattr(self, node, parent):
- """visit a DelAttr node by returning a fresh instance of it"""
- newnode = new.DelAttr()
- self._set_infos(node, newnode, parent)
- newnode.expr = self.visit(node.expr, newnode)
- newnode.attrname = node.attrname
- return newnode
-
- def visit_delname(self, node, parent):
- """visit a DelName node by returning a fresh instance of it"""
- newnode = new.DelName()
- self._set_infos(node, newnode, parent)
- newnode.name = node.name
- self._save_assignment(newnode) # ???
- return newnode
-
- def visit_dict(self, node, parent):
- """visit a Dict node by returning a fresh instance of it"""
- newnode = new.Dict()
- self._set_infos(node, newnode, parent)
- newnode.items = [(self.visit(key, newnode), self.visit(value, newnode))
- for (key, value) in node.items]
- return newnode
-
- def visit_discard(self, node, parent):
- """visit a Discard node by returning a fresh instance of it"""
- newnode = new.Discard()
- if sys.version_info >= (2, 4) and node.lineno is None:
- # ignore dummy Discard introduced when a statement
- # is ended by a semi-colon: remove it at the end of rebuilding
- # however, it does also happen in regular Discard nodes on 2.3
- self._remove_nodes.append((newnode, parent))
- self._set_infos(node, newnode, parent)
- self.asscontext = "Dis"
- newnode.value = self.visit(node.expr, newnode)
- self.asscontext = None
- return newnode
-
- def visit_excepthandler(self, node, parent):
- """visit an ExceptHandler node by returning a fresh instance of it"""
- newnode = new.ExceptHandler()
- self._set_infos(node, newnode, parent)
- newnode.type = self.visit(node.type, newnode)
- newnode.name = self.visit(node.name, newnode)
- newnode.body = [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 = new.Exec()
- self._set_infos(node, newnode, parent)
- newnode.expr = self.visit(node.expr, newnode)
- newnode.globals = self.visit(node.locals, newnode)
- newnode.locals = self.visit(node.globals, newnode)
- return newnode
-
- def visit_extslice(self, node, parent):
- """visit an ExtSlice node by returning a fresh instance of it"""
- newnode = new.ExtSlice()
- self._set_infos(node, newnode, parent)
- newnode.dims = [self.visit(dim, newnode) for dim in node.subs]
- return newnode
-
- def visit_for(self, node, parent):
- """visit a For node by returning a fresh instance of it"""
- newnode = new.For()
- self._set_infos(node, newnode, parent)
- self.asscontext = "Ass"
- newnode.target = self.visit(node.assign, newnode)
- self.asscontext = None
- newnode.iter = self.visit(node.list, newnode)
- newnode.body = [self.visit(child, newnode) for child in node.body.nodes]
- newnode.orelse = self._init_else_node(node, newnode)
- return newnode
-
- def visit_from(self, node, parent):
- """visit a From node by returning a fresh instance of it"""
- newnode = new.From(node.modname, node.names)
- self._set_infos(node, newnode, parent)
- self._store_from_node(newnode)
- return newnode
-
- def _visit_function(self, node, parent):
- """visit a Function node by returning a fresh instance of it"""
- newnode = new.Function(node.name, node.doc)
- self._set_infos(node, newnode, parent)
- if hasattr(node, 'decorators'):
- newnode.decorators = self.visit(node.decorators, newnode)
- newnode.args = self.visit_arguments(node, newnode)
- newnode.body = [self.visit(child, newnode) for child in node.code.nodes]
- return newnode
-
- def visit_genexpr(self, node, parent):
- """visit a GenExpr node by returning a fresh instance of it"""
- newnode = new.GenExpr()
- self._set_infos(node, newnode, parent)
- # remove GenExprInner node
- newnode.elt = self.visit(node.code.expr, newnode)
- newnode.generators = [self.visit(n, newnode) for n in node.code.quals]
- return newnode
-
- def visit_getattr(self, node, parent):
- """visit a Getattr node by returning a fresh instance of it"""
- newnode = new.Getattr()
- self._set_infos(node, newnode, parent)
- if self.asscontext == "Aug":
- return self.visit_assattr(node, parent)
- newnode.expr = self.visit(node.expr, newnode)
- newnode.attrname = node.attrname
- return newnode
-
- def visit_if(self, node, parent):
- """visit an If node by returning a fresh instance of it"""
- newnode = subnode = new.If()
- self._set_infos(node, newnode, parent)
- test, body = node.tests[0]
- newnode.test = self.visit(test, newnode)
- newnode.body = [self.visit(child, newnode) for child in body.nodes]
- for test, body in node.tests[1:]:# this represents 'elif'
- # create successively If nodes and put it in orelse of the previous
- subparent, subnode = subnode, new.If()
- subnode.parent = subparent
- subnode.fromlineno = test.fromlineno
- subnode.tolineno = body.nodes[-1].tolineno
- subnode.blockstart_tolineno = test.tolineno
- subnode.test = self.visit(test, subnode)
- subnode.body = [self.visit(child, subnode) for child in body.nodes]
- subparent.orelse = [subnode]
- # the last subnode gets the else block:
- subnode.orelse = self._init_else_node(node, subnode)
- return newnode
-
- def visit_ifexp(self, node, parent):
- """visit an IfExp node by returning a fresh instance of it"""
- newnode = new.IfExp()
- self._set_infos(node, newnode, parent)
- newnode.test = self.visit(node.test, newnode)
- newnode.body = [self.visit(child, newnode) for child in node.body]
- newnode.orelse = self.visit(node.orelse, newnode)
- return newnode
-
- def visit_import(self, node, parent):
- """visit an Import node by returning a fresh instance of it"""
- newnode = new.Import()
- self._set_infos(node, newnode, parent)
- newnode.names = node.names
- self._save_import_locals(newnode)
- return newnode
-
- def visit_index(self, node, parent):
- """visit an Index node by returning a fresh instance of it"""
- newnode = new.Index()
- self._set_infos(node, newnode, parent)
- newnode.value = self.visit(node.subs[0], newnode)
- return newnode
-
- def visit_keyword(self, node, parent):
- """visit a Keyword node by returning a fresh instance of it"""
- newnode = new.Keyword()
- self._set_infos(node, newnode, parent)
- newnode.value = self.visit(node.expr, newnode)
- newnode.arg = node.name
- return newnode
-
- def visit_lambda(self, node, parent):
- """visit a Lambda node by returning a fresh instance of it"""
- newnode = new.Lambda()
- self._set_infos(node, newnode, parent)
- newnode.body = self.visit(node.code, newnode)
- newnode.args = self.visit_arguments(node, newnode)
- return newnode
-
- def visit_list(self, node, parent):
- """visit a List node by returning a fresh instance of it"""
- newnode = new.List()
- self._set_infos(node, newnode, parent)
- newnode.elts = [self.visit(child, newnode) for child in node.nodes]
- return newnode
-
- def visit_listcomp(self, node, parent):
- """visit a ListComp node by returning a fresh instance of it"""
- newnode = new.ListComp()
- self._set_infos(node, newnode, parent)
- newnode.elt = self.visit(node.expr, newnode)
- newnode.generators = [self.visit(child, newnode) for child in node.quals]
- return newnode
-
- def visit_module(self, node, modname, package):
- """visit a Module node by returning a fresh instance of it"""
- newnode = new.Module(modname, node.doc)
- newnode.package = package
- self._set_infos(node, newnode, None)
- self._remove_nodes = [] # list of ';' Discard nodes to be removed
- newnode.body = [self.visit(child, newnode) for child in node.node.nodes]
- for discard, d_parent in self._remove_nodes:
- d_parent.child_sequence(discard).remove(discard)
- return newnode
-
- def visit_name(self, node, parent):
- """visit a Name node by returning a fresh instance of it"""
- if node.name in CONST_NAME_TRANSFORMS:
- newnode = new.Const(CONST_NAME_TRANSFORMS[node.name])
- self._set_infos(node, newnode, parent)
- return newnode
- if self.asscontext == "Aug":
- return self.visit_assname(node, parent)
- newnode = new.Name()
- self._set_infos(node, newnode, parent)
- newnode.name = node.name
- return newnode
-
- def visit_print(self, node, parent):
- """visit a Print node by returning a fresh instance of it"""
- newnode = new.Print()
- self._set_infos(node, newnode, parent)
- newnode.dest = self.visit(node.dest, newnode)
- newnode.values = [self.visit(child, newnode) for child in node.nodes]
- newnode.nl = False
- return newnode
-
- def visit_printnl(self, node, parent):
- newnode = self.visit_print(node, parent)
- self._set_infos(node, newnode, parent)
- newnode.nl = True
- return newnode
-
- def visit_raise(self, node, parent):
- """visit a Raise node by returning a fresh instance of it"""
- newnode = new.Raise()
- self._set_infos(node, newnode, parent)
- newnode.exc = self.visit(node.expr1, newnode)
- newnode.inst = self.visit(node.expr2, newnode)
- newnode.tback = self.visit(node.expr3, newnode)
- return newnode
-
- def visit_return(self, node, parent):
- """visit a Return node by returning a fresh instance of it"""
- newnode = new.Return()
- self._set_infos(node, newnode, parent)
- newnode.value = self.visit(_filter_none(node.value), newnode)
- return newnode
-
- def visit_slice(self, node, parent):
- """visit a compiler.Slice by returning a astng.Subscript"""
- # compiler.Slice nodes represent astng.Subscript nodes
- # the astng.Subscript node has a astng.Slice node as child
- if node.flags == 'OP_DELETE':
- delnode = self._check_del_node(node, parent, [node])
- if delnode:
- return delnode
- newnode = new.Subscript()
- self._set_infos(node, newnode, parent)
- newnode.value = self.visit(node.expr, newnode)
- newnode.slice = self.visit_sliceobj(node, newnode, slice=True)
- return newnode
-
- def visit_sliceobj(self, node, parent, slice=False):
- """visit a Slice or Sliceobj; transform Sliceobj into a astng.Slice"""
- newnode = new.Slice()
- self._set_infos(node, newnode, parent)
- if slice:
- subs = [node.lower, node.upper, None]
- else:
- subs = node.nodes
- if len(subs) == 2:
- subs.append(None)
- newnode.lower = self.visit(_filter_none(subs[0]), newnode)
- newnode.upper = self.visit(_filter_none(subs[1]), newnode)
- newnode.step = self.visit(_filter_none(subs[2]), newnode)
- return newnode
-
- def visit_subscript(self, node, parent):
- """visit a Subscript node by returning a fresh instance of it"""
- if node.flags == 'OP_DELETE':
- delnode = self._check_del_node(node, parent, [node])
- if delnode:
- return delnode
- newnode = new.Subscript()
- self._set_infos(node, newnode, parent)
- self.asscontext, asscontext = None, self.asscontext
- newnode.value = self.visit(node.expr, newnode)
- if [n for n in node.subs if isinstance(n, Sliceobj)]:
- if len(node.subs) == 1: # Sliceobj -> new.Slice
- newnode.slice = self.visit_sliceobj(node.subs[0], newnode)
- else: # ExtSlice
- newnode.slice = self.visit_extslice(node, newnode)
- else: # Index
- newnode.slice = self.visit_index(node, newnode)
- self.asscontext = asscontext
- return newnode
-
- def visit_tryexcept(self, node, parent):
- """visit a TryExcept node by returning a fresh instance of it"""
- newnode = new.TryExcept()
- self._set_infos(node, newnode, parent)
- newnode.body = [self.visit(child, newnode) for child in node.body.nodes]
- newnode.handlers = [self._visit_excepthandler(newnode, values)
- for values in node.handlers]
- newnode.orelse = self._init_else_node(node, newnode)
- return newnode
-
- def _visit_excepthandler(self, parent, values):
- """build an ExceptHandler node from given values and visit children"""
- newnode = new.ExceptHandler()
- newnode.parent = parent
- exctype, excobj, body = values
- if exctype and exctype.lineno:
- newnode.fromlineno = exctype.lineno
- else:
- newnode.fromlineno = body.nodes[0].fromlineno - 1
- newnode.tolineno = body.nodes[-1].tolineno
- if excobj:
- newnode.blockstart_tolineno = excobj.tolineno
- elif exctype:
- newnode.blockstart_tolineno = exctype.tolineno
- else:
- newnode.blockstart_tolineno = newnode.fromlineno
- newnode.type = self.visit(exctype, newnode)
- self.asscontext = "Ass"
- newnode.name = self.visit(excobj, newnode)
- self.asscontext = None
- newnode.body = [self.visit(child, newnode) for child in body.nodes]
- return newnode
-
- def visit_tryfinally(self, node, parent):
- """visit a TryFinally node by returning a fresh instance of it"""
- newnode = new.TryFinally()
- self._set_infos(node, newnode, parent)
- newnode.body = [self.visit(child, newnode) for child in node.body.nodes]
- newnode.finalbody = [self.visit(n, newnode) for n in node.final.nodes]
- return newnode
-
- def visit_tuple(self, node, parent):
- """visit a Tuple node by returning a fresh instance of it"""
- newnode = new.Tuple()
- self._set_infos(node, newnode, parent)
- newnode.elts = [self.visit(child, newnode) for child in node.nodes]
- return newnode
-
- def visit_unaryop(self, node, parent):
- """visit an UnaryOp node by returning a fresh instance of it"""
- newnode = new.UnaryOp()
- self._set_infos(node, newnode, parent)
- newnode.operand = self.visit(node.expr, newnode)
- newnode.op = UnaryOp_OP_CLASSES[node.__class__]
- return newnode
-
- def visit_while(self, node, parent):
- """visit a While node by returning a fresh instance of it"""
- newnode = new.While()
- self._set_infos(node, newnode, parent)
- newnode.test = self.visit(node.test, newnode)
- newnode.body = [self.visit(child, newnode) for child in node.body.nodes]
- newnode.orelse = self._init_else_node(node, newnode)
- return newnode
-
- def visit_with(self, node, parent):
- """visit a With node by returning a fresh instance of it"""
- newnode = new.With()
- self._set_infos(node, newnode, parent)
- newnode.expr = self.visit(node.expr, newnode)
- newnode.vars = self.visit(node.vars, newnode)
- newnode.body = [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"""
- discard = self._check_discard(node, parent)
- if discard:
- return discard
- newnode = new.Yield()
- self._set_infos(node, newnode, parent)
- newnode.value = self.visit(node.value, newnode)
- return newnode
-
- def _check_discard(self, node, parent):
- """check if we introduced already a discard node."""
- # XXX we should maybe use something else then 'asscontext' here
- if self.asscontext is None:
- self.asscontext = 'Dis'
- newnode = new.Discard()
- self._set_infos(node, newnode, parent)
- newnode.value = self.visit(node, newnode)
- self.asscontext = None
- return newnode
- return False
-
diff --git a/builder.py b/builder.py
index 9efb4e56..7aa0f247 100644
--- a/builder.py
+++ b/builder.py
@@ -41,15 +41,10 @@ from logilab.astng.raw_building import build_module, object_build_class, \
object_build_methoddescriptor, attach_const_node, attach_import_node
from logilab.astng.manager import ASTNGManager
-try:
- from _ast import PyCF_ONLY_AST
- def parse(string):
- return compile(string, "<string>", 'exec', PyCF_ONLY_AST)
- from logilab.astng._nodes_ast import TreeRebuilder
-except ImportError, exc:
- from compiler import parse
- from logilab.astng import patchcomptransformer
- from logilab.astng._nodes_compiler import TreeRebuilder
+from _ast import PyCF_ONLY_AST
+def parse(string):
+ return compile(string, "<string>", 'exec', PyCF_ONLY_AST)
+from logilab.astng._nodes_ast import TreeRebuilder
# ast NG builder ##############################################################
diff --git a/patchcomptransformer.py b/patchcomptransformer.py
deleted file mode 100644
index b4f448d4..00000000
--- a/patchcomptransformer.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU Lesser 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser 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.
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-# copyright 2003-2010 Sylvain Thenault, all rights reserved.
-# contact mailto:thenault@gmail.com
-#
-# This file is part of logilab-astng.
-#
-# logilab-astng is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by the
-# Free Software Foundation, either version 2.1 of the License, or (at your
-# option) any later version.
-#
-# logilab-astng 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 Lesser General Public License
-# for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with logilab-astng. If not, see <http://www.gnu.org/licenses/>.
-"""Monkey patch compiler.transformer to fix line numbering bugs
-
-"""
-# TODO : move this module to _nodes_compiler
-
-from types import TupleType
-from token import DEDENT
-from compiler import transformer
-
-import compiler.ast as nodes
-
-def fromto_lineno(asttuple):
- """return the minimum and maximum line number of the given ast tuple"""
- return from_lineno(asttuple), to_lineno(asttuple)
-
-def from_lineno(asttuple):
- """return the minimum line number of the given ast tuple"""
- while type(asttuple[1]) is TupleType:
- asttuple = asttuple[1]
- return asttuple[2]
-
-def to_lineno(asttuple):
- """return the maximum line number of the given ast tuple"""
- while type(asttuple[1]) is TupleType:
- for i in xrange(len(asttuple) - 1, 0, -1):
- if asttuple[i][0] != DEDENT:
- asttuple = asttuple[i]
- break
- else:
- raise Exception()
- return asttuple[2]
-
-def fix_lineno(node, fromast, toast=None, blockast=None):
- if getattr(node, 'fromlineno', None) is not None:
- return node
- if isinstance(node, nodes.Stmt):
- return node
- if toast is None or toast is fromast:
- node.fromlineno, node.tolineno = fromto_lineno(fromast)
- else:
- node.fromlineno, node.tolineno = from_lineno(fromast), to_lineno(toast)
- if blockast:
- node.blockstart_tolineno = to_lineno(blockast)
- return node
-
-BaseTransformer = transformer.Transformer
-
-COORD_MAP = {
- # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
- 'if': 0,
- # 'while' test ':' suite ['else' ':' suite]
- 'while': 1,
- # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
- 'for': 3,
- # 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
- 'try': 0,
- # | 'try' ':' suite 'finally' ':' suite
- # XXX with
- }
-
-def fixlineno_wrap(function, stype):
- def fixlineno_wrapper(self, nodelist):
- node = function(self, nodelist)
- try:
- blockstart_idx = COORD_MAP[stype]
- except KeyError:
- return fix_lineno(node, nodelist[0], nodelist[-1])
- else:
- return fix_lineno(node, nodelist[0], nodelist[-1], nodelist[blockstart_idx])
- return fixlineno_wrapper
-
-class ASTNGTransformer(BaseTransformer):
- """overrides transformer for a better source line number handling"""
- def com_NEWLINE(self, *args):
- # A ';' at the end of a line can make a NEWLINE token appear
- # here, Render it harmless. (genc discards ('discard',
- # ('const', xxxx)) Nodes)
- lineno = args[0][1]
- # don't put fromlineno/tolineno on Const None to mark it as dynamically
- # added, without "physical" reference in the source
- n = nodes.Discard(nodes.Const(None))
- n.fromlineno = n.tolineno = lineno
- return n
-
- def com_node(self, node):
- res = self._dispatch[node[0]](node[1:])
- return fix_lineno(res, node)
-
- def com_assign(self, node, assigning):
- res = BaseTransformer.com_assign(self, node, assigning)
- return fix_lineno(res, node)
-
- def com_apply_trailer(self, primaryNode, nodelist):
- node = BaseTransformer.com_apply_trailer(self, primaryNode, nodelist)
- return fix_lineno(node, nodelist)
-
- def funcdef(self, nodelist):
- node = BaseTransformer.funcdef(self, nodelist)
- if getattr(node, 'decorators', None) is not None:
- fix_lineno(node.decorators, nodelist[0])
- return fix_lineno(node, nodelist[-5], nodelist[-1], nodelist[-3])
-
- def lambdef(self, nodelist):
- node = BaseTransformer.lambdef(self, nodelist)
- return fix_lineno(node, nodelist[1], nodelist[-1])
-
- def classdef(self, nodelist):
- node = BaseTransformer.classdef(self, nodelist)
- return fix_lineno(node, nodelist[0], nodelist[-1], nodelist[-2])
-
- def file_input(self, nodelist):
- node = BaseTransformer.file_input(self, nodelist)
- if node.node.nodes:
- node.tolineno = node.node.nodes[-1].tolineno
- else:
- node.tolineno = 0
- return node
-
-# wrap *_stmt methods
-for name in dir(BaseTransformer):
- if name.endswith('_stmt') and not (name in ('com_stmt',
- 'com_append_stmt')
- or name in ASTNGTransformer.__dict__):
- setattr(BaseTransformer, name,
- fixlineno_wrap(getattr(BaseTransformer, name), name[:-5]))
-
-transformer.Transformer = ASTNGTransformer
-
diff --git a/rebuilder.py b/rebuilder.py
index 526cb4c1..de7ca375 100644
--- a/rebuilder.py
+++ b/rebuilder.py
@@ -75,15 +75,9 @@ REDIRECT = {'arguments': 'Arguments',
'Invert': 'UnaryOp'
}
-import sys
-if sys.version_info >= (2, 4):
- _key_func = lambda node: node.fromlineno
- def sort_locals(my_list):
- my_list.sort(key=_key_func)
-else:
- _cmp_nodes = lambda x, y: cmp(x.fromlineno, y.fromlineno)
- def sort_locals(my_list):
- my_list.sort(_cmp_nodes)
+_key_func = lambda node: node.fromlineno
+def sort_locals(my_list):
+ my_list.sort(key=_key_func)
class RebuildVisitor(object):
"""Visitor to transform an AST to an ASTNG
diff --git a/test/unittest_builder.py b/test/unittest_builder.py
index 7c78a3b8..20fd587f 100644
--- a/test/unittest_builder.py
+++ b/test/unittest_builder.py
@@ -121,8 +121,6 @@ class FromToLineNoTC(TestCase):
self.assertEqual(return_.tolineno, 18)
def test_decorated_function_lineno(self):
- if sys.version_info < (2, 4):
- self.skipTest('require python >=2.4')
astng = builder.ASTNGBuilder().string_build('''
@decorator
def function(
@@ -229,8 +227,6 @@ finally:
def test_try_finally_25_lineno(self):
- if sys.version_info < (2, 5):
- self.skipTest('require python >= 2.5')
astng = builder.ASTNGBuilder().string_build('''
try:
print (a)
@@ -248,8 +244,6 @@ finally:
def test_with_lineno(self):
- if sys.version_info < (2, 5):
- self.skipTest('require python >=2.5')
astng = builder.ASTNGBuilder().string_build('''
from __future__ import with_statement
with file("/tmp/pouet") as f:
@@ -332,10 +326,7 @@ class BuilderTC(TestCase):
fclass = builtin_astng['OSError']
# things like OSError.strerror are now (2.5) data descriptors on the
# class instead of entries in the __dict__ of an instance
- if sys.version_info < (2, 5):
- container = fclass.instance_attrs
- else:
- container = fclass
+ container = fclass
self.assert_('errno' in container)
self.assert_('strerror' in container)
self.assert_('filename' in container)
@@ -449,17 +440,16 @@ def global_no_effect():
self.assert_('close' in fclass)
break
- if sys.version_info >= (2, 4):
- def test_gen_expr_var_scope(self):
- data = 'l = list(n for n in range(10))\n'
- astng = self.builder.string_build(data, __name__, __file__)
- # n unavailable outside gen expr scope
- self.failIf('n' in astng)
- # test n is inferable anyway
- n = get_name_node(astng, 'n')
- self.failIf(n.scope() is astng)
- self.failUnlessEqual([i.__class__ for i in n.infer()],
- [YES.__class__])
+ def test_gen_expr_var_scope(self):
+ data = 'l = list(n for n in range(10))\n'
+ astng = self.builder.string_build(data, __name__, __file__)
+ # n unavailable outside gen expr scope
+ self.failIf('n' in astng)
+ # test n is inferable anyway
+ n = get_name_node(astng, 'n')
+ self.failIf(n.scope() is astng)
+ self.failUnlessEqual([i.__class__ for i in n.infer()],
+ [YES.__class__])
class FileBuildTC(TestCase):
diff --git a/test/unittest_inference.py b/test/unittest_inference.py
index 370d9dd0..c10660d9 100644
--- a/test/unittest_inference.py
+++ b/test/unittest_inference.py
@@ -326,12 +326,9 @@ def f():
nie = error.infered()[0]
self.assertIsInstance(nie, nodes.Class)
nie_ancestors = [c.name for c in nie.ancestors()]
- if sys.version_info < (2, 5):
- self.failUnlessEqual(nie_ancestors, ['RuntimeError', 'StandardError', 'Exception'])
- elif sys.version_info < (3, 0):
+ if sys.version_info < (3, 0):
self.failUnlessEqual(nie_ancestors, ['RuntimeError', 'StandardError', 'Exception', 'BaseException', 'object'])
else:
-
self.failUnlessEqual(nie_ancestors, ['RuntimeError', 'Exception', 'BaseException', 'object'])
def test_except_inference(self):
@@ -468,13 +465,12 @@ class Warning(Warning):
ancestor = ancestors.next()
self.failUnlessEqual(ancestor.name, 'Exception')
self.failUnlessEqual(ancestor.root().name, EXC_MODULE)
- if sys.version_info >= (2, 5):
- ancestor = ancestors.next()
- self.failUnlessEqual(ancestor.name, 'BaseException')
- self.failUnlessEqual(ancestor.root().name, EXC_MODULE)
- ancestor = ancestors.next()
- self.failUnlessEqual(ancestor.name, 'object')
- self.failUnlessEqual(ancestor.root().name, BUILTINS_NAME)
+ ancestor = ancestors.next()
+ self.failUnlessEqual(ancestor.name, 'BaseException')
+ self.failUnlessEqual(ancestor.root().name, EXC_MODULE)
+ ancestor = ancestors.next()
+ self.failUnlessEqual(ancestor.name, 'object')
+ self.failUnlessEqual(ancestor.root().name, BUILTINS_NAME)
self.failUnlessRaises(StopIteration, ancestors.next)
def test_qqch(self):
@@ -660,8 +656,6 @@ print ([(d,e) for e,d in ([1,2], [3,4])])
def test_simple_for_genexpr(self):
- if sys.version_info < (2, 4):
- return
code = '''
print ((d,e) for e,d in ([1,2], [3,4]))
'''
@@ -676,7 +670,7 @@ print ((d,e) for e,d in ([1,2], [3,4]))
code = '''
help()
'''
- # XXX failing with python > 2.3 since __builtin__.help assignment has
+ # XXX failing since __builtin__.help assignment has
# been moved into a function...
astng = builder.string_build(code, __name__, __file__)
node = get_name_node(astng, 'help', -1)
@@ -694,14 +688,8 @@ open("toto.txt")
node = get_name_node(astng, 'open', -1)
infered = list(node.infer())
self.failUnlessEqual(len(infered), 1)
- if sys.version_info < (2, 5):
- # On python < 2.5 open and file are the same thing.
- self.assertIsInstance(infered[0], nodes.Class)
- self.failUnlessEqual(infered[0].name, 'file')
- else:
- # On python >= 2.5 open is a builtin function.
- self.assertIsInstance(infered[0], nodes.Function)
- self.failUnlessEqual(infered[0].name, 'open')
+ self.assertIsInstance(infered[0], nodes.Function)
+ self.failUnlessEqual(infered[0].name, 'open')
def test_callfunc_context_func(self):
code = '''
@@ -732,8 +720,6 @@ un = mirror(1)
self.failUnlessEqual(infered[0].value, 1)
def test_factory_method(self):
- if sys.version_info < (2, 4):
- self.skipTest('this test require python >= 2.4')
code = '''
class Super(object):
@classmethod
@@ -923,8 +909,6 @@ def f(x):
sys.stderr = sys.__stderr__
def test_python25_relative_import(self):
- if sys.version_info < (2, 5):
- self.skipTest('require py >= 2.5')
data = "from ...common import date; print (date)"
# !! FIXME also this relative import would not work 'in real' (no __init__.py in test/)
# the test works since we pretend we have a package by passing the full modname
@@ -934,8 +918,6 @@ def f(x):
self.assertEqual(infered.name, 'logilab.common.date')
def test_python25_no_relative_import(self):
- if sys.version_info < (2, 5):
- self.skipTest('require py >= 2.5')
fname = join(abspath(dirname(__file__)), 'regrtest_data', 'package', 'absimport.py')
astng = builder.file_build(fname, 'absimport')
self.failUnless(astng.absolute_import_activated(), True)
diff --git a/test/unittest_lookup.py b/test/unittest_lookup.py
index e6819236..e0d66904 100644
--- a/test/unittest_lookup.py
+++ b/test/unittest_lookup.py
@@ -163,8 +163,6 @@ if x > 0:
self.assertEqual(len(xnames[2].lookup('x')[1]), 2)
def test_list_comps(self):
- if sys.version_info < (2, 4):
- self.skipTest('this test require python >= 2.4')
astng = builder.string_build("""
print ([ i for i in range(10) ])
print ([ i for i in range(10) ])
@@ -278,8 +276,6 @@ def initialize(linter):
def test_decorator_arguments_lookup(self):
- if sys.version_info < (2, 4):
- self.skipTest('this test require python >= 2.4')
code = '''
def decorator(value):
def wrapper(function):
@@ -303,8 +299,6 @@ class foo:
def test_inner_decorator_member_lookup(self):
- if sys.version_info < (2, 4):
- self.skipTest('this test require python >= 2.4')
code = '''
class FileA:
def decorator(bla):
@@ -323,8 +317,6 @@ class FileA:
def test_static_method_lookup(self):
- if sys.version_info < (2, 4):
- self.skipTest('this test require python >= 2.4')
code = '''
class FileA:
@staticmethod
diff --git a/test/unittest_nodes.py b/test/unittest_nodes.py
index 40401243..6a9e2dde 100644
--- a/test/unittest_nodes.py
+++ b/test/unittest_nodes.py
@@ -152,8 +152,6 @@ finally:
print ('pouet')
"""
def test_block_range(self):
- if sys.version_info < (2, 5):
- self.skipTest('require python >= 2.5')
# XXX ensure expected values
self.assertEqual(self.astng.body[0].block_range(1), (1, 6))
self.assertEqual(self.astng.body[0].block_range(2), (2, 2))
diff --git a/test/unittest_scoped_nodes.py b/test/unittest_scoped_nodes.py
index 97c2e278..e83b89fc 100644
--- a/test/unittest_scoped_nodes.py
+++ b/test/unittest_scoped_nodes.py
@@ -217,8 +217,6 @@ def f():
self.failUnlessEqual(g.pytype(), '__builtin__.function')
def test_is_method(self):
- if sys.version_info < (2, 4):
- self.skipTest('this test require python >= 2.4')
data = '''
class A:
def meth1(self):