# Copyright (c) 2009-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) # Copyright (c) 2014-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 """Module for some node classes. More nodes in scoped_nodes.py """ import functools import warnings import sys import six from astroid import context as contextmod from astroid import decorators from astroid import exceptions from astroid import inference from astroid.interpreter import runtimeabc from astroid.interpreter import objects from astroid import manager from astroid import protocols from astroid.tree import base from astroid.tree import treeabc from astroid import util raw_building = util.lazy_import('raw_building') BUILTINS = six.moves.builtins.__name__ MANAGER = manager.AstroidManager() # getitem() helpers. _SLICE_SENTINEL = object() def _slice_value(index, context=None): """Get the value of the given slice index.""" if isinstance(index, Const): if isinstance(index.value, (int, type(None))): return index.value elif index is None: return None else: # Try to infer what the index actually is. # Since we can't return all the possible values, # we'll stop at the first possible value. try: inferred = next(index.infer(context=context)) except exceptions.InferenceError: pass else: if isinstance(inferred, Const): if isinstance(inferred.value, (int, type(None))): return inferred.value # Use a sentinel, because None can be a valid # value that this function can return, # as it is the case for unspecified bounds. return _SLICE_SENTINEL def _infer_slice(node, context=None): lower = _slice_value(node.lower, context) upper = _slice_value(node.upper, context) step = _slice_value(node.step, context) if all(elem is not _SLICE_SENTINEL for elem in (lower, upper, step)): return slice(lower, upper, step) raise exceptions.AstroidTypeError( message='Could not infer slice used in subscript', node=node, index=node.parent, context=context) def _container_getitem(instance, elts, index, context=None): """Get a slice or an item, using the given *index*, for the given sequence.""" try: if isinstance(index, Slice): index_slice = _infer_slice(index, context=context) new_cls = instance.__class__() new_cls.elts = elts[index_slice] new_cls.parent = instance.parent return new_cls elif isinstance(index, Const): return elts[index.value] except IndexError: util.reraise(exceptions.AstroidIndexError( message='Index {index!s} out of range', node=instance, index=index, context=context)) except TypeError as exc: util.reraise(exceptions.AstroidTypeError( message='Type error {error!r}', error=exc, node=instance, index=index, context=context)) raise exceptions.AstroidTypeError( 'Could not use %s as subscript index' % index ) @util.register_implementation(treeabc.Statement) class Statement(base.NodeNG): """Statement node adding a few attributes""" is_statement = True def next_sibling(self): """return the next sibling statement""" stmts = self.parent.child_sequence(self) index = stmts.index(self) try: return stmts[index +1] except IndexError: pass def previous_sibling(self): """return the previous sibling statement""" stmts = self.parent.child_sequence(self) index = stmts.index(self) if index >= 1: return stmts[index -1] class AssignedStmtsMixin(object): """Provide an `assigned_stmts` method to classes which inherits it.""" def assigned_stmts(self, node=None, context=None, assign_path=None): """Responsible to return the assigned statement (e.g. not inferred) according to the assignment type. The `assign_path` parameter is used to record the lhs path of the original node. For instance if we want assigned statements for 'c' in 'a, (b,c)', assign_path will be [1, 1] once arrived to the Assign node. The `context` parameter is the current inference context which should be given to any intermediary inference necessary. """ # Inject the current module into assigned_stmts, in order to avoid # circular dependencies between these modules. return protocols.assigned_stmts(self, sys.modules[__name__], node=node, context=context, assign_path=assign_path) # Name classes class BaseAssignName(base.LookupMixIn, base.ParentAssignTypeMixin, AssignedStmtsMixin, base.NodeNG): _other_fields = ('name',) def __init__(self, name=None, lineno=None, col_offset=None, parent=None): self.name = name super(BaseAssignName, self).__init__(lineno, col_offset, parent) infer_lhs = inference.infer_name @util.register_implementation(treeabc.AssignName) class AssignName(BaseAssignName): """class representing an AssignName node""" @util.register_implementation(treeabc.Parameter) class Parameter(BaseAssignName): _astroid_fields = ('default', 'annotation') _other_fields = ('name', ) def __init__(self, name=None, lineno=None, col_offset=None, parent=None): super(Parameter, self).__init__(name=name, lineno=lineno, col_offset=col_offset, parent=parent) def postinit(self, default, annotation): self.default = default self.annotation = annotation @util.register_implementation(treeabc.DelName) class DelName(base.LookupMixIn, base.ParentAssignTypeMixin, base.NodeNG): """class representing a DelName node""" _other_fields = ('name',) def __init__(self, name=None, lineno=None, col_offset=None, parent=None): self.name = name super(DelName, self).__init__(lineno, col_offset, parent) @util.register_implementation(treeabc.Name) class Name(base.LookupMixIn, base.NodeNG): """class representing a Name node""" _other_fields = ('name',) def __init__(self, name=None, lineno=None, col_offset=None, parent=None): self.name = name super(Name, self).__init__(lineno, col_offset, parent) @util.register_implementation(treeabc.Arguments) class Arguments(base.AssignTypeMixin, AssignedStmtsMixin, base.NodeNG): """class representing an Arguments node""" _astroid_fields = ('args', 'vararg', 'kwarg', 'keyword_only', 'positional_only') def __init__(self, parent=None): # We don't want lineno and col_offset from the parent's __init__. super(Arguments, self).__init__(parent=parent) def postinit(self, args, vararg, kwarg, keyword_only, positional_only): self.args = args self.vararg = vararg self.kwarg = kwarg self.keyword_only = keyword_only self.positional_only = positional_only self.positional_and_keyword = self.args + self.positional_only def _infer_name(self, frame, name): if self.parent is frame: return name return None @decorators.cachedproperty def fromlineno(self): # Let the Function's lineno be the lineno for this. if self.parent.fromlineno: return self.parent.fromlineno return super(Arguments, self).fromlineno def format_args(self): """return arguments formatted as string""" result = [] if self.positional_and_keyword: result.append(_format_args(self.positional_and_keyword)) if self.vararg: result.append('*%s' % _format_args((self.vararg, ))) if self.keyword_only: if not self.vararg: result.append('*') result.append(_format_args(self.keyword_only)) if self.kwarg: result.append('**%s' % _format_args((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 """ for place in (self.positional_and_keyword, self.keyword_only): i = _find_arg(argname, place)[0] if i is not None: value = place[i] if not value.default: continue return value.default raise exceptions.NoDefault(func=self.parent, name=argname) def is_argument(self, name): """return True if the name is defined in arguments""" if self.vararg and name == self.vararg.name: return True if self.kwarg and name == self.kwarg.name: return True is_arg = self.find_argname(name, True)[1] is not None is_kwarg = ( self.keyword_only and _find_arg(name, self.keyword_only, True)[1] is not None ) return is_arg or is_kwarg def find_argname(self, argname, rec=False): """return index and Name node with given name""" if self.positional_and_keyword: # self.args may be None in some cases (builtin function) return _find_arg(argname, self.positional_and_keyword, rec) return None, None def get_children(self): """override get_children to skip over None elements in kw_defaults""" for child in super(Arguments, self).get_children(): if child is not None: yield child 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): values = [] if not args: return '' for i, arg in enumerate(args): if isinstance(arg, Tuple): values.append('(%s)' % _format_args(arg.elts)) else: argname = arg.name annotation = arg.annotation if annotation: argname += ':' + annotation.as_string() values.append(argname) default = arg.default if default: values[-1] += '=' + default.as_string() return ', '.join(values) @util.register_implementation(treeabc.Unknown) class Unknown(base.NodeNG): '''This node represents a node in a constructed AST where introspection is not possible. At the moment, it's only used in the args attribute of FunctionDef nodes where function signature introspection failed. ''' def infer(self, context=None, **kwargs): '''Inference on an Unknown node immediately terminates.''' yield util.Uninferable @util.register_implementation(treeabc.AssignAttr) class AssignAttr(base.ParentAssignTypeMixin, AssignedStmtsMixin, base.NodeNG): """class representing an AssignAttr node""" _astroid_fields = ('expr',) _other_fields = ('attrname',) expr = None def __init__(self, attrname=None, lineno=None, col_offset=None, parent=None): self.attrname = attrname super(AssignAttr, self).__init__(lineno, col_offset, parent) def postinit(self, expr=None): self.expr = expr infer_lhs = inference.infer_attribute @util.register_implementation(treeabc.Assert) class Assert(Statement): """class representing an Assert node""" _astroid_fields = ('test', 'fail',) test = None fail = None def postinit(self, test=None, fail=None): self.fail = fail self.test = test @util.register_implementation(treeabc.Assign) class Assign(base.AssignTypeMixin, AssignedStmtsMixin, Statement): """class representing an Assign node""" _astroid_fields = ('targets', 'value',) targets = None value = None def postinit(self, targets=None, value=None): self.targets = targets self.value = value @util.register_implementation(treeabc.AugAssign) class AugAssign(base.AssignTypeMixin, AssignedStmtsMixin, Statement): """class representing an AugAssign node""" _astroid_fields = ('target', 'value') _other_fields = ('op',) target = None value = None def __init__(self, op=None, lineno=None, col_offset=None, parent=None): self.op = op super(AugAssign, self).__init__(lineno, col_offset, parent) def postinit(self, target=None, value=None): self.target = target self.value = value def _infer_augassign(self, context): return inference.infer_augassign(self, nodes=sys.modules[__name__], context=context) def type_errors(self, context=None): """Return a list of TypeErrors which can occur during inference. Each TypeError is represented by a :class:`BinaryOperationError`, which holds the original exception. """ try: results = self._infer_augassign(context=context) return [result for result in results if isinstance(result, util.BadBinaryOperationMessage)] except exceptions.InferenceError: return [] @util.register_implementation(treeabc.Repr) class Repr(base.NodeNG): """class representing a Repr node""" _astroid_fields = ('value',) value = None def postinit(self, value=None): self.value = value @util.register_implementation(treeabc.BinOp) class BinOp(base.NodeNG): """class representing a BinOp node""" _astroid_fields = ('left', 'right') _other_fields = ('op',) left = None right = None def __init__(self, op=None, lineno=None, col_offset=None, parent=None): self.op = op super(BinOp, self).__init__(lineno, col_offset, parent) def postinit(self, left=None, right=None): self.left = left self.right = right def _infer_binop(self, context): return inference.infer_binop(self, nodes=sys.modules[__name__], context=context) def type_errors(self, context=None): """Return a list of TypeErrors which can occur during inference. Each TypeError is represented by a :class:`BadBinaryOperationMessage`, which holds the original exception. """ try: results = self._infer_binop(context=context) return [result for result in results if isinstance(result, util.BadBinaryOperationMessage)] except exceptions.InferenceError: return [] @util.register_implementation(treeabc.BoolOp) class BoolOp(base.NodeNG): """class representing a BoolOp node""" _astroid_fields = ('values',) _other_fields = ('op',) values = None def __init__(self, op=None, lineno=None, col_offset=None, parent=None): self.op = op super(BoolOp, self).__init__(lineno, col_offset, parent) def postinit(self, values=None): self.values = values @util.register_implementation(treeabc.Break) class Break(Statement): """class representing a Break node""" @util.register_implementation(treeabc.Call) class Call(base.NodeNG): """class representing a Call node""" _astroid_fields = ('func', 'args', 'keywords') func = None args = None keywords = None def postinit(self, func=None, args=None, keywords=None): self.func = func self.args = args self.keywords = keywords @property def starargs(self): args = self.args or [] return [arg for arg in args if isinstance(arg, Starred)] @property def kwargs(self): keywords = self.keywords or [] return [keyword for keyword in keywords if keyword.arg is None] @util.register_implementation(treeabc.Compare) class Compare(base.NodeNG): """class representing a Compare node""" _astroid_fields = ('left', 'comparators') _other_fields = ('ops',) left = None def __init__(self, ops, lineno=None, col_offset=None, parent=None): self.comparators = [] self.ops = ops super(Compare, self).__init__(lineno, col_offset, parent) def postinit(self, left=None, comparators=None): self.left = left self.comparators = comparators def get_children(self): """override get_children for tuple fields""" yield self.left for comparator in self.comparators: yield comparator def last_child(self): """override last_child""" return self.comparators[-1] @util.register_implementation(treeabc.Comprehension) class Comprehension(AssignedStmtsMixin, base.NodeNG): """class representing a Comprehension node""" _astroid_fields = ('target', 'iter', 'ifs') target = None iter = None ifs = None def __init__(self, parent=None): self.parent = parent def postinit(self, target=None, iter=None, ifs=None): self.target = target self.iter = iter self.ifs = ifs optional_assign = True def assign_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 @util.register_implementation(treeabc.Const) @util.register_implementation(runtimeabc.BuiltinInstance) class Const(base.NodeNG, objects.BaseInstance): """represent a constant node like num, str, bytes""" _other_fields = ('value',) def __init__(self, value, lineno=None, col_offset=None, parent=None): self.value = value super(Const, self).__init__(lineno, col_offset, parent) def getitem(self, index, context=None): if isinstance(index, Const): index_value = index.value elif isinstance(index, Slice): index_value = _infer_slice(index, context=context) else: raise exceptions.AstroidTypeError( 'Could not use type {} as subscript index'.format(type(index)) ) try: if isinstance(self.value, six.string_types): return Const(self.value[index_value]) if isinstance(self.value, bytes) and six.PY3: # Bytes aren't instances of six.string_types # on Python 3. Also, indexing them should return # integers. return Const(self.value[index_value]) except IndexError as exc: util.reraise(exceptions.AstroidIndexError( message='Index {index!r} out of range', error=exc, node=self, index=index, context=context)) except TypeError as exc: util.reraise(exceptions.AstroidTypeError( message='Type error {error!r}', error=exc, node=self, index=index, context=context)) raise exceptions.AstroidTypeError( '%r (value=%s)' % (self, self.value) ) def has_dynamic_getattr(self): return False def itered(self): if isinstance(self.value, six.string_types): return self.value raise TypeError() def pytype(self): return self._proxied.qname() def bool_value(self): return bool(self.value) @decorators.cachedproperty def _proxied(self): builtins = MANAGER.builtins() return builtins.getattr(type(self.value).__name__)[0] @util.register_implementation(treeabc.NameConstant) class NameConstant(Const): """Represents a builtin singleton, at the moment True, False, None, and NotImplemented. """ # @decorators.cachedproperty # def _proxied(self): # return self # # builtins = MANAGER.builtins() # # return builtins.getattr(str(self.value))[0] @util.register_implementation(treeabc.ReservedName) class ReservedName(base.NodeNG): '''Used in the builtins AST to assign names to singletons.''' _astroid_fields = ('value',) _other_fields = ('name',) def __init__(self, name, lineno=None, col_offset=None, parent=None): self.name = name super(ReservedName, self).__init__(lineno, col_offset, parent) def postinit(self, value): self.value = value @util.register_implementation(treeabc.Continue) class Continue(Statement): """class representing a Continue node""" @util.register_implementation(treeabc.Decorators) class Decorators(base.NodeNG): """class representing a Decorators node""" _astroid_fields = ('nodes',) nodes = None def postinit(self, nodes): self.nodes = nodes @util.register_implementation(treeabc.DelAttr) class DelAttr(base.ParentAssignTypeMixin, base.NodeNG): """class representing a DelAttr node""" _astroid_fields = ('expr',) _other_fields = ('attrname',) expr = None def __init__(self, attrname=None, lineno=None, col_offset=None, parent=None): self.attrname = attrname super(DelAttr, self).__init__(lineno, col_offset, parent) def postinit(self, expr=None): self.expr = expr @util.register_implementation(treeabc.Delete) class Delete(base.AssignTypeMixin, Statement): """class representing a Delete node""" _astroid_fields = ('targets',) targets = None def postinit(self, targets=None): self.targets = targets @util.register_implementation(treeabc.Dict) @util.register_implementation(runtimeabc.BuiltinInstance) class Dict(base.NodeNG, objects.DictInstance): """class representing a Dict node""" _astroid_fields = ('keys', 'values') def __init__(self, lineno=None, col_offset=None, parent=None): self.keys = [] self.values = [] super(Dict, self).__init__(lineno, col_offset, parent) def postinit(self, keys, values): self.keys = keys self.values = values @property def items(self): return list(zip(self.keys, self.values)) def pytype(self): return '%s.dict' % BUILTINS def get_children(self): """get children of a Dict node""" # overrides get_children for key, value in zip(self.keys, self.values): yield key yield value def last_child(self): """override last_child""" if self.values: return self.values[-1] return None def itered(self): return self.keys def getitem(self, lookup_key, context=None): for key, value in zip(self.keys, self.values): # TODO(cpopa): no support for overriding yet, {1:2, **{1: 3}}. if isinstance(key, DictUnpack): try: return value.getitem(lookup_key, context) except (exceptions.AstroidTypeError, exceptions.AstroidIndexError): continue for inferredkey in key.infer(context): if inferredkey is util.Uninferable: continue if isinstance(inferredkey, Const) and isinstance(lookup_key, Const): if inferredkey.value == lookup_key.value: return value raise exceptions.AstroidIndexError(lookup_key) def bool_value(self): return bool(self.keys) @decorators.cachedproperty def _proxied(self): builtins = MANAGER.builtins() return builtins.getattr('dict')[0] @util.register_implementation(treeabc.Expr) class Expr(Statement): """class representing a Expr node""" _astroid_fields = ('value',) value = None def postinit(self, value=None): self.value = value @util.register_implementation(treeabc.Ellipsis) class Ellipsis(base.NodeNG): # pylint: disable=redefined-builtin """class representing an Ellipsis node""" def bool_value(self): return True _INTERPRETER_OBJECT_SENTINEL = object() @util.register_implementation(treeabc.InterpreterObject) class InterpreterObject(base.NodeNG): '''Used for connecting ASTs and runtime objects InterpreterObjects are used in manufactured ASTs that simulate features of real ASTs for inference, usually to handle behavior implemented in the interpreter or in C extensions. They can be used as a "translator" from a non-AST object, or in astroid's parlance, a runtime object to an AST. They mimick their underlying object, which means that an InterpreterObject can act as the object it is wrapping. ''' _other_fields = ('name', 'object') object = _INTERPRETER_OBJECT_SENTINEL def __init__(self, object_=None, name=None, lineno=None, col_offset=None, parent=None): if object_ is not None: self.object = object_ self.name = name super(InterpreterObject, self).__init__(lineno, col_offset, parent) def has_underlying_object(self): return self.object != _INTERPRETER_OBJECT_SENTINEL def __getattr__(self, attr): if self.has_underlying_object(): return getattr(self.object, attr) raise AttributeError(attr) @util.register_implementation(treeabc.ExceptHandler) class ExceptHandler(base.AssignTypeMixin, AssignedStmtsMixin, Statement): """class representing an ExceptHandler node""" _astroid_fields = ('type', 'name', 'body',) type = None name = None body = None def postinit(self, type=None, name=None, body=None): self.type = type self.name = name self.body = body @decorators.cachedproperty def blockstart_tolineno(self): if self.name: return self.name.tolineno elif self.type: return self.type.tolineno else: return self.lineno 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 @util.register_implementation(treeabc.Exec) class Exec(Statement): """class representing an Exec node""" _astroid_fields = ('expr', 'globals', 'locals') expr = None globals = None locals = None def postinit(self, expr=None, globals=None, locals=None): self.expr = expr self.globals = globals self.locals = locals @util.register_implementation(treeabc.ExtSlice) class ExtSlice(base.NodeNG): """class representing an ExtSlice node""" _astroid_fields = ('dims',) dims = None def postinit(self, dims=None): self.dims = dims @util.register_implementation(treeabc.For) class For(base.BlockRangeMixIn, base.AssignTypeMixin, AssignedStmtsMixin, Statement): """class representing a For node""" _astroid_fields = ('target', 'iter', 'body', 'orelse',) target = None iter = None body = None orelse = None def postinit(self, target=None, iter=None, body=None, orelse=None): self.target = target self.iter = iter self.body = body self.orelse = orelse optional_assign = True @decorators.cachedproperty def blockstart_tolineno(self): return self.iter.tolineno @util.register_implementation(treeabc.AsyncFor) class AsyncFor(For): """Asynchronous For built with `async` keyword.""" @util.register_implementation(treeabc.Await) class Await(base.NodeNG): """Await node for the `await` keyword.""" _astroid_fields = ('value', ) value = None def postinit(self, value=None): self.value = value @util.register_implementation(treeabc.ImportFrom) class ImportFrom(base.FilterStmtsMixin, Statement): """class representing a ImportFrom node""" _other_fields = ('modname', 'names', 'level') def __init__(self, fromname, names, level=0, lineno=None, col_offset=None, parent=None): self.modname = fromname self.names = names self.level = level super(ImportFrom, self).__init__(lineno, col_offset, parent) def _infer_name(self, frame, name): return name @util.register_implementation(treeabc.Attribute) class Attribute(base.NodeNG): """class representing a Attribute node""" _astroid_fields = ('expr',) _other_fields = ('attrname',) expr = None def __init__(self, attrname=None, lineno=None, col_offset=None, parent=None): self.attrname = attrname super(Attribute, self).__init__(lineno, col_offset, parent) def postinit(self, expr=None): self.expr = expr @util.register_implementation(treeabc.Global) class Global(Statement): """class representing a Global node""" _other_fields = ('names',) def __init__(self, names, lineno=None, col_offset=None, parent=None): self.names = names super(Global, self).__init__(lineno, col_offset, parent) def _infer_name(self, frame, name): return name @util.register_implementation(treeabc.If) class If(base.BlockRangeMixIn, Statement): """class representing an If node""" _astroid_fields = ('test', 'body', 'orelse') test = None body = None orelse = None def postinit(self, test=None, body=None, orelse=None): self.test = test self.body = body self.orelse = orelse @decorators.cachedproperty def blockstart_tolineno(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) @util.register_implementation(treeabc.IfExp) class IfExp(base.NodeNG): """class representing an IfExp node""" _astroid_fields = ('test', 'body', 'orelse') test = None body = None orelse = None def postinit(self, test=None, body=None, orelse=None): self.test = test self.body = body self.orelse = orelse @util.register_implementation(treeabc.Import) class Import(base.FilterStmtsMixin, Statement): """class representing an Import node""" _other_fields = ('names',) def __init__(self, names=None, lineno=None, col_offset=None, parent=None): self.names = names super(Import, self).__init__(lineno, col_offset, parent) def infer_name_module(self, name): context = contextmod.InferenceContext() context.lookupname = name return self.infer(context, asname=False) def _infer_name(self, frame, name): return name @util.register_implementation(treeabc.Index) class Index(base.NodeNG): """class representing an Index node""" _astroid_fields = ('value',) value = None def postinit(self, value=None): self.value = value @util.register_implementation(treeabc.Keyword) class Keyword(base.NodeNG): """class representing a Keyword node""" _astroid_fields = ('value',) _other_fields = ('arg',) value = None def __init__(self, arg=None, lineno=None, col_offset=None, parent=None): self.arg = arg super(Keyword, self).__init__(lineno, col_offset, parent) def postinit(self, value=None): self.value = value @util.register_implementation(treeabc.List) @util.register_implementation(runtimeabc.BuiltinInstance) class List(base.BaseContainer, AssignedStmtsMixin, objects.BaseInstance): """class representing a List node""" _other_fields = ('ctx',) def __init__(self, ctx=None, lineno=None, col_offset=None, parent=None): self.ctx = ctx super(List, self).__init__(lineno, col_offset, parent) def pytype(self): return '%s.list' % BUILTINS def getitem(self, index, context=None): return _container_getitem(self, self.elts, index) @decorators.cachedproperty def _proxied(self): builtins = MANAGER.builtins() return builtins.getattr('list')[0] @util.register_implementation(treeabc.Nonlocal) class Nonlocal(Statement): """class representing a Nonlocal node""" _other_fields = ('names',) def __init__(self, names, lineno=None, col_offset=None, parent=None): self.names = names super(Nonlocal, self).__init__(lineno, col_offset, parent) def _infer_name(self, frame, name): return name @util.register_implementation(treeabc.Pass) class Pass(Statement): """class representing a Pass node""" @util.register_implementation(treeabc.Print) class Print(Statement): """class representing a Print node""" _astroid_fields = ('dest', 'values',) dest = None values = None def __init__(self, nl=None, lineno=None, col_offset=None, parent=None): self.nl = nl super(Print, self).__init__(lineno, col_offset, parent) def postinit(self, dest=None, values=None): self.dest = dest self.values = values @util.register_implementation(treeabc.Raise) class Raise(Statement): """class representing a Raise node""" exc = None if six.PY2: _astroid_fields = ('exc', 'inst', 'tback') inst = None tback = None def postinit(self, exc=None, inst=None, tback=None): self.exc = exc self.inst = inst self.tback = tback else: _astroid_fields = ('exc', 'cause') exc = None cause = None def postinit(self, exc=None, cause=None): self.exc = exc self.cause = cause 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 @util.register_implementation(treeabc.Return) class Return(Statement): """class representing a Return node""" _astroid_fields = ('value',) value = None def postinit(self, value=None): self.value = value @util.register_implementation(treeabc.Set) @util.register_implementation(runtimeabc.BuiltinInstance) class Set(base.BaseContainer, objects.BaseInstance): """class representing a Set node""" def pytype(self): return '%s.set' % BUILTINS @decorators.cachedproperty def _proxied(self): builtins = MANAGER.builtins() return builtins.getattr('set')[0] @util.register_implementation(treeabc.Slice) class Slice(base.NodeNG): """class representing a Slice node""" _astroid_fields = ('lower', 'upper', 'step') lower = None upper = None step = None def postinit(self, lower=None, upper=None, step=None): self.lower = lower self.upper = upper self.step = step def _wrap_attribute(self, attr): """Wrap the empty attributes of the Slice in a Const node.""" if not attr: return Const(attr, parent=self) return attr @decorators.cachedproperty def _proxied(self): builtins = MANAGER.builtins() return builtins.getattr('slice')[0] def pytype(self): return '%s.slice' % BUILTINS def igetattr(self, attrname, context=None): if attrname == 'start': yield self._wrap_attribute(self.lower) elif attrname == 'stop': yield self._wrap_attribute(self.upper) elif attrname == 'step': yield self._wrap_attribute(self.step) else: for value in self.getattr(attrname, context=context): yield value def getattr(self, attrname, context=None): return self._proxied.getattr(attrname, context) @util.register_implementation(treeabc.Starred) class Starred(base.ParentAssignTypeMixin, AssignedStmtsMixin, base.NodeNG): """class representing a Starred node""" _astroid_fields = ('value',) _other_fields = ('ctx', ) value = None def __init__(self, ctx=None, lineno=None, col_offset=None, parent=None): self.ctx = ctx super(Starred, self).__init__(lineno=lineno, col_offset=col_offset, parent=parent) def postinit(self, value=None): self.value = value @util.register_implementation(treeabc.Subscript) class Subscript(base.NodeNG): """class representing a Subscript node""" _astroid_fields = ('value', 'slice') _other_fields = ('ctx', ) value = None slice = None def __init__(self, ctx=None, lineno=None, col_offset=None, parent=None): self.ctx = ctx super(Subscript, self).__init__(lineno=lineno, col_offset=col_offset, parent=parent) def postinit(self, value=None, slice=None): self.value = value self.slice = slice infer_lhs = inference.infer_subscript @util.register_implementation(treeabc.TryExcept) class TryExcept(base.BlockRangeMixIn, Statement): """class representing a TryExcept node""" _astroid_fields = ('body', 'handlers', 'orelse',) body = None handlers = None orelse = None def postinit(self, body=None, handlers=None, orelse=None): self.body = body self.handlers = handlers self.orelse = orelse def _infer_name(self, frame, name): return name 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) @util.register_implementation(treeabc.TryFinally) class TryFinally(base.BlockRangeMixIn, Statement): """class representing a TryFinally node""" _astroid_fields = ('body', 'finalbody',) body = None finalbody = None def postinit(self, body=None, finalbody=None): self.body = body self.finalbody = finalbody 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) @util.register_implementation(treeabc.Tuple) @util.register_implementation(runtimeabc.BuiltinInstance) class Tuple(base.BaseContainer, AssignedStmtsMixin, objects.BaseInstance): """class representing a Tuple node""" _other_fields = ('ctx',) def __init__(self, ctx=None, lineno=None, col_offset=None, parent=None): self.ctx = ctx super(Tuple, self).__init__(lineno, col_offset, parent) def pytype(self): return '%s.tuple' % BUILTINS def getitem(self, index, context=None): return _container_getitem(self, self.elts, index) @decorators.cachedproperty def _proxied(self): builtins = MANAGER.builtins() return builtins.getattr('tuple')[0] @util.register_implementation(treeabc.UnaryOp) class UnaryOp(base.NodeNG): """class representing an UnaryOp node""" _astroid_fields = ('operand',) _other_fields = ('op',) operand = None def __init__(self, op=None, lineno=None, col_offset=None, parent=None): self.op = op super(UnaryOp, self).__init__(lineno, col_offset, parent) def postinit(self, operand=None): self.operand = operand def _infer_unaryop(self, context=None): return inference.infer_unaryop(self, nodes=sys.modules[__name__], context=context) def type_errors(self, context=None): """Return a list of TypeErrors which can occur during inference. Each TypeError is represented by a :class:`BadUnaryOperationMessage`, which holds the original exception. """ try: results = self._infer_unaryop(context=context) return [result for result in results if isinstance(result, util.BadUnaryOperationMessage)] except exceptions.InferenceError: return [] @util.register_implementation(treeabc.While) class While(base.BlockRangeMixIn, Statement): """class representing a While node""" _astroid_fields = ('test', 'body', 'orelse',) test = None body = None orelse = None def postinit(self, test=None, body=None, orelse=None): self.test = test self.body = body self.orelse = orelse @decorators.cachedproperty def blockstart_tolineno(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) @util.register_implementation(treeabc.With) class With(base.BlockRangeMixIn, base.AssignTypeMixin, AssignedStmtsMixin, Statement): """class representing a With node""" _astroid_fields = ('items', 'body') def __init__(self, lineno=None, col_offset=None, parent=None): self.items = [] self.body = [] super(With, self).__init__(lineno, col_offset, parent) def postinit(self, items=None, body=None): self.items = items self.body = body @decorators.cachedproperty def blockstart_tolineno(self): return self.items[-1].context_expr.tolineno @util.register_implementation(treeabc.WithItem) class WithItem(base.ParentAssignTypeMixin, AssignedStmtsMixin, base.NodeNG): _astroid_fields = ('context_expr', 'optional_vars') context_expr = None optional_vars = None def postinit(self, context_expr=None, optional_vars=None): self.context_expr = context_expr self.optional_vars = optional_vars @util.register_implementation(treeabc.AsyncWith) class AsyncWith(With): """Asynchronous `with` built with the `async` keyword.""" @util.register_implementation(treeabc.Yield) class Yield(base.NodeNG): """class representing a Yield node""" _astroid_fields = ('value',) value = None def postinit(self, value=None): self.value = value @util.register_implementation(treeabc.YieldFrom) class YieldFrom(Yield): """ Class representing a YieldFrom node. """ @util.register_implementation(treeabc.DictUnpack) class DictUnpack(base.NodeNG): """Represents the unpacking of dicts into dicts using PEP 448.""" @object.__new__ @util.register_implementation(treeabc.Empty) class Empty(base.NodeNG): """Empty nodes represents the lack of something For instance, they can be used to represent missing annotations or defaults for arguments or anything where None is a valid value. """ def __bool__(self): return False __nonzero__ = __bool__ @util.register_implementation(treeabc.FormattedValue) class FormattedValue(base.NodeNG): """Represents a PEP 498 format string.""" _astroid_fields = ('value', 'format_spec') value = None conversion = None format_spec = None def postinit(self, value, conversion=None, format_spec=None): self.value = value self.conversion = conversion self.format_spec = format_spec @util.register_implementation(treeabc.JoinedStr) class JoinedStr(base.NodeNG): """Represents a list of string expressions to be joined.""" _astroid_fields = ('values',) value = None def postinit(self, values=None): self.values = values # Register additional inference dispatched functions. We do # this here, since we need to pass this module as an argument # to these functions, in order to avoid circular dependencies # between inference and node_classes. _module = sys.modules[__name__] inference.infer.register(treeabc.UnaryOp, functools.partial(inference.filtered_infer_unaryop, nodes=_module)) inference.infer.register(treeabc.Arguments, functools.partial(inference.infer_arguments, nodes=_module)) inference.infer.register(treeabc.BinOp, functools.partial(inference.filtered_infer_binop, nodes=_module)) inference.infer.register(treeabc.AugAssign, functools.partial(inference.filtered_infer_augassign, nodes=_module)) del _module