Index: third_party/logilab/astng/node_classes.py |
=================================================================== |
--- third_party/logilab/astng/node_classes.py (revision 292986) |
+++ third_party/logilab/astng/node_classes.py (working copy) |
@@ -1,903 +0,0 @@ |
-# copyright 2003-2011 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/>. |
-"""Module for some node classes. More nodes in scoped_nodes.py |
-""" |
- |
-import sys |
- |
-from logilab.astng import BUILTINS_MODULE |
-from logilab.astng.exceptions import NoDefault |
-from logilab.astng.bases import (NodeNG, Statement, Instance, InferenceContext, |
- _infer_stmts, YES) |
-from logilab.astng.mixins import BlockRangeMixIn, AssignTypeMixin, \ |
- ParentAssignTypeMixin, FromImportMixIn |
- |
- |
-def unpack_infer(stmt, context=None): |
- """recursively generate nodes inferred by the given statement. |
- If the inferred value is a list or a tuple, recurse on the elements |
- """ |
- if isinstance(stmt, (List, Tuple)): |
- for elt in stmt.elts: |
- for infered_elt in unpack_infer(elt, context): |
- yield infered_elt |
- return |
- infered = stmt.infer(context).next() |
- if infered is stmt or infered is YES: |
- yield infered |
- return |
- for infered in stmt.infer(context): |
- for inf_inf in unpack_infer(infered, context): |
- yield inf_inf |
- |
- |
-def are_exclusive(stmt1, stmt2, exceptions=None): |
- """return true if the two given statements are mutually exclusive |
- |
- `exceptions` may be a list of exception names. If specified, discard If |
- branches and check one of the statement is in an exception handler catching |
- one of the given exceptions. |
- |
- 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 branches |
- """ |
- # 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 node in stmt1_parents: |
- # if the common parent is a If or TryExcept statement, look if |
- # nodes are in exclusive branches |
- if isinstance(node, If) and exceptions is None: |
- if (node.locate_child(previous)[1] |
- is not node.locate_child(children[node])[1]): |
- return True |
- elif isinstance(node, TryExcept): |
- c2attr, c2node = node.locate_child(previous) |
- c1attr, c1node = node.locate_child(children[node]) |
- if c1node is not c2node: |
- if ((c2attr == 'body' and c1attr == 'handlers' and children[node].catch(exceptions)) or |
- (c2attr == 'handlers' and c1attr == 'body' and previous.catch(exceptions)) or |
- (c2attr == 'handlers' and c1attr == 'orelse') or |
- (c2attr == 'orelse' and c1attr == 'handlers')): |
- return True |
- elif c2attr == 'handlers' and c1attr == 'handlers': |
- return previous is not children[node] |
- return False |
- previous = node |
- node = node.parent |
- return False |
- |
- |
-class LookupMixIn(object): |
- """Mixin looking up a name in the right scope |
- """ |
- |
- def lookup(self, name): |
- """lookup a variable name |
- |
- return the scope node and the list of assignments associated to the given |
- name according to the scope where it has been found (locals, globals or |
- builtin) |
- |
- The lookup is starting from self's scope. If self is not a frame itself and |
- the name is found in the inner frame locals, statements will be filtered |
- to remove ignorable statements according to self's location |
- """ |
- return self.scope().scope_lookup(self, name) |
- |
- def ilookup(self, name): |
- """infered lookup |
- |
- return an iterator on infered values of the statements returned by |
- the lookup method |
- """ |
- frame, stmts = self.lookup(name) |
- context = InferenceContext() |
- return _infer_stmts(stmts, context, frame) |
- |
- def _filter_stmts(self, stmts, frame, offset): |
- """filter statements to remove ignorable statements. |
- |
- If self is not a frame itself and the name is found in the inner |
- frame locals, statements will be filtered to remove ignorable |
- statements according to self's location |
- """ |
- # if offset == -1, my actual frame is not the inner frame but its parent |
- # |
- # class A(B): pass |
- # |
- # we need this to resolve B correctly |
- if offset == -1: |
- myframe = self.frame().parent.frame() |
- else: |
- myframe = self.frame() |
- if not myframe is frame or self is frame: |
- return stmts |
- mystmt = self.statement() |
- # line filtering if we are in the same frame |
- # |
- # take care node may be missing lineno information (this is the case for |
- # nodes inserted for living objects) |
- if myframe is frame and mystmt.fromlineno is not None: |
- assert mystmt.fromlineno is not None, mystmt |
- mylineno = mystmt.fromlineno + offset |
- else: |
- # disabling lineno filtering |
- mylineno = 0 |
- _stmts = [] |
- _stmt_parents = [] |
- for node in stmts: |
- stmt = node.statement() |
- # line filtering is on and we have reached our location, break |
- if mylineno > 0 and stmt.fromlineno > mylineno: |
- break |
- assert hasattr(node, 'ass_type'), (node, node.scope(), |
- node.scope().locals) |
- ass_type = node.ass_type() |
- |
- if node.has_base(self): |
- break |
- |
- _stmts, done = ass_type._get_filtered_stmts(self, node, _stmts, mystmt) |
- if done: |
- break |
- |
- optional_assign = ass_type.optional_assign |
- if optional_assign and ass_type.parent_of(self): |
- # we are inside a loop, loop var assigment is hidding previous |
- # assigment |
- _stmts = [node] |
- _stmt_parents = [stmt.parent] |
- continue |
- |
- # XXX comment various branches below!!! |
- try: |
- pindex = _stmt_parents.index(stmt.parent) |
- except ValueError: |
- pass |
- else: |
- # we got a parent index, this means the currently visited node |
- # is at the same block level as a previously visited node |
- if _stmts[pindex].ass_type().parent_of(ass_type): |
- # both statements are not at the same block level |
- continue |
- # if currently visited node is following previously considered |
- # assignement and both are not exclusive, we can drop the |
- # previous one. For instance in the following code :: |
- # |
- # if a: |
- # x = 1 |
- # else: |
- # x = 2 |
- # print x |
- # |
- # we can't remove neither x = 1 nor x = 2 when looking for 'x' |
- # of 'print x'; while in the following :: |
- # |
- # x = 1 |
- # x = 2 |
- # print x |
- # |
- # we can remove x = 1 when we see x = 2 |
- # |
- # moreover, on loop assignment types, assignment won't |
- # necessarily be done if the loop has no iteration, so we don't |
- # want to clear previous assigments if any (hence the test on |
- # optional_assign) |
- if not (optional_assign or are_exclusive(_stmts[pindex], node)): |
- del _stmt_parents[pindex] |
- del _stmts[pindex] |
- if isinstance(node, AssName): |
- if not optional_assign and stmt.parent is mystmt.parent: |
- _stmts = [] |
- _stmt_parents = [] |
- elif isinstance(node, DelName): |
- _stmts = [] |
- _stmt_parents = [] |
- continue |
- if not are_exclusive(self, node): |
- _stmts.append(node) |
- _stmt_parents.append(stmt.parent) |
- return _stmts |
- |
-# Name classes |
- |
-class AssName(LookupMixIn, ParentAssignTypeMixin, NodeNG): |
- """class representing an AssName node""" |
- |
- |
-class DelName(LookupMixIn, ParentAssignTypeMixin, NodeNG): |
- """class representing a DelName node""" |
- |
- |
-class Name(LookupMixIn, NodeNG): |
- """class representing a Name node""" |
- |
- |
- |
- |
-##################### node classes ######################################## |
- |
-class Arguments(NodeNG, AssignTypeMixin): |
- """class representing an Arguments node""" |
- _astng_fields = ('args', 'defaults') |
- args = None |
- defaults = None |
- |
- def __init__(self, vararg=None, kwarg=None): |
- self.vararg = vararg |
- self.kwarg = kwarg |
- |
- def _infer_name(self, frame, name): |
- if self.parent is frame: |
- return name |
- return None |
- |
- def format_args(self): |
- """return arguments formatted as string""" |
- result = [_format_args(self.args, self.defaults)] |
- if self.vararg: |
- result.append('*%s' % self.vararg) |
- if self.kwarg: |
- result.append('**%s' % self.kwarg) |
- return ', '.join(result) |
- |
- def default_value(self, argname): |
- """return the default value for an argument |
- |
- :raise `NoDefault`: if there is no default value defined |
- """ |
- i = _find_arg(argname, self.args)[0] |
- if i is not None: |
- idx = i - (len(self.args) - len(self.defaults)) |
- if idx >= 0: |
- return self.defaults[idx] |
- raise NoDefault() |
- |
- def is_argument(self, name): |
- """return True if the name is defined in arguments""" |
- if name == self.vararg: |
- return True |
- if name == self.kwarg: |
- return True |
- return self.find_argname(name, True)[1] is not None |
- |
- def find_argname(self, argname, rec=False): |
- """return index and Name node with given name""" |
- if self.args: # self.args may be None in some cases (builtin function) |
- return _find_arg(argname, self.args, rec) |
- return None, None |
- |
- |
-def _find_arg(argname, args, rec=False): |
- for i, arg in enumerate(args): |
- if isinstance(arg, Tuple): |
- if rec: |
- found = _find_arg(argname, arg.elts) |
- if found[0] is not None: |
- return found |
- elif arg.name == argname: |
- return i, arg |
- return None, None |
- |
- |
-def _format_args(args, defaults=None): |
- values = [] |
- if args is None: |
- return '' |
- if defaults is not None: |
- default_offset = len(args) - len(defaults) |
- for i, arg in enumerate(args): |
- if isinstance(arg, Tuple): |
- values.append('(%s)' % _format_args(arg.elts)) |
- else: |
- values.append(arg.name) |
- if defaults is not None and i >= default_offset: |
- values[-1] += '=' + defaults[i-default_offset].as_string() |
- return ', '.join(values) |
- |
- |
-class AssAttr(NodeNG, ParentAssignTypeMixin): |
- """class representing an AssAttr node""" |
- _astng_fields = ('expr',) |
- expr = None |
- |
-class Assert(Statement): |
- """class representing an Assert node""" |
- _astng_fields = ('test', 'fail',) |
- test = None |
- fail = None |
- |
-class Assign(Statement, AssignTypeMixin): |
- """class representing an Assign node""" |
- _astng_fields = ('targets', 'value',) |
- targets = None |
- value = None |
- |
-class AugAssign(Statement, AssignTypeMixin): |
- """class representing an AugAssign node""" |
- _astng_fields = ('target', 'value',) |
- target = None |
- value = None |
- |
-class Backquote(NodeNG): |
- """class representing a Backquote node""" |
- _astng_fields = ('value',) |
- value = None |
- |
-class BinOp(NodeNG): |
- """class representing a BinOp node""" |
- _astng_fields = ('left', 'right',) |
- left = None |
- right = None |
- |
-class BoolOp(NodeNG): |
- """class representing a BoolOp node""" |
- _astng_fields = ('values',) |
- values = None |
- |
-class Break(Statement): |
- """class representing a Break node""" |
- |
- |
-class CallFunc(NodeNG): |
- """class representing a CallFunc node""" |
- _astng_fields = ('func', 'args', 'starargs', 'kwargs') |
- func = None |
- args = None |
- starargs = None |
- kwargs = None |
- |
- def __init__(self): |
- self.starargs = None |
- self.kwargs = None |
- |
-class Compare(NodeNG): |
- """class representing a Compare node""" |
- _astng_fields = ('left', 'ops',) |
- left = None |
- ops = None |
- |
- def get_children(self): |
- """override get_children for tuple fields""" |
- yield self.left |
- for _, comparator in self.ops: |
- yield comparator # we don't want the 'op' |
- |
- def last_child(self): |
- """override last_child""" |
- # XXX maybe if self.ops: |
- return self.ops[-1][1] |
- #return self.left |
- |
-class Comprehension(NodeNG): |
- """class representing a Comprehension node""" |
- _astng_fields = ('target', 'iter' ,'ifs') |
- target = None |
- iter = None |
- ifs = None |
- |
- optional_assign = True |
- def ass_type(self): |
- return self |
- |
- def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt): |
- """method used in filter_stmts""" |
- if self is mystmt: |
- if isinstance(lookup_node, (Const, Name)): |
- return [lookup_node], True |
- |
- elif self.statement() is mystmt: |
- # original node's statement is the assignment, only keeps |
- # current node (gen exp, list comp) |
- |
- return [node], True |
- |
- return stmts, False |
- |
- |
-class Const(NodeNG, Instance): |
- """represent a constant node like num, str, bool, None, bytes""" |
- |
- def __init__(self, value=None): |
- self.value = value |
- |
- def getitem(self, index, context=None): |
- if isinstance(self.value, basestring): |
- return Const(self.value[index]) |
- raise TypeError('%r (value=%s)' % (self, self.value)) |
- |
- def has_dynamic_getattr(self): |
- return False |
- |
- def itered(self): |
- if isinstance(self.value, basestring): |
- return self.value |
- raise TypeError() |
- |
- def pytype(self): |
- return self._proxied.qname() |
- |
- |
-class Continue(Statement): |
- """class representing a Continue node""" |
- |
- |
-class Decorators(NodeNG): |
- """class representing a Decorators node""" |
- _astng_fields = ('nodes',) |
- nodes = None |
- |
- def __init__(self, nodes=None): |
- self.nodes = nodes |
- |
- def scope(self): |
- # skip the function node to go directly to the upper level scope |
- return self.parent.parent.scope() |
- |
-class DelAttr(NodeNG, ParentAssignTypeMixin): |
- """class representing a DelAttr node""" |
- _astng_fields = ('expr',) |
- expr = None |
- |
- |
-class Delete(Statement, AssignTypeMixin): |
- """class representing a Delete node""" |
- _astng_fields = ('targets',) |
- targets = None |
- |
- |
-class Dict(NodeNG, Instance): |
- """class representing a Dict node""" |
- _astng_fields = ('items',) |
- |
- def __init__(self, items=None): |
- if items is None: |
- self.items = [] |
- else: |
- self.items = [(const_factory(k), const_factory(v)) |
- for k,v in items.iteritems()] |
- |
- def pytype(self): |
- return '%s.dict' % BUILTINS_MODULE |
- |
- def get_children(self): |
- """get children of a Dict node""" |
- # overrides get_children |
- for key, value in self.items: |
- yield key |
- yield value |
- |
- def last_child(self): |
- """override last_child""" |
- if self.items: |
- return self.items[-1][1] |
- return None |
- |
- def itered(self): |
- return self.items[::2] |
- |
- def getitem(self, key, context=None): |
- for i in xrange(0, len(self.items), 2): |
- for inferedkey in self.items[i].infer(context): |
- if inferedkey is YES: |
- continue |
- if isinstance(inferedkey, Const) and inferedkey.value == key: |
- return self.items[i+1] |
- raise IndexError(key) |
- |
- |
-class Discard(Statement): |
- """class representing a Discard node""" |
- _astng_fields = ('value',) |
- value = None |
- |
- |
-class Ellipsis(NodeNG): |
- """class representing an Ellipsis node""" |
- |
- |
-class EmptyNode(NodeNG): |
- """class representing an EmptyNode node""" |
- |
- |
-class ExceptHandler(Statement, AssignTypeMixin): |
- """class representing an ExceptHandler node""" |
- _astng_fields = ('type', 'name', 'body',) |
- type = None |
- name = None |
- body = None |
- |
- def _blockstart_toline(self): |
- if self.name: |
- return self.name.tolineno |
- elif self.type: |
- return self.type.tolineno |
- else: |
- return self.lineno |
- |
- def set_line_info(self, lastchild): |
- self.fromlineno = self.lineno |
- self.tolineno = lastchild.tolineno |
- self.blockstart_tolineno = self._blockstart_toline() |
- |
- def catch(self, exceptions): |
- if self.type is None or exceptions is None: |
- return True |
- for node in self.type.nodes_of_class(Name): |
- if node.name in exceptions: |
- return True |
- |
- |
-class Exec(Statement): |
- """class representing an Exec node""" |
- _astng_fields = ('expr', 'globals', 'locals',) |
- expr = None |
- globals = None |
- locals = None |
- |
- |
-class ExtSlice(NodeNG): |
- """class representing an ExtSlice node""" |
- _astng_fields = ('dims',) |
- dims = None |
- |
-class For(BlockRangeMixIn, AssignTypeMixin, Statement): |
- """class representing a For node""" |
- _astng_fields = ('target', 'iter', 'body', 'orelse',) |
- target = None |
- iter = None |
- body = None |
- orelse = None |
- |
- optional_assign = True |
- def _blockstart_toline(self): |
- return self.iter.tolineno |
- |
- |
-class From(FromImportMixIn, Statement): |
- """class representing a From node""" |
- |
- def __init__(self, fromname, names, level=0): |
- self.modname = fromname |
- self.names = names |
- self.level = level |
- |
-class Getattr(NodeNG): |
- """class representing a Getattr node""" |
- _astng_fields = ('expr',) |
- expr = None |
- |
- |
-class Global(Statement): |
- """class representing a Global node""" |
- |
- def __init__(self, names): |
- self.names = names |
- |
- def _infer_name(self, frame, name): |
- return name |
- |
- |
-class If(BlockRangeMixIn, Statement): |
- """class representing an If node""" |
- _astng_fields = ('test', 'body', 'orelse') |
- test = None |
- body = None |
- orelse = None |
- |
- def _blockstart_toline(self): |
- return self.test.tolineno |
- |
- def block_range(self, lineno): |
- """handle block line numbers range for if statements""" |
- if lineno == self.body[0].fromlineno: |
- return lineno, lineno |
- if lineno <= self.body[-1].tolineno: |
- return lineno, self.body[-1].tolineno |
- return self._elsed_block_range(lineno, self.orelse, |
- self.body[0].fromlineno - 1) |
- |
- |
-class IfExp(NodeNG): |
- """class representing an IfExp node""" |
- _astng_fields = ('test', 'body', 'orelse') |
- test = None |
- body = None |
- orelse = None |
- |
- |
-class Import(FromImportMixIn, Statement): |
- """class representing an Import node""" |
- |
- |
-class Index(NodeNG): |
- """class representing an Index node""" |
- _astng_fields = ('value',) |
- value = None |
- |
- |
-class Keyword(NodeNG): |
- """class representing a Keyword node""" |
- _astng_fields = ('value',) |
- value = None |
- |
- |
-class List(NodeNG, Instance, ParentAssignTypeMixin): |
- """class representing a List node""" |
- _astng_fields = ('elts',) |
- |
- def __init__(self, elts=None): |
- if elts is None: |
- self.elts = [] |
- else: |
- self.elts = [const_factory(e) for e in elts] |
- |
- def pytype(self): |
- return '%s.list' % BUILTINS_MODULE |
- |
- def getitem(self, index, context=None): |
- return self.elts[index] |
- |
- def itered(self): |
- return self.elts |
- |
- |
-class Nonlocal(Statement): |
- """class representing a Nonlocal node""" |
- |
- def __init__(self, names): |
- self.names = names |
- |
- def _infer_name(self, frame, name): |
- return name |
- |
- |
-class Pass(Statement): |
- """class representing a Pass node""" |
- |
- |
-class Print(Statement): |
- """class representing a Print node""" |
- _astng_fields = ('dest', 'values',) |
- dest = None |
- values = None |
- |
- |
-class Raise(Statement): |
- """class representing a Raise node""" |
- exc = None |
- if sys.version_info < (3, 0): |
- _astng_fields = ('exc', 'inst', 'tback') |
- inst = None |
- tback = None |
- else: |
- _astng_fields = ('exc', 'cause') |
- exc = None |
- cause = None |
- |
- def raises_not_implemented(self): |
- if not self.exc: |
- return |
- for name in self.exc.nodes_of_class(Name): |
- if name.name == 'NotImplementedError': |
- return True |
- |
- |
-class Return(Statement): |
- """class representing a Return node""" |
- _astng_fields = ('value',) |
- value = None |
- |
- |
-class Set(NodeNG, Instance, ParentAssignTypeMixin): |
- """class representing a Set node""" |
- _astng_fields = ('elts',) |
- |
- def __init__(self, elts=None): |
- if elts is None: |
- self.elts = [] |
- else: |
- self.elts = [const_factory(e) for e in elts] |
- |
- def pytype(self): |
- return '%s.set' % BUILTINS_MODULE |
- |
- def itered(self): |
- return self.elts |
- |
- |
-class Slice(NodeNG): |
- """class representing a Slice node""" |
- _astng_fields = ('lower', 'upper', 'step') |
- lower = None |
- upper = None |
- step = None |
- |
-class Starred(NodeNG): |
- """class representing a Starred node""" |
- _astng_fields = ('value',) |
- value = None |
- |
- |
-class Subscript(NodeNG): |
- """class representing a Subscript node""" |
- _astng_fields = ('value', 'slice') |
- value = None |
- slice = None |
- |
- |
-class TryExcept(BlockRangeMixIn, Statement): |
- """class representing a TryExcept node""" |
- _astng_fields = ('body', 'handlers', 'orelse',) |
- body = None |
- handlers = None |
- orelse = None |
- |
- def _infer_name(self, frame, name): |
- return name |
- |
- def _blockstart_toline(self): |
- return self.lineno |
- |
- def block_range(self, lineno): |
- """handle block line numbers range for try/except statements""" |
- last = None |
- for exhandler in self.handlers: |
- if exhandler.type and lineno == exhandler.type.fromlineno: |
- return lineno, lineno |
- if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno: |
- return lineno, exhandler.body[-1].tolineno |
- if last is None: |
- last = exhandler.body[0].fromlineno - 1 |
- return self._elsed_block_range(lineno, self.orelse, last) |
- |
- |
-class TryFinally(BlockRangeMixIn, Statement): |
- """class representing a TryFinally node""" |
- _astng_fields = ('body', 'finalbody',) |
- body = None |
- finalbody = None |
- |
- def _blockstart_toline(self): |
- return self.lineno |
- |
- def block_range(self, lineno): |
- """handle block line numbers range for try/finally statements""" |
- child = self.body[0] |
- # py2.5 try: except: finally: |
- if (isinstance(child, TryExcept) and child.fromlineno == self.fromlineno |
- and lineno > self.fromlineno and lineno <= child.tolineno): |
- return child.block_range(lineno) |
- return self._elsed_block_range(lineno, self.finalbody) |
- |
- |
-class Tuple(NodeNG, Instance, ParentAssignTypeMixin): |
- """class representing a Tuple node""" |
- _astng_fields = ('elts',) |
- |
- def __init__(self, elts=None): |
- if elts is None: |
- self.elts = [] |
- else: |
- self.elts = [const_factory(e) for e in elts] |
- |
- def pytype(self): |
- return '%s.tuple' % BUILTINS_MODULE |
- |
- def getitem(self, index, context=None): |
- return self.elts[index] |
- |
- def itered(self): |
- return self.elts |
- |
- |
-class UnaryOp(NodeNG): |
- """class representing an UnaryOp node""" |
- _astng_fields = ('operand',) |
- operand = None |
- |
- |
-class While(BlockRangeMixIn, Statement): |
- """class representing a While node""" |
- _astng_fields = ('test', 'body', 'orelse',) |
- test = None |
- body = None |
- orelse = None |
- |
- def _blockstart_toline(self): |
- return self.test.tolineno |
- |
- def block_range(self, lineno): |
- """handle block line numbers range for for and while statements""" |
- return self. _elsed_block_range(lineno, self.orelse) |
- |
- |
-class With(BlockRangeMixIn, AssignTypeMixin, Statement): |
- """class representing a With node""" |
- _astng_fields = ('expr', 'vars', 'body') |
- expr = None |
- vars = None |
- body = None |
- |
- def _blockstart_toline(self): |
- if self.vars: |
- return self.vars.tolineno |
- else: |
- return self.expr.tolineno |
- |
- |
-class Yield(NodeNG): |
- """class representing a Yield node""" |
- _astng_fields = ('value',) |
- value = None |
- |
-# constants ############################################################## |
- |
-CONST_CLS = { |
- list: List, |
- tuple: Tuple, |
- dict: Dict, |
- set: Set, |
- type(None): Const, |
- } |
- |
-def _update_const_classes(): |
- """update constant classes, so the keys of CONST_CLS can be reused""" |
- klasses = (bool, int, float, complex, str) |
- if sys.version_info < (3, 0): |
- klasses += (unicode, long) |
- if sys.version_info >= (2, 6): |
- klasses += (bytes,) |
- for kls in klasses: |
- CONST_CLS[kls] = Const |
-_update_const_classes() |
- |
-def const_factory(value): |
- """return an astng node for a python value""" |
- # since const_factory is called to evaluate content of container (eg list, |
- # tuple), it may be called with some node as argument that should be left |
- # untouched |
- if isinstance(value, NodeNG): |
- return value |
- try: |
- return CONST_CLS[value.__class__](value) |
- except (KeyError, AttributeError): |
- # some constants (like from gtk._gtk) don't have their class in |
- # CONST_CLS, though we can "assert isinstance(value, tuple(CONST_CLS))" |
- if isinstance(value, tuple(CONST_CLS)): |
- return Const(value) |
- node = EmptyNode() |
- node.object = value |
- return node |