blob: 66e802b8889b4ffd50d86f4c7e63255ad46c1d07 [file]
# Copyright (c) 2009-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
# Copyright (c) 2014-2016 Claudiu Popa <pcmanticore@gmail.com>
# Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com>
# 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