summaryrefslogtreecommitdiff
path: root/astroid
diff options
context:
space:
mode:
Diffstat (limited to 'astroid')
-rw-r--r--astroid/node_classes.py2479
-rw-r--r--astroid/nodes.py20
-rw-r--r--astroid/protocols.py1
-rw-r--r--astroid/scoped_nodes.py1131
4 files changed, 3339 insertions, 292 deletions
diff --git a/astroid/node_classes.py b/astroid/node_classes.py
index bc9a629c..b213f7d9 100644
--- a/astroid/node_classes.py
+++ b/astroid/node_classes.py
@@ -1,3 +1,4 @@
+# pylint: disable=too-many-lines; https://github.com/PyCQA/astroid/issues/465
# Copyright (c) 2009-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
# Copyright (c) 2013-2014, 2016 Google, Inc.
# Copyright (c) 2014-2016 Claudiu Popa <pcmanticore@gmail.com>
@@ -199,38 +200,93 @@ def _container_getitem(instance, elts, index, context=None):
class NodeNG(object):
- """Base Class for all Astroid node classes.
+ """ A node of the new Abstract Syntax Tree (AST).
- It represents a node of the new abstract syntax tree.
+ This is the base class for all Astroid node classes.
"""
is_statement = False
+ """Whether this node indicates a statement.
+
+ :type: bool
+ """
optional_assign = False # True for For (and for Comprehension if py <3.0)
+ """Whether this node optionally assigns a variable.
+
+ This is for loop assignments because loop won't necessarily perform an
+ assignment if the loop has no iterations.
+ This is also the case from comprehensions in Python 2.
+
+ :type: bool
+ """
is_function = False # True for FunctionDef nodes
- # attributes below are set by the builder module or by raw factories
+ """Whether this node indicates a function.
+
+ :type: bool
+ """
+ # Attributes below are set by the builder module or by raw factories
lineno = None
+ """The line that this node appears on in the source code.
+
+ :type: int or None
+ """
col_offset = None
- # parent node in the tree
+ """The column that this node appears on in the source code.
+
+ :type: int or None
+ """
parent = None
- # attributes containing child node(s) redefined in most concrete classes:
+ """The parent node in the syntax tree.
+
+ :type: NodeNG or None
+ """
_astroid_fields = ()
- # attributes containing non-nodes:
+ """Node attributes that contain child nodes.
+
+ This is redefined in most concrete classes.
+
+ :type: tuple(str)
+ """
_other_fields = ()
- # attributes containing AST-dependent fields:
+ """Node attributes that do not contain child nodes.
+
+ :type: tuple(str)
+ """
_other_other_fields = ()
+ """Attributes that contain AST-dependent fields.
+
+ :type: tuple(str)
+ """
# instance specific inference function infer(node, context)
_explicit_inference = None
def __init__(self, lineno=None, col_offset=None, parent=None):
+ """
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.lineno = lineno
self.col_offset = col_offset
self.parent = parent
def infer(self, context=None, **kwargs):
- """main interface to the interface system, return a generator on inferred
- values.
+ """Get a generator of the inferred values.
+
+ This is the main entry point to the inference system.
+
+ .. seealso:: :ref:`inference`
If the instance has some explicit inference function set, it will be
called instead of the default interface.
+
+ :returns: The inferred values.
+ :rtype: iterable
"""
if self._explicit_inference is not None:
# explicit_inference is not bound, give it self explicitly
@@ -251,7 +307,13 @@ class NodeNG(object):
return context.cache_generator(key, self._infer(context, **kwargs))
def _repr_name(self):
- """return self.name or self.attrname or '' for nice representation"""
+ """Get a name for nice representation.
+
+ This is either :attr:`name`, :attr:`attrname`, or the empty string.
+
+ :returns: The nice name.
+ :rtype: str
+ """
return getattr(self, 'name', getattr(self, 'attrname', ''))
def __str__(self):
@@ -291,10 +353,16 @@ class NodeNG(object):
'id': id(self)}
def accept(self, visitor):
+ """Visit this node using the given visitor."""
func = getattr(visitor, "visit_" + self.__class__.__name__.lower())
return func(self)
def get_children(self):
+ """Get the child nodes below this node.
+
+ :returns: The children.
+ :rtype: iterable(NodeNG)
+ """
for field in self._astroid_fields:
attr = getattr(self, field)
if attr is None:
@@ -306,7 +374,11 @@ class NodeNG(object):
yield attr
def last_child(self):
- """an optimized version of list(get_children())[-1]"""
+ """An optimized version of list(get_children())[-1]
+
+ :returns: The last child, or None if no children exist.
+ :rtype: NodeNG or None
+ """
for field in self._astroid_fields[::-1]:
attr = getattr(self, field)
if not attr: # None or empty listy / tuple
@@ -318,7 +390,15 @@ class NodeNG(object):
return None
def parent_of(self, node):
- """return true if i'm a parent of the given node"""
+ """Check if this node is the parent of the given node.
+
+ :param node: The node to check if it is the child.
+ :type node: NodeNG
+
+ :returns: True if this node is the parent of the given node,
+ False otherwise.
+ :rtype: bool
+ """
parent = node.parent
while parent is not None:
if self is parent:
@@ -327,33 +407,56 @@ class NodeNG(object):
return False
def statement(self):
- """return the first parent node marked as statement node"""
+ """The first parent node, including self, marked as statement node.
+
+ :returns: The first parent statement.
+ :rtype: NodeNG
+ """
if self.is_statement:
return self
return self.parent.statement()
def frame(self):
- """return the first parent frame node (i.e. Module, FunctionDef or
- ClassDef)
+ """The first parent frame node.
+ A frame node is a :class:`Module`, :class:`FunctionDef`,
+ or :class:`ClassDef`.
+
+ :returns: The first parent frame node.
+ :rtype: Module or FunctionDef or ClassDef
"""
return self.parent.frame()
def scope(self):
- """return the first node defining a new scope (i.e. Module,
- FunctionDef, ClassDef, Lambda but also GenExpr)
+ """The first parent node defining a new scope.
+ :returns: The first parent scope node.
+ :rtype: Module or FunctionDef or ClassDef or Lambda or GenExpr
"""
return self.parent.scope()
def root(self):
- """return the root node of the tree, (i.e. a Module)"""
+ """Return the root node of the syntax tree.
+
+ :returns: The root node.
+ :rtype: Module
+ """
if self.parent:
return self.parent.root()
return self
def child_sequence(self, child):
- """search for the right sequence where the child lies in"""
+ """Search for the sequence that contains this child.
+
+ :param child: The child node to search sequences for.
+ :type child: NodeNG
+
+ :returns: The sequence containing the given child node.
+ :rtype: iterable(NodeNG)
+
+ :raises AstroidError: If no sequence could be found that contains
+ the given child.
+ """
for field in self._astroid_fields:
node_or_sequence = getattr(self, field)
if node_or_sequence is child:
@@ -367,7 +470,18 @@ class NodeNG(object):
raise exceptions.AstroidError(msg % (repr(child), repr(self)))
def locate_child(self, child):
- """return a 2-uple (child attribute name, sequence or node)"""
+ """Find the field of this node that contains the given child.
+
+ :param child: The child node to search fields for.
+ :type child: NodeNG
+
+ :returns: A tuple of the name of the field that contains the child,
+ and the sequence or node that contains the child node.
+ :rtype: tuple(str, iterable(NodeNG) or NodeNG)
+
+ :raises AstroidError: If no field could be found that contains
+ the given child.
+ """
for field in self._astroid_fields:
node_or_sequence = getattr(self, field)
# /!\ compiler.ast Nodes have an __iter__ walking over child nodes
@@ -381,16 +495,32 @@ class NodeNG(object):
# is only used in are_exclusive, child_sequence one time in pylint.
def next_sibling(self):
- """return the next sibling statement"""
+ """The next sibling statement node.
+
+ :returns: The next sibling statement node.
+ :rtype: NodeNG or None
+ """
return self.parent.next_sibling()
def previous_sibling(self):
- """return the previous sibling statement"""
+ """The previous sibling statement.
+
+ :returns: The previous sibling statement node.
+ :rtype: NodeNG or None
+ """
return self.parent.previous_sibling()
def nearest(self, nodes):
- """return the node which is the nearest before this one in the
- given list of nodes
+ """Get the node closest to this one from the given list of nodes.
+
+ :param nodes: The list of nodes to search. All of these nodes must
+ belong to the same module as this one. The list should be
+ sorted by the line number of the nodes, smallest first.
+ :type nodes: iterable(NodeNG)
+
+ :returns: The node closest to this one in the source code,
+ or None if one could not be found.
+ :rtype: NodeNG or None
"""
myroot = self.root()
mylineno = self.fromlineno
@@ -411,6 +541,10 @@ class NodeNG(object):
@decorators.cachedproperty
def fromlineno(self):
+ """The first line that this node appears on in the source code.
+
+ :type: int or None
+ """
if self.lineno is None:
return self._fixed_source_line()
@@ -418,6 +552,10 @@ class NodeNG(object):
@decorators.cachedproperty
def tolineno(self):
+ """The last line that this node appears on in the source code.
+
+ :type: int or None
+ """
if not self._astroid_fields:
# can't have children
lastchild = None
@@ -429,10 +567,13 @@ class NodeNG(object):
return lastchild.tolineno
def _fixed_source_line(self):
- """return the line number where the given node appears
+ """Attempt to find the line that this node appears on.
+
+ We need this method since not all nodes have :attr:`lineno` set.
- we need this method since not all nodes have the lineno attribute
- correctly set...
+ :returns: The line number of this node,
+ or None if this could not be determined.
+ :rtype: int or None
"""
line = self.lineno
_node = self
@@ -448,18 +589,44 @@ class NodeNG(object):
return line
def block_range(self, lineno):
- """handle block line numbers range for non block opening statements
+ """Get a range from the given line number to where this node ends.
+
+ :param lineno: The line number to start the range at.
+ :type lineno: int
+
+ :returns: The range of line numbers that this node belongs to,
+ starting at the given line number.
+ :rtype: tuple(int, int or None)
"""
return lineno, self.tolineno
def set_local(self, name, stmt):
- """delegate to a scoped parent handling a locals dictionary"""
+ """Define that the given name is declared in the given statement node.
+
+ This definition is stored on the parent scope node.
+
+ .. seealso:: :meth:`scope`
+
+ :param name: The name that is being defined.
+ :type name: str
+
+ :param stmt: The statement that defines the given name.
+ :type stmt: NodeNG
+ """
self.parent.set_local(name, stmt)
def nodes_of_class(self, klass, skip_klass=None):
- """return an iterator on nodes which are instance of the given class(es)
+ """Get the nodes (including this one or below) of the given type.
+
+ :param klass: The type of node to search for.
+ :type klass: builtins.type
- klass may be a class object or a tuple of class objects
+ :param skip_klass: A type of node to ignore. This is useful to ignore
+ subclasses of :attr:`klass`.
+ :type skip_klass: builtins.type
+
+ :returns: The node of the given type.
+ :rtype: iterable(NodeNG)
"""
if isinstance(self, klass):
yield self
@@ -480,10 +647,23 @@ class NodeNG(object):
node=self, context=context)
def inferred(self):
- '''return list of inferred values for a more simple inference usage'''
+ """Get a list of the inferred values.
+
+ .. seealso:: :ref:`inference`
+
+ :returns: The inferred values.
+ :rtype: list
+ """
return list(self.infer())
def infered(self):
+ """A deprecated alias of :meth:`inferred`.
+
+ .. deprecated:: 1.5
+
+ :returns: The inferred values.
+ :rtype: list
+ """
warnings.warn('%s.infered() is deprecated and slated for removal '
'in astroid 2.0, use %s.inferred() instead.'
% (type(self).__name__, type(self).__name__),
@@ -491,42 +671,75 @@ class NodeNG(object):
return self.inferred()
def instantiate_class(self):
- """instantiate a node if it is a ClassDef node, else return self"""
+ """Instantiate a instance of the defined class.
+
+ .. note::
+
+ On anything other than a :class:`ClassDef` this will return self.
+
+ :returns: An instance of the defined class.
+ :rtype: object
+ """
return self
def has_base(self, node):
+ """Check if this node inherits from the given type.
+
+ :param node: The node defining the base to look for.
+ Usually this is a :class:`Name` node.
+ :type node: NodeNG
+ """
return False
def callable(self):
+ """Whether this node defines something that is callable.
+
+ :returns: True if this defines something that is callable,
+ False otherwise.
+ :rtype: bool
+ """
return False
def eq(self, value):
return False
def as_string(self):
+ """Get the source code that this node represents.
+
+ :returns: The source code.
+ :rtype: str
+ """
return as_string.to_code(self)
def repr_tree(self, ids=False, include_linenos=False,
ast_state=False, indent=' ', max_depth=0, max_width=80):
- """Returns a string representation of the AST from this node.
+ """Get a string representation of the AST from this node.
:param ids: If true, includes the ids with the node type names.
+ :type ids: bool
:param include_linenos: If true, includes the line numbers and
column offsets.
+ :type include_linenos: bool
:param ast_state: If true, includes information derived from
- the whole AST like local and global variables.
+ the whole AST like local and global variables.
+ :type ast_state: bool
:param indent: A string to use to indent the output string.
+ :type indent: str
:param max_depth: If set to a positive integer, won't return
- nodes deeper than max_depth in the string.
+ nodes deeper than max_depth in the string.
+ :type max_depth: int
+
+ :param max_width: Attempt to format the output string to stay
+ within this number of characters, but can exceed it under some
+ circumstances. Only positive integer values are valid, the default is 80.
+ :type max_width: int
- :param max_width: Only positive integer values are valid, the
- default is 80. Attempts to format the output string to stay
- within max_width characters, but can exceed it under some
- circumstances.
+ :returns: The string representation of the AST.
+ :rtype: str
"""
@_singledispatch
def _repr_tree(node, result, done, cur_indent='', depth=1):
@@ -625,19 +838,22 @@ class NodeNG(object):
return ''.join(result)
def bool_value(self):
- """Determine the bool value of this node
+ """Determine the boolean value of this node.
The boolean value of a node can have three
possible values:
- * False. For instance, empty data structures,
+ * False: For instance, empty data structures,
False, empty strings, instances which return
explicitly False from the __nonzero__ / __bool__
method.
- * True. Most of constructs are True by default:
+ * True: Most of constructs are True by default:
classes, functions, modules etc
- * Uninferable: the inference engine is uncertain of the
+ * Uninferable: The inference engine is uncertain of the
node's value.
+
+ :returns: The boolean value of this node.
+ :rtype: bool or Uninferable
"""
return util.Uninferable
@@ -645,9 +861,17 @@ class NodeNG(object):
class Statement(NodeNG):
"""Statement node adding a few attributes"""
is_statement = True
+ """Whether this node indicates a statement.
+
+ :type: bool
+ """
def next_sibling(self):
- """return the next sibling statement"""
+ """The next sibling statement node.
+
+ :returns: The next sibling statement node.
+ :rtype: NodeNG or None
+ """
stmts = self.parent.child_sequence(self)
index = stmts.index(self)
try:
@@ -656,14 +880,17 @@ class Statement(NodeNG):
pass
def previous_sibling(self):
- """return the previous sibling statement"""
+ """The previous sibling statement.
+
+ :returns: The previous sibling statement node.
+ :rtype: NodeNG or None
+ """
stmts = self.parent.child_sequence(self)
index = stmts.index(self)
if index >= 1:
return stmts[index -1]
return None
-
@six.add_metaclass(abc.ABCMeta)
class _BaseContainer(mixins.ParentAssignTypeMixin,
NodeNG, bases.Instance):
@@ -672,14 +899,43 @@ class _BaseContainer(mixins.ParentAssignTypeMixin,
_astroid_fields = ('elts',)
def __init__(self, lineno=None, col_offset=None, parent=None):
+ """
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.elts = []
+ """The elements in the node.
+
+ :type: list(NodeNG)
+ """
+
super(_BaseContainer, self).__init__(lineno, col_offset, parent)
def postinit(self, elts):
+ """Do some setup after initialisation.
+
+ :param elts: The list of elements the that node contains.
+ :type elts: list(NodeNG)
+ """
self.elts = elts
@classmethod
def from_constants(cls, elts=None):
+ """Create a node of this type from the given list of elements.
+
+ :param elts: The list of elements that the node should contain.
+ :type elts: list(NodeNG)
+
+ :returns: A new node containing the given elements.
+ :rtype: NodeNG
+ """
node = cls()
if elts is None:
node.elts = []
@@ -688,49 +944,82 @@ class _BaseContainer(mixins.ParentAssignTypeMixin,
return node
def itered(self):
+ """An iterator over the elements this node contains.
+
+ :returns: The contents of this node.
+ :rtype: iterable(NodeNG)
+ """
return self.elts
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ :rtype: bool or Uninferable
+ """
return bool(self.elts)
@abc.abstractmethod
def pytype(self):
- pass
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
class LookupMixIn(object):
- """Mixin looking up a name in the right scope
- """
+ """Mixin to look up a name in the right scope."""
def lookup(self, name):
- """lookup a variable name
+ """Lookup where the given variable is assigned.
- 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
+ The lookup starts 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
+ filtered to remove ignorable statements according to self's location.
+
+ :param name: The name of the variable to find assignments for.
+ :type name: str
+
+ :returns: 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).
+ :rtype: tuple(str, list(NodeNG))
"""
return self.scope().scope_lookup(self, name)
def ilookup(self, name):
- """inferred lookup
+ """Lookup the inferred values of the given variable.
- return an iterator on inferred values of the statements returned by
- the lookup method
+ :param name: The variable name to find values for.
+ :type name: str
+
+ :returns: The inferred values of the statements returned from
+ :meth:`lookup`.
+ :rtype: iterable
"""
frame, stmts = self.lookup(name)
context = contextmod.InferenceContext()
return bases._infer_stmts(stmts, context, frame)
def _filter_stmts(self, stmts, frame, offset):
- """filter statements to remove ignorable statements.
+ """Filter the given list of 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
+ statements according to self's location.
+
+ :param stmts: The statements to filter.
+ :type stmts: list(NodeNG)
+
+ :param frame: The frame that all of the given statements belong to.
+ :type frame: NodeNG
+
+ :param offset: The line offset to filter statements up to.
+ :type offset: int
+
+ :returns: The filtered statements.
+ :rtype: list(NodeNG)
"""
# if offset == -1, my actual frame is not the inner frame but its parent
#
@@ -845,34 +1134,134 @@ class LookupMixIn(object):
# Name classes
class AssignName(LookupMixIn, mixins.ParentAssignTypeMixin, NodeNG):
- """class representing an AssignName node"""
+ """Variation of :class:`ast.Assign` representing assignment to a name.
+
+ An :class:`AssignName` is the name of something that is assigned to.
+ This includes variables defined in a function signature or in a loop.
+
+ >>> node = astroid.extract_node('variable = range(10)')
+ >>> node
+ <Assign l.1 at 0x7effe1db8550>
+ >>> list(node.get_children())
+ [<AssignName.variable l.1 at 0x7effe1db8748>, <Call l.1 at 0x7effe1db8630>]
+ >>> list(node.get_children())[0].as_string()
+ 'variable'
+ """
_other_fields = ('name',)
def __init__(self, name=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param name: The name that is assigned to.
+ :type name: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.name = name
+ """The name that is assigned to.
+
+ :type: str or None
+ """
+
super(AssignName, self).__init__(lineno, col_offset, parent)
class DelName(LookupMixIn, mixins.ParentAssignTypeMixin, NodeNG):
- """class representing a DelName node"""
+ """Variation of :class:`ast.Delete` represention deletion of a name.
+
+ A :class:`DelName` is the name of something that is deleted.
+
+ >>> node = astroid.extract_node("del variable #@")
+ >>> list(node.get_children())
+ [<DelName.variable l.1 at 0x7effe1da4d30>]
+ >>> list(node.get_children())[0].as_string()
+ 'variable'
+ """
_other_fields = ('name',)
def __init__(self, name=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param name: The name that is being deleted.
+ :type name: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.name = name
+ """The name that is being deleted.
+
+ :type: str or None
+ """
+
super(DelName, self).__init__(lineno, col_offset, parent)
class Name(LookupMixIn, NodeNG):
- """class representing a Name node"""
+ """Class representing an :class:`ast.Name` node.
+
+ A :class:`Name` node is something that is named, but not covered by
+ :class:`AssignName` or :class:`DelName`.
+
+ >>> node = astroid.extract_node('range(10)')
+ >>> node
+ <Call l.1 at 0x7effe1db8710>
+ >>> list(node.get_children())
+ [<Name.range l.1 at 0x7effe1db86a0>, <Const.int l.1 at 0x7effe1db8518>]
+ >>> list(node.get_children())[0].as_string()
+ 'range'
+ """
_other_fields = ('name',)
def __init__(self, name=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param name: The name that this node refers to.
+ :type name: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.name = name
+ """The name that this node refers to.
+
+ :type: str or None
+ """
+
super(Name, self).__init__(lineno, col_offset, parent)
class Arguments(mixins.AssignTypeMixin, NodeNG):
- """class representing an Arguments node"""
+ """Class representing an :class:`ast.arguments` node.
+
+ An :class:`Arguments` node represents that arguments in a
+ function definition.
+
+ >>> node = astroid.extract_node('def foo(bar): pass')
+ >>> node
+ <FunctionDef.foo l.1 at 0x7effe1db8198>
+ >>> node.args
+ <Arguments l.1 at 0x7effe1db82e8>
+ """
if six.PY3:
# Python 3.4+ uses a different approach regarding annotations,
# each argument is a new class, _ast.arg, which exposes an
@@ -889,27 +1278,118 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
'kw_defaults', 'annotations', 'varargannotation',
'kwargannotation', 'kwonlyargs_annotations')
varargannotation = None
+ """The type annotation for the variable length arguments.
+
+ :type: NodeNG
+ """
kwargannotation = None
+ """The type annotation for the variable length keyword arguments.
+
+ :type: NodeNG
+ """
else:
_astroid_fields = ('args', 'defaults', 'kwonlyargs', 'kw_defaults')
_other_fields = ('vararg', 'kwarg')
def __init__(self, vararg=None, kwarg=None, parent=None):
+ """
+ :param vararg: The name of the variable length arguments.
+ :type vararg: str or None
+
+ :param kwarg: The name of the variable length keyword arguments.
+ :type kwarg: str or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
super(Arguments, self).__init__(parent=parent)
self.vararg = vararg
+ """The name of the variable length arguments.
+
+ :type: str or None
+ """
+
self.kwarg = kwarg
+ """The name of the variable length keyword arguments.
+
+ :type: str or None
+ """
+
self.args = []
+ """The names of the required arguments.
+
+ :type: list(AssignName)
+ """
+
self.defaults = []
+ """The default values for arguments that can be passed positionally.
+
+ :type: list(NodeNG)
+ """
+
self.kwonlyargs = []
+ """The keyword arguments that cannot be passed positionally.
+
+ :type: list(AssignName)
+ """
+
self.kw_defaults = []
+ """The default values for keyword arguments that cannot be passed positionally.
+
+ :type: list(NodeNG)
+ """
+
self.annotations = []
+ """The type annotations of arguments that can be passed positionally.
+
+ :type: list(NodeNG)
+ """
+
self.kwonlyargs_annotations = []
+ """The type annotations of arguments that cannot be passed positionally.
+
+ :type: list(NodeNG)
+ """
def postinit(self, args, defaults, kwonlyargs, kw_defaults,
annotations,
kwonlyargs_annotations=None,
varargannotation=None,
kwargannotation=None):
+ """Do some setup after initialisation.
+
+ :param args: The names of the required arguments.
+ :type args: list(AssignName)
+
+ :param defaults: The default values for arguments that can be passed
+ positionally.
+ :type defaults: list(NodeNG)
+
+ :param kwonlyargs: The keyword arguments that cannot be passed
+ positionally.
+ :type kwonlyargs: list(AssignName)
+
+ :param kw_defaults: The default values for keyword arguments that
+ cannot be passed positionally.
+ :type kw_defaults: list(NodeNG)
+
+ :param annotations: The type annotations of arguments that can be
+ passed positionally.
+ :type annotations: list(NodeNG)
+
+ :param kwonlyargs_annotations: The type annotations of arguments that
+ cannot be passed positionally. This should always be passed in
+ Python 3.
+ :type kwonlyargs_annotations: list(NodeNG)
+
+ :param varargannotation: The type annotation for the variable length
+ arguments.
+ :type varargannotation: NodeNG
+
+ :param kwargannotation: The type annotation for the variable length
+ keyword arguments.
+ :type kwargannotation: NodeNG
+ """
self.args = args
self.defaults = defaults
self.kwonlyargs = kwonlyargs
@@ -926,11 +1406,19 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
@decorators.cachedproperty
def fromlineno(self):
+ """The first line that this node appears on in the source code.
+
+ :type: int or None
+ """
lineno = super(Arguments, self).fromlineno
return max(lineno, self.parent.fromlineno or 0)
def format_args(self):
- """return arguments formatted as string"""
+ """Get the arguments formatted as string.
+
+ :returns: The formatted arguments.
+ :rtype: str
+ """
result = []
if self.args:
result.append(
@@ -952,9 +1440,13 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
return ', '.join(result)
def default_value(self, argname):
- """return the default value for an argument
+ """Get the default value for an argument.
+
+ :param argname: The name of the argument to get the default value for.
+ :type argname: str
- :raise `NoDefault`: if there is no default value defined
+ :raises NoDefault: If there is no default value defined for the
+ given argument.
"""
i = _find_arg(argname, self.args)[0]
if i is not None:
@@ -967,7 +1459,15 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
raise exceptions.NoDefault(func=self.parent, name=argname)
def is_argument(self, name):
- """return True if the name is defined in arguments"""
+ """Check if the given name is defined in the arguments.
+
+ :param name: The name to check for.
+ :type name: str
+
+ :returns: True if the given name is defined in the arguments,
+ False otherwise.
+ :rtype: bool
+ """
if name == self.vararg:
return True
if name == self.kwarg:
@@ -976,13 +1476,30 @@ class Arguments(mixins.AssignTypeMixin, NodeNG):
self.kwonlyargs and _find_arg(name, self.kwonlyargs, True)[1] is not None)
def find_argname(self, argname, rec=False):
- """return index and Name node with given name"""
+ """Get the index and :class:`AssignName` node for given name.
+
+ :param argname: The name of the argument to search for.
+ :type argname: str
+
+ :param rec: Whether or not to include arguments in unpacked tuples
+ in the search.
+ :type rec: bool
+
+ :returns: The index and node for the argument.
+ :rtype: tuple(str or None, AssignName or None)
+ """
if self.args: # self.args may be None in some cases (builtin function)
return _find_arg(argname, self.args, rec)
return None, None
def get_children(self):
- """override get_children to skip over None elements in kw_defaults"""
+ """Get the child nodes below this node.
+
+ This skips over `None` elements in :attr:`kw_defaults`.
+
+ :returns: The children.
+ :rtype: iterable(NodeNG)
+ """
for child in super(Arguments, self).get_children():
if child is not None:
yield child
@@ -1025,52 +1542,174 @@ def _format_args(args, defaults=None, annotations=None):
class AssignAttr(mixins.ParentAssignTypeMixin, NodeNG):
- """class representing an AssignAttr node"""
+ """Variation of :class:`ast.Assign` representing assignment to an attribute.
+
+ >>> node = astroid.extract_node('self.attribute = range(10)')
+ >>> node
+ <Assign l.1 at 0x7effe1d521d0>
+ >>> list(node.get_children())
+ [<AssignAttr.attribute l.1 at 0x7effe1d52320>, <Call l.1 at 0x7effe1d522e8>]
+ >>> list(node.get_children())[0].as_string()
+ 'self.attribute'
+ """
_astroid_fields = ('expr',)
_other_fields = ('attrname',)
expr = None
+ """What has the attribute that is being assigned to.
+
+ :type: NodeNG or None
+ """
def __init__(self, attrname=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param attrname: The name of the attribute being assigned to.
+ :type attrname: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.attrname = attrname
+ """The name of the attribute being assigned to.
+
+ :type: str or None
+ """
+
super(AssignAttr, self).__init__(lineno, col_offset, parent)
def postinit(self, expr=None):
+ """Do some setup after initialisation.
+
+ :param expr: What has the attribute that is being assigned to.
+ :type expr: NodeNG or None
+ """
self.expr = expr
class Assert(Statement):
- """class representing an Assert node"""
+ """Class representing an :class:`ast.Assert` node.
+
+ An :class:`Assert` node represents an assert statement.
+
+ >>> node = astroid.extract_node('assert len(things) == 10, "Not enough things"')
+ >>> node
+ <Assert l.1 at 0x7effe1d527b8>
+ """
_astroid_fields = ('test', 'fail',)
test = None
+ """The test that passes or fails the assertion.
+
+ :type: NodeNG or None
+ """
fail = None
+ """The message shown when the assertion fails.
+
+ :type: NodeNG or None
+ """
def postinit(self, test=None, fail=None):
+ """Do some setup after initialisation.
+
+ :param test: The test that passes or fails the assertion.
+ :type test: NodeNG or None
+
+ :param fail: The message shown when the assertion fails.
+ :type fail: NodeNG or None
+ """
self.fail = fail
self.test = test
class Assign(mixins.AssignTypeMixin, Statement):
- """class representing an Assign node"""
+ """Class representing an :class:`ast.Assign` node.
+
+ An :class:`Assign` is a statement where something is explicitly
+ asssigned to.
+
+ >>> node = astroid.extract_node('variable = range(10)')
+ >>> node
+ <Assign l.1 at 0x7effe1db8550>
+ """
_astroid_fields = ('targets', 'value',)
targets = None
+ """What is being assigned to.
+
+ :type: list(NodeNG) or None
+ """
value = None
+ """The value being assigned to the variables.
+
+ :type: NodeNG or None
+ """
def postinit(self, targets=None, value=None):
+ """Do some setup after initialisation.
+
+ :param targets: What is being assigned to.
+ :type targets: list(NodeNG) or None
+
+ :param value: The value being assigned to the variables.
+ :type: NodeNG or None
+ """
self.targets = targets
self.value = value
class AnnAssign(mixins.AssignTypeMixin, Statement):
- """Class representing an AnnAssign node"""
+ """Class representing an :class:`ast.AnnAssign` node.
+
+ An :class:`AnnAssign` is an assignment with a type annotation.
+
+ >>> node = astroid.extract_node('variable: List[int] = range(10)')
+ >>> node
+ <AnnAssign l.1 at 0x7effe1d4c630>
+ """
_astroid_fields = ('target', 'annotation', 'value',)
_other_fields = ('simple',)
target = None
+ """What is being assigned to.
+
+ :type: NodeNG or None
+ """
annotation = None
+ """The type annotation of what is being assigned to.
+
+ :type: NodeNG
+ """
value = None
+ """The value being assigned to the variables.
+
+ :type: NodeNG or None
+ """
simple = None
+ """Whether :attr:`target` is a pure name or a complex statement.
+
+ :type: int
+ """
def postinit(self, target, annotation, simple, value=None):
+ """Do some setup after initialisation.
+
+ :param target: What is being assigned to.
+ :type target: NodeNG
+
+ :param annotation: The type annotation of what is being assigned to.
+ :type: NodeNG
+
+ :param simple: Whether :attr:`target` is a pure name
+ or a complex statement.
+ :type simple: int
+
+ :param value: The value being assigned to the variables.
+ :type: NodeNG or None
+ """
self.target = target
self.annotation = annotation
self.value = value
@@ -1078,17 +1717,62 @@ class AnnAssign(mixins.AssignTypeMixin, Statement):
class AugAssign(mixins.AssignTypeMixin, Statement):
- """class representing an AugAssign node"""
+ """Class representing an :class:`ast.AugAssign` node.
+
+ An :class:`AugAssign` is an assignment paired with an operator.
+
+ >>> node = astroid.extract_node('variable += 1')
+ >>> node
+ <AugAssign l.1 at 0x7effe1db4d68>
+ """
_astroid_fields = ('target', 'value')
_other_fields = ('op',)
target = None
+ """What is being assigned to.
+
+ :type: NodeNG or None
+ """
value = None
+ """The value being assigned to the variable.
+
+ :type: NodeNG or None
+ """
def __init__(self, op=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param op: The operator that is being combined with the assignment.
+ This includes the equals sign.
+ :type op: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.op = op
+ """The operator that is being combined with the assignment.
+
+ This includes the equals sign.
+
+ :type: str or None
+ """
+
super(AugAssign, self).__init__(lineno, col_offset, parent)
def postinit(self, target=None, value=None):
+ """Do some setup after initialisation.
+
+ :param target: What is being assigned to.
+ :type target: NodeNG or None
+
+ :param value: The value being assigned to the variable.
+ :type: NodeNG or None
+ """
self.target = target
self.value = value
@@ -1097,10 +1781,13 @@ class AugAssign(mixins.AssignTypeMixin, Statement):
raise NotImplementedError
def type_errors(self, context=None):
- """Return a list of TypeErrors which can occur during inference.
+ """Get a list of type errors which can occur during inference.
- Each TypeError is represented by a :class:`BadBinaryOperationMessage`,
+ Each TypeError is represented by a :class:`BadBinaryOperationMessage` ,
which holds the original exception.
+
+ :returns: The list of possible type errors.
+ :rtype: list(BadBinaryOperationMessage)
"""
try:
results = self._infer_augassign(context=context)
@@ -1111,26 +1798,85 @@ class AugAssign(mixins.AssignTypeMixin, Statement):
class Repr(NodeNG):
- """class representing a Repr node"""
+ """Class representing an :class:`ast.Repr` node.
+
+ A :class:`Repr` node represents the backtick syntax,
+ which is a deprecated alias for :func:`repr` removed in Python 3.
+
+ >>> node = astroid.extract_node('`variable`')
+ >>> node
+ <Repr l.1 at 0x7fa0951d75d0>
+ """
_astroid_fields = ('value',)
value = None
+ """What is having :func:`repr` called on it.
+
+ :type: NodeNG or None
+ """
def postinit(self, value=None):
+ """Do some setup after initialisation.
+
+ :param value: What is having :func:`repr` called on it.
+ :type value: NodeNG or None
+ """
self.value = value
class BinOp(NodeNG):
- """class representing a BinOp node"""
+ """Class representing an :class:`ast.BinOp` node.
+
+ A :class:`BinOp` node is an application of a binary operator.
+
+ >>> node = astroid.extract_node('a + b')
+ >>> node
+ <BinOp l.1 at 0x7f23b2e8cfd0>
+ """
_astroid_fields = ('left', 'right')
_other_fields = ('op',)
left = None
+ """What is being applied to the operator on the left side.
+
+ :type: NodeNG or None
+ """
right = None
+ """What is being applied to the operator on the right side.
+
+ :type: NodeNG or None
+ """
def __init__(self, op=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param op: The operator.
+ :type: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.op = op
+ """The operator.
+
+ :type: str or None
+ """
+
super(BinOp, self).__init__(lineno, col_offset, parent)
def postinit(self, left=None, right=None):
+ """Do some setup after initialisation.
+
+ :param left: What is being applied to the operator on the left side.
+ :type left: NodeNG or None
+
+ :param right: What is being applied to the operator on the right side.
+ :type right: NodeNG or None
+ """
self.left = left
self.right = right
@@ -1139,10 +1885,13 @@ class BinOp(NodeNG):
raise NotImplementedError
def type_errors(self, context=None):
- """Return a list of TypeErrors which can occur during inference.
+ """Get a list of type errors which can occur during inference.
Each TypeError is represented by a :class:`BadBinaryOperationMessage`,
which holds the original exception.
+
+ :returns: The list of possible type errors.
+ :rtype: list(BadBinaryOperationMessage)
"""
try:
results = self._infer_binop(context=context)
@@ -1153,94 +1902,271 @@ class BinOp(NodeNG):
class BoolOp(NodeNG):
- """class representing a BoolOp node"""
+ """Class representing an :class:`ast.BoolOp` node.
+
+ A :class:`BoolOp` is an application of a boolean operator.
+
+ >>> node = astroid.extract_node('a and b')
+ >>> node
+ <BinOp l.1 at 0x7f23b2e71c50>
+ """
_astroid_fields = ('values',)
_other_fields = ('op',)
values = None
+ """The values being applied to the operator.
+
+ :type: list(NodeNG) or None
+ """
def __init__(self, op=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param op: The operator.
+ :type: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.op = op
+ """The operator.
+
+ :type: str or None
+ """
+
super(BoolOp, self).__init__(lineno, col_offset, parent)
def postinit(self, values=None):
+ """Do some setup after initialisation.
+
+ :param values: The values being applied to the operator.
+ :type values: list(NodeNG) or None
+ """
self.values = values
class Break(Statement):
- """class representing a Break node"""
+ """Class representing an :class:`ast.Break` node.
+
+ >>> node = astroid.extract_node('break')
+ >>> node
+ <Break l.1 at 0x7f23b2e9e5c0>
+ """
class Call(NodeNG):
- """class representing a Call node"""
+ """Class representing an :class:`ast.Call` node.
+
+ A :class:`Call` node is a call to a function, method, etc.
+
+ >>> node = astroid.extract_node('function()')
+ >>> node
+ <Call l.1 at 0x7f23b2e71eb8>
+ """
_astroid_fields = ('func', 'args', 'keywords')
func = None
+ """What is being called.
+
+ :type: NodeNG or None
+ """
args = None
+ """The positional arguments being given to the call.
+
+ :type: list(NodeNG) or None
+ """
keywords = None
+ """The keyword arguments being given to the call.
+
+ :type: list(NodeNG) or None
+ """
def postinit(self, func=None, args=None, keywords=None):
+ """Do some setup after initialisation.
+
+ :param func: What is being called.
+ :type func: NodeNG or None
+
+ :param args: The positional arguments being given to the call.
+ :type args: list(NodeNG) or None
+
+ :param keywords: The keyword arguments being given to the call.
+ :type keywords: list(NodeNG) or None
+ """
self.func = func
self.args = args
self.keywords = keywords
@property
def starargs(self):
+ """The positional arguments that unpack something.
+
+ :type: list(Starred)
+ """
args = self.args or []
return [arg for arg in args if isinstance(arg, Starred)]
@property
def kwargs(self):
+ """The keyword arguments that unpack something.
+
+ :type: list(Keyword)
+ """
keywords = self.keywords or []
return [keyword for keyword in keywords if keyword.arg is None]
class Compare(NodeNG):
- """class representing a Compare node"""
+ """Class representing an :class:`ast.Compare` node.
+
+ A :class:`Compare` node indicates a comparison.
+
+ >>> node = astroid.extract_node('a <= b <= c')
+ >>> node
+ <Compare l.1 at 0x7f23b2e9e6d8>
+ >>> node.ops
+ [('<=', <Name.b l.1 at 0x7f23b2e9e2b0>), ('<=', <Name.c l.1 at 0x7f23b2e9e390>)]
+ """
_astroid_fields = ('left', 'ops',)
left = None
+ """The value at the left being applied to a comparison operator.
+
+ :type: NodeNG or None
+ """
ops = None
+ """The remainder of the operators and their relevant right hand value.
+
+ :type: list(tuple(str, NodeNG)) or None
+ """
def postinit(self, left=None, ops=None):
+ """Do some setup after initialisation.
+
+ :param left: The value at the left being applied to a comparison
+ operator.
+ :type left: NodeNG or None
+
+ :param ops: The remainder of the operators
+ and their relevant right hand value.
+ :type ops: list(tuple(str, NodeNG)) or None
+ """
self.left = left
self.ops = ops
def get_children(self):
- """override get_children for tuple fields"""
+ """Get the child nodes below this node.
+
+ Overridden to handle the tuple fields and skip returning the operator
+ strings.
+
+ :returns: The children.
+ :rtype: iterable(NodeNG)
+ """
yield self.left
for _, comparator in self.ops:
yield comparator # we don't want the 'op'
def last_child(self):
- """override last_child"""
+ """An optimized version of list(get_children())[-1]
+
+ :returns: The last child.
+ :rtype: NodeNG
+ """
# XXX maybe if self.ops:
return self.ops[-1][1]
#return self.left
class Comprehension(NodeNG):
- """class representing a Comprehension node"""
+ """Class representing an :class:`ast.comprehension` node.
+
+ A :class:`Comprehension` indicates the loop inside any type of
+ comprehension including generator expressions.
+
+ >>> node = astroid.extract_node('[x for x in some_values]')
+ >>> list(node.get_children())
+ [<Name.x l.1 at 0x7f23b2e352b0>, <Comprehension l.1 at 0x7f23b2e35320>]
+ >>> list(node.get_children())[1].as_string()
+ 'for x in some_values'
+ """
_astroid_fields = ('target', 'iter', 'ifs')
_other_fields = ('is_async',)
target = None
+ """What is assigned to by the comprehension.
+
+ :type: NodeNG or None
+ """
iter = None
+ """What is iterated over by the comprehension.
+
+ :type: NodeNG or None
+ """
ifs = None
+ """The contents of any if statements that filter the comprehension.
+
+ :type: list(NodeNG) or None
+ """
is_async = None
+ """Whether this is an asynchronous comprehension or not.
+
+ :type: bool or None
+ """
def __init__(self, parent=None):
+ """
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
super(Comprehension, self).__init__()
self.parent = parent
# pylint: disable=redefined-builtin; same name as builtin ast module.
def postinit(self, target=None, iter=None, ifs=None, is_async=None):
+ """Do some setup after initialisation.
+
+ :param target: What is assigned to by the comprehension.
+ :type target: NodeNG or None
+
+ :param iter: What is iterated over by the comprehension.
+ :type iter: NodeNG or None
+
+ :param ifs: The contents of any if statements that filter
+ the comprehension.
+ :type ifs: list(NodeNG) or None
+
+ :param is_async: Whether this is an asynchronous comprehension or not.
+ :type: bool or None
+ """
self.target = target
self.iter = iter
self.ifs = ifs
self.is_async = is_async
optional_assign = True
+ """Whether this node optionally assigns a variable.
+
+ :type: bool
+ """
def assign_type(self):
+ """The type of assignment that this node performs.
+
+ :returns: The assignment type.
+ :rtype: NodeNG
+ """
return self
def ass_type(self):
+ """A deprecated alias of :meth:`assign_type`.
+
+ .. deprecated:: 1.5
+
+ :returns: The assignment type.
+ :rtype: NodeNG
+ """
warnings.warn('%s.ass_type() is deprecated and slated for removal'
'in astroid 2.0, use %s.assign_type() instead.'
% (type(self).__name__, type(self).__name__),
@@ -1263,14 +2189,52 @@ class Comprehension(NodeNG):
class Const(NodeNG, bases.Instance):
- """represent a constant node like num, str, bool, None, bytes"""
+ """Class representing any constant including num, str, bool, None, bytes.
+
+ >>> node = astroid.extract_node('(5, "This is a string.", True, None, b"bytes")')
+ >>> node
+ <Tuple.tuple l.1 at 0x7f23b2e358d0>
+ >>> list(node.get_children())
+ [<Const.int l.1 at 0x7f23b2e35940>,
+ <Const.str l.1 at 0x7f23b2e35978>,
+ <Const.bool l.1 at 0x7f23b2e359b0>,
+ <Const.NoneType l.1 at 0x7f23b2e359e8>,
+ <Const.bytes l.1 at 0x7f23b2e35a20>]
+ """
_other_fields = ('value',)
def __init__(self, value, lineno=None, col_offset=None, parent=None):
+ """
+ :param value: The value that the constant represents.
+ :type value: object
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.value = value
+ """The value that the constant represents.
+
+ :type: object
+ """
+
super(Const, self).__init__(lineno, col_offset, parent)
def getitem(self, index, context=None):
+ """Get an item from this node if subscriptable.
+
+ :param index: The node to use as a subscript index.
+ :type index: Const or Slice
+
+ :raises AstroidTypeError: When the given index cannot be used as a
+ subscript index, or if this node is not subscriptable.
+ """
if isinstance(index, Const):
index_value = index.value
elif isinstance(index, Slice):
@@ -1303,73 +2267,217 @@ class Const(NodeNG, bases.Instance):
)
def has_dynamic_getattr(self):
+ """Check if the node has a custom __getattr__ or __getattribute__.
+
+ :returns: True if the class has a custom
+ __getattr__ or __getattribute__, False otherwise.
+ For a :class:`Const` this is always ``False``.
+ :rtype: bool
+ """
return False
def itered(self):
+ """An iterator over the elements this node contains.
+
+ :returns: The contents of this node.
+ :rtype: iterable(str)
+
+ :raises TypeError: If this node does not represent something that is iterable.
+ """
if isinstance(self.value, six.string_types):
return self.value
raise TypeError()
def pytype(self):
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
return self._proxied.qname()
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ :rtype: bool
+ """
return bool(self.value)
class Continue(Statement):
- """class representing a Continue node"""
+ """Class representing an :class:`ast.Continue` node.
+
+ >>> node = astroid.extract_node('continue')
+ >>> node
+ <Continue l.1 at 0x7f23b2e35588>
+ """
class Decorators(NodeNG):
- """class representing a Decorators node"""
+ """A node representing a list of decorators.
+
+ A :class:`Decorators` is the decorators that are applied to
+ a method or function.
+
+ >>> node = astroid.extract_node('''
+ @property
+ def my_property(self):
+ return 3
+ ''')
+ >>> node
+ <FunctionDef.my_property l.2 at 0x7f23b2e35d30>
+ >>> list(node.get_children())[0]
+ <Decorators l.1 at 0x7f23b2e35d68>
+ """
_astroid_fields = ('nodes',)
nodes = None
+ """The decorators that this node contains.
+
+ :type: list(Name or Call) or None
+ """
def postinit(self, nodes):
+ """Do some setup after initialisation.
+
+ :param nodes: The decorators that this node contains.
+ :type nodes: list(Name or Call)
+ """
self.nodes = nodes
def scope(self):
+ """The first parent node defining a new scope.
+
+ :returns: The first parent scope node.
+ :rtype: Module or FunctionDef or ClassDef or Lambda or GenExpr
+ """
# skip the function node to go directly to the upper level scope
return self.parent.parent.scope()
class DelAttr(mixins.ParentAssignTypeMixin, NodeNG):
- """class representing a DelAttr node"""
+ """Variation of :class:`ast.Delete` representing deletion of an attribute.
+
+ >>> node = astroid.extract_node('del self.attr')
+ >>> node
+ <Delete l.1 at 0x7f23b2e35f60>
+ >>> list(node.get_children())[0]
+ <DelAttr.attr l.1 at 0x7f23b2e411d0>
+ """
_astroid_fields = ('expr',)
_other_fields = ('attrname',)
expr = None
+ """The name that this node represents.
+
+ :type: Name or None
+ """
def __init__(self, attrname=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param attrname: The name of the attribute that is being deleted.
+ :type attrname: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.attrname = attrname
+ """The name of the attribute that is being deleted.
+
+ :type: str or None
+ """
+
super(DelAttr, self).__init__(lineno, col_offset, parent)
def postinit(self, expr=None):
+ """Do some setup after initialisation.
+
+ :param expr: The name that this node represents.
+ :type expr: Name or None
+ """
self.expr = expr
class Delete(mixins.AssignTypeMixin, Statement):
- """class representing a Delete node"""
+ """Class representing an :class:`ast.Delete` node.
+
+ A :class:`Delete` is a ``del`` statement this is deleting something.
+
+ >>> node = astroid.extract_node('del self.attr')
+ >>> node
+ <Delete l.1 at 0x7f23b2e35f60>
+ """
_astroid_fields = ('targets',)
targets = None
+ """What is being deleted.
+
+ :type: list(NodeNG) or None
+ """
def postinit(self, targets=None):
+ """Do some setup after initialisation.
+
+ :param targets: What is being deleted.
+ :type targets: list(NodeNG) or None
+ """
self.targets = targets
class Dict(NodeNG, bases.Instance):
- """class representing a Dict node"""
+ """Class representing an :class:`ast.Dict` node.
+
+ A :class:`Dict` is a dictionary that is created with ``{}`` syntax.
+
+ >>> node = astroid.extract_node('{1: "1"}')
+ >>> node
+ <Dict.dict l.1 at 0x7f23b2e35cc0>
+ """
_astroid_fields = ('items',)
def __init__(self, lineno=None, col_offset=None, parent=None):
+ """
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.items = []
+ """The key-value pairs contained in the dictionary.
+
+ :type: list(tuple(NodeNG, NodeNG))
+ """
+
super(Dict, self).__init__(lineno, col_offset, parent)
def postinit(self, items):
+ """Do some setup after initialisation.
+
+ :param items: The ley-value pairs contained in the dictionary.
+ :type items: list(tuple(NodeNG, NodeNG))
+ """
self.items = items
@classmethod
def from_constants(cls, items=None):
+ """Create a :class:`Dict` of constants from a live dictionary.
+
+ :param items: The items to store in the node.
+ :type items: dict
+
+ :returns: The created dictionary node.
+ :rtype: Dict
+ """
node = cls()
if items is None:
node.items = []
@@ -1379,25 +2487,55 @@ class Dict(NodeNG, bases.Instance):
return node
def pytype(self):
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
return '%s.dict' % BUILTINS
def get_children(self):
- """get children of a Dict node"""
- # overrides get_children
+ """Get the key and value nodes below this node.
+
+ Children are returned in the order that they are defined in the source
+ code, key first then the value.
+
+ :returns: The children.
+ :rtype: iterable(NodeNG)
+ """
for key, value in self.items:
yield key
yield value
def last_child(self):
- """override last_child"""
+ """An optimized version of list(get_children())[-1]
+
+ :returns: The last child, or None if no children exist.
+ :rtype: NodeNG or None
+ """
if self.items:
return self.items[-1][1]
return None
def itered(self):
+ """An iterator over the keys this node contains.
+
+ :returns: The keys of this node.
+ :rtype: iterable(NodeNG)
+ """
return self.items[::2]
def getitem(self, index, context=None):
+ """Get an item from this node.
+
+ :param index: The node to use as a subscript index.
+ :type index: Const or Slice
+
+ :raises AstroidTypeError: When the given index cannot be used as a
+ subscript index, or if this node is not subscriptable.
+ :raises AstroidIndexError: If the given index does not exist in the
+ dictionary.
+ """
for key, value in self.items:
# TODO(cpopa): no support for overriding yet, {1:2, **{1: 3}}.
if isinstance(key, DictUnpack):
@@ -1415,46 +2553,124 @@ class Dict(NodeNG, bases.Instance):
raise exceptions.AstroidIndexError(index)
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ :rtype: bool
+ """
return bool(self.items)
class Expr(Statement):
- """class representing a Expr node"""
+ """Class representing an :class:`ast.Expr` node.
+
+ An :class:`Expr` is any expression that does not have its value used or
+ stored.
+
+ >>> node = astroid.extract_node('method()')
+ >>> node
+ <Call l.1 at 0x7f23b2e352b0>
+ >>> node.parent
+ <Expr l.1 at 0x7f23b2e35278>
+ """
_astroid_fields = ('value',)
value = None
+ """What the expression does.
+
+ :type: NodeNG or None
+ """
def postinit(self, value=None):
+ """Do some setup after initialisation.
+
+ :param value: What the expression does.
+ :type value: NodeNG or None
+ """
self.value = value
class Ellipsis(NodeNG): # pylint: disable=redefined-builtin
- """class representing an Ellipsis node"""
+ """Class representing an :class:`ast.Ellipsis` node.
+
+ An :class:`Ellipsis` is the ``...`` syntax.
+
+ >>> node = astroid.extract_node('...')
+ >>> node
+ <Ellipsis l.1 at 0x7f23b2e35160>
+ """
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ For an :class:`Ellipsis` this is always ``True``.
+ :rtype: bool
+ """
return True
class EmptyNode(NodeNG):
- """class representing an EmptyNode node"""
+ """Holds an arbitrary object in the :attr:`LocalsDictNodeNG.locals`."""
object = None
class ExceptHandler(mixins.AssignTypeMixin, Statement):
- """class representing an ExceptHandler node"""
+ """Class representing an :class:`ast.ExceptHandler`. node.
+
+ An :class:`ExceptHandler` is an ``except`` block on a try-except.
+
+ >>> node = astroid.extract_node('''
+ try:
+ do_something()
+ except Exception as error:
+ print("Error!")
+ ''')
+ >>> node
+ <TryExcept l.2 at 0x7f23b2e9d908>
+ >>> >>> node.handlers
+ [<ExceptHandler l.4 at 0x7f23b2e9e860>]
+ """
_astroid_fields = ('type', 'name', 'body',)
type = None
+ """The types that the block handles.
+
+ :type: Tuple or NodeNG or None
+ """
name = None
+ """The name that the caught exception is assigned to.
+
+ :type: AssignName or None
+ """
body = None
+ """The contents of the block.
+
+ :type: list(NodeNG) or None
+ """
# pylint: disable=redefined-builtin; had to use the same name as builtin ast module.
def postinit(self, type=None, name=None, body=None):
+ """Do some setup after initialisation.
+
+ :param type: The types that the block handles.
+ :type type: Tuple or NodeNG or None
+
+ :param name: The name that the caught exception is assigned to.
+ :type name: AssignName or None
+
+ :param body:The contents of the block.
+ :type body: list(NodeNG) or None
+ """
self.type = type
self.name = name
self.body = body
@decorators.cachedproperty
def blockstart_tolineno(self):
+ """The line on which the beginning of this block ends.
+
+ :type: int
+ """
if self.name:
return self.name.tolineno
elif self.type:
@@ -1463,6 +2679,13 @@ class ExceptHandler(mixins.AssignTypeMixin, Statement):
return self.lineno
def catch(self, exceptions): # pylint: disable=redefined-outer-name
+ """Check if this node handles any of the given exceptions.
+
+ If ``exceptions`` is empty, this will default to ``True``.
+
+ :param exceptions: The name of the exceptions to check for.
+ :type exceptions: list(str)
+ """
if self.type is None or exceptions is None:
return True
for node in self.type.nodes_of_class(Name):
@@ -1472,95 +2695,324 @@ class ExceptHandler(mixins.AssignTypeMixin, Statement):
class Exec(Statement):
- """class representing an Exec node"""
+ """Class representing the ``exec`` statement.
+
+ >>> node = astroid.extract_node('exec "True"')
+ >>> node
+ <Exec l.1 at 0x7f0e8106c6d0>
+ """
_astroid_fields = ('expr', 'globals', 'locals',)
expr = None
+ """The expression to be executed.
+
+ :type: NodeNG or None
+ """
globals = None
+ """The globals dictionary to execute with.
+
+ :type: NodeNG or None
+ """
locals = None
+ """The locals dictionary to execute with.
+
+ :type: NodeNG or None
+ """
# pylint: disable=redefined-builtin; had to use the same name as builtin ast module.
def postinit(self, expr=None, globals=None, locals=None):
+ """Do some setup after initialisation.
+
+ :param expr: The expression to be executed.
+ :type expr: NodeNG or None
+
+ :param globals:The globals dictionary to execute with.
+ :type globals: NodeNG or None
+
+ :param locals: The locals dictionary to execute with.
+ :type locals: NodeNG or None
+ """
self.expr = expr
self.globals = globals
self.locals = locals
class ExtSlice(NodeNG):
- """class representing an ExtSlice node"""
+ """Class representing an :class:`ast.ExtSlice` node.
+
+ An :class:`ExtSlice` is a complex slice expression.
+
+ >>> node = astroid.extract_node('l[1:3, 5]')
+ >>> node
+ <Subscript l.1 at 0x7f23b2e9e550>
+ >>> node.slice
+ <ExtSlice l.1 at 0x7f23b7b05ef0>
+ """
_astroid_fields = ('dims',)
dims = None
+ """The simple dimensions that form the complete slice.
+
+ :type: list(NodeNG) or None
+ """
def postinit(self, dims=None):
+ """Do some setup after initialisation.
+
+ :param dims: The simple dimensions that form the complete slice.
+ :type dims: list(NodeNG) or None
+ """
self.dims = dims
class For(mixins.BlockRangeMixIn, mixins.AssignTypeMixin, Statement):
- """class representing a For node"""
+ """Class representing an :class:`ast.For` node.
+
+ >>> node = astroid.extract_node('for thing in things: print(thing)')
+ >>> node
+ <For l.1 at 0x7f23b2e8cf28>
+ """
_astroid_fields = ('target', 'iter', 'body', 'orelse',)
target = None
+ """What the loop assigns to.
+
+ :type: NodeNG or None
+ """
iter = None
+ """What the loop iterates over.
+
+ :type: NodeNG or None
+ """
body = None
+ """The contents of the body of the loop.
+
+ :type: list(NodeNG) or None
+ """
orelse = None
+ """The contents of the ``else`` block of the loop.
+
+ :type: list(NodeNG) or None
+ """
# pylint: disable=redefined-builtin; had to use the same name as builtin ast module.
def postinit(self, target=None, iter=None, body=None, orelse=None):
+ """Do some setup after initialisation.
+
+ :param target: What the loop assigns to.
+ :type target: NodeNG or None
+
+ :param iter: What the loop iterates over.
+ :type iter: NodeNG or None
+
+ :param body: The contents of the body of the loop.
+ :type body: list(NodeNG) or None
+
+ :param orelse: The contents of the ``else`` block of the loop.
+ :type orelse: list(NodeNG) or None
+ """
self.target = target
self.iter = iter
self.body = body
self.orelse = orelse
optional_assign = True
+ """Whether this node optionally assigns a variable.
+
+ This is always ``True`` for :class:`For` nodes.
+
+ :type: bool
+ """
+
@decorators.cachedproperty
def blockstart_tolineno(self):
+ """The line on which the beginning of this block ends.
+
+ :type: int
+ """
return self.iter.tolineno
class AsyncFor(For):
- """Asynchronous For built with `async` keyword."""
+ """Class representing an :class:`ast.AsyncFor` node.
+
+ An :class:`AsyncFor` is an asynchronous :class:`For` built with
+ the ``async`` keyword.
+
+ >>> node = astroid.extract_node('''
+ async def func(things):
+ async for thing in things:
+ print(thing)
+ ''')
+ >>> node
+ <AsyncFunctionDef.func l.2 at 0x7f23b2e416d8>
+ >>> node.body[0]
+ <AsyncFor l.3 at 0x7f23b2e417b8>
+ """
class Await(NodeNG):
- """Await node for the `await` keyword."""
+ """Class representing an :class:`ast.Await` node.
+
+ An :class:`Await` is the ``await`` keyword.
+
+ >>> node = astroid.extract_node('''
+ async def func(things):
+ await other_func()
+ ''')
+ >>> node
+ <AsyncFunctionDef.func l.2 at 0x7f23b2e41748>
+ >>> node.body[0]
+ <Expr l.3 at 0x7f23b2e419e8>
+ >>> list(node.body[0].get_children())[0]
+ <Await l.3 at 0x7f23b2e41a20>
+ """
_astroid_fields = ('value', )
value = None
+ """What to wait for.
+
+ :type: NodeNG or None
+ """
def postinit(self, value=None):
+ """Do some setup after initialisation.
+
+ :param value: What to wait for.
+ :type value: NodeNG or None
+ """
self.value = value
class ImportFrom(mixins.ImportFromMixin, Statement):
- """class representing a ImportFrom node"""
+ """Class representing an :class:`ast.ImportFrom` node.
+
+ >>> node = astroid.extract_node('from my_package import my_module')
+ >>> node
+ <ImportFrom l.1 at 0x7f23b2e415c0>
+ """
_other_fields = ('modname', 'names', 'level')
def __init__(self, fromname, names, level=0, lineno=None,
col_offset=None, parent=None):
+ """
+ :param fromname: The module that is being imported from.
+ :type fromname: str or None
+
+ :param names: What is being imported from the module.
+ :type names: list(tuple(str, str or None))
+
+ :param level: The level of relative import.
+ :type level: int
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.modname = fromname
+ """The module that is being imported from.
+
+ This is ``None`` for relative imports.
+
+ :type: str or None
+ """
+
self.names = names
+ """What is being imported from the module.
+
+ Each entry is a :class:`tuple` of the name being imported,
+ and the alias that the name is assigned to (if any).
+
+ :type: list(tuple(str, str or None))
+ """
+
self.level = level
+ """The level of relative import.
+
+ Essentially this is the number of dots in the import.
+ This is always 0 for absolute imports.
+
+ :type: int
+ """
+
super(ImportFrom, self).__init__(lineno, col_offset, parent)
class Attribute(NodeNG):
- """class representing a Attribute node"""
+ """Class representing an :class:`ast.Attribute` node."""
_astroid_fields = ('expr',)
_other_fields = ('attrname',)
expr = None
+ """The name that this node represents.
+
+ :type: Name or None
+ """
def __init__(self, attrname=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param attrname: The name of the attribute.
+ :type attrname: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.attrname = attrname
+ """The name of the attribute.
+
+ :type: str or None
+ """
+
super(Attribute, self).__init__(lineno, col_offset, parent)
def postinit(self, expr=None):
+ """Do some setup after initialisation.
+
+ :param expr: The name that this node represents.
+ :type expr: Name or None
+ """
self.expr = expr
class Global(Statement):
- """class representing a Global node"""
+ """Class representing an :class:`ast.Global` node.
+
+ >>> node = astroid.extract_node('global a_global')
+ >>> node
+ <Global l.1 at 0x7f23b2e9de10>
+ """
_other_fields = ('names',)
def __init__(self, names, lineno=None, col_offset=None, parent=None):
+ """
+ :param names: The names being declared as global.
+ :type names: list(str)
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.names = names
+ """The names being declared as global.
+
+ :type: list(str)
+ """
+
super(Global, self).__init__(lineno, col_offset, parent)
def _infer_name(self, frame, name):
@@ -1568,23 +3020,63 @@ class Global(Statement):
class If(mixins.BlockRangeMixIn, Statement):
- """class representing an If node"""
+ """Class representing an :class:`ast.If` node.
+
+ >>> node = astroid.extract_node('if condition: print(True)')
+ >>> node
+ <If l.1 at 0x7f23b2e9dd30>
+ """
_astroid_fields = ('test', 'body', 'orelse')
test = None
+ """The condition that the statement tests.
+
+ :type: NodeNG or None
+ """
body = None
+ """The contents of the block.
+
+ :type: list(NodeNG) or None
+ """
orelse = None
+ """The contents of the ``else`` block.
+
+ :type: list(NodeNG) or None
+ """
def postinit(self, test=None, body=None, orelse=None):
+ """Do some setup after initialisation.
+
+ :param test: The condition that the statement tests.
+ :type test: NodeNG or None
+
+ :param body: The contents of the block.
+ :type body: list(NodeNG) or None
+
+ :param orelse: The contents of the ``else`` block.
+ :type orelse: list(NodeNG) or None
+ """
self.test = test
self.body = body
self.orelse = orelse
@decorators.cachedproperty
def blockstart_tolineno(self):
+ """The line on which the beginning of this block ends.
+
+ :type: int
+ """
return self.test.tolineno
def block_range(self, lineno):
- """handle block line numbers range for if statements"""
+ """Get a range from the given line number to where this node ends.
+
+ :param lineno: The line number to start the range at.
+ :type lineno: int
+
+ :returns: The range of line numbers that this node belongs to,
+ starting at the given line number.
+ :rtype: tuple(int, int)
+ """
if lineno == self.body[0].fromlineno:
return lineno, lineno
if lineno <= self.body[-1].tolineno:
@@ -1594,72 +3086,242 @@ class If(mixins.BlockRangeMixIn, Statement):
class IfExp(NodeNG):
- """class representing an IfExp node"""
+ """Class representing an :class:`ast.IfExp` node.
+
+ >>> node = astroid.extract_node('value if condition else other')
+ >>> node
+ <IfExp l.1 at 0x7f23b2e9dbe0>
+ """
_astroid_fields = ('test', 'body', 'orelse')
test = None
+ """The condition that the statement tests.
+
+ :type: NodeNG or None
+ """
body = None
+ """The contents of the block.
+
+ :type: list(NodeNG) or None
+ """
orelse = None
+ """The contents of the ``else`` block.
+
+ :type: list(NodeNG) or None
+ """
def postinit(self, test=None, body=None, orelse=None):
+ """Do some setup after initialisation.
+
+ :param test: The condition that the statement tests.
+ :type test: NodeNG or None
+
+ :param body: The contents of the block.
+ :type body: list(NodeNG) or None
+
+ :param orelse: The contents of the ``else`` block.
+ :type orelse: list(NodeNG) or None
+ """
self.test = test
self.body = body
self.orelse = orelse
-
class Import(mixins.ImportFromMixin, Statement):
- """class representing an Import node"""
+ """Class representing an :class:`ast.Import` node.
+
+ >>> node = astroid.extract_node('import astroid')
+ >>> node
+ <Import l.1 at 0x7f23b2e4e5c0>
+ """
_other_fields = ('names',)
def __init__(self, names=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param names: The names being imported.
+ :type names: list(tuple(str, str or None)) or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.names = names
+ """The names being imported.
+
+ Each entry is a :class:`tuple` of the name being imported,
+ and the alias that the name is assigned to (if any).
+
+ :type: list(tuple(str, str or None)) or None
+ """
+
super(Import, self).__init__(lineno, col_offset, parent)
class Index(NodeNG):
- """class representing an Index node"""
+ """Class representing an :class:`ast.Index` node.
+
+ An :class:`Index` is a simple subscript.
+
+ >>> node = astroid.extract_node('things[1]')
+ >>> node
+ <Subscript l.1 at 0x7f23b2e9e2b0>
+ >>> node.slice
+ <Index l.1 at 0x7f23b2e9e6a0>
+ """
_astroid_fields = ('value',)
value = None
+ """The value to subscript with.
+
+ :type: NodeNG or None
+ """
def postinit(self, value=None):
+ """Do some setup after initialisation.
+
+ :param value: The value to subscript with.
+ :type value: NodeNG or None
+ """
self.value = value
class Keyword(NodeNG):
- """class representing a Keyword node"""
+ """Class representing an :class:`ast.keyword` node.
+
+ >>> node = astroid.extract_node('function(a_kwarg=True)')
+ >>> node
+ <Call l.1 at 0x7f23b2e9e320>
+ >>> node.keywords
+ [<Keyword l.1 at 0x7f23b2e9e9b0>]
+ """
_astroid_fields = ('value',)
_other_fields = ('arg',)
value = None
+ """The value being assigned to the keyword argument.
+
+ :type: NodeNG or None
+ """
def __init__(self, arg=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param arg: The argument being assigned to.
+ :type arg: Name or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.arg = arg
+ """The argument being assigned to.
+
+ :type: Name or None
+ """
+
super(Keyword, self).__init__(lineno, col_offset, parent)
def postinit(self, value=None):
+ """Do some setup after initialisation.
+
+ :param value: The value being assigned to the ketword argument.
+ :type value: NodeNG or None
+ """
self.value = value
class List(_BaseContainer):
- """class representing a List node"""
+ """Class representing an :class:`ast.List` node.
+
+ >>> node = astroid.extract_node('[1, 2, 3]')
+ >>> node
+ <List.list l.1 at 0x7f23b2e9e128>
+ """
_other_fields = ('ctx',)
def __init__(self, ctx=None, lineno=None,
col_offset=None, parent=None):
+ """
+ :param ctx: Whether the list is assigned to or loaded from.
+ :type ctx: Context or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.ctx = ctx
+ """Whether the list is assigned to or loaded from.
+
+ :type: Context or None
+ """
+
super(List, self).__init__(lineno, col_offset, parent)
def pytype(self):
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
return '%s.list' % BUILTINS
def getitem(self, index, context=None):
+ """Get an item from this node.
+
+ :param index: The node to use as a subscript index.
+ :type index: Const or Slice
+ """
return _container_getitem(self, self.elts, index, context=context)
class Nonlocal(Statement):
- """class representing a Nonlocal node"""
+ """Class representing an :class:`ast.Nonlocal` node.
+
+ >>> node = astroid.extract_node('''
+ def function():
+ nonlocal var
+ ''')
+ >>> node
+ <FunctionDef.function l.2 at 0x7f23b2e9e208>
+ >>> node.body[0]
+ <Nonlocal l.3 at 0x7f23b2e9e908>
+ """
_other_fields = ('names',)
def __init__(self, names, lineno=None, col_offset=None, parent=None):
+ """
+ :param names: The names being decalred as not local.
+ :type names: list(str)
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.names = names
+ """The names being declared as not local.
+
+ :type: list(str)
+ """
+
super(Nonlocal, self).__init__(lineno, col_offset, parent)
def _infer_name(self, frame, name):
@@ -1667,46 +3329,136 @@ class Nonlocal(Statement):
class Pass(Statement):
- """class representing a Pass node"""
+ """Class representing an :class:`ast.Pass` node.
+
+ >>> node = astroid.extract_node('pass')
+ >>> node
+ <Pass l.1 at 0x7f23b2e9e748>
+ """
class Print(Statement):
- """class representing a Print node"""
+ """Class representing an :class:`ast.Print` node.
+
+ >>> node = astroid.extract_node('print "A message"')
+ >>> node
+ <Print l.1 at 0x7f0e8101d290>
+ """
_astroid_fields = ('dest', 'values',)
dest = None
+ """Where to print to.
+
+ :type: NodeNG or None
+ """
values = None
+ """What to print.
+
+ :type: list(NodeNG) or None
+ """
def __init__(self, nl=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param nl: Whether to print a new line.
+ :type nl: bool or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.nl = nl
+ """Whether to print a new line.
+
+ :type: bool or None
+ """
+
super(Print, self).__init__(lineno, col_offset, parent)
def postinit(self, dest=None, values=None):
+ """Do some setup after initialisation.
+
+ :param dest: Where to print to.
+ :type dest: NodeNG or None
+
+ :param values: What to print.
+ :type values: list(NodeNG) or None
+ """
self.dest = dest
self.values = values
class Raise(Statement):
- """class representing a Raise node"""
+ """Class representing an :class:`ast.Raise` node.
+
+ >>> node = astroid.extract_node('raise RuntimeError("Something bad happened!")')
+ >>> node
+ <Raise l.1 at 0x7f23b2e9e828>
+ """
exc = None
+ """What is being raised.
+
+ :type: NodeNG or None
+ """
if six.PY2:
_astroid_fields = ('exc', 'inst', 'tback')
inst = None
+ """The "value" of the exception being raised.
+
+ :type: NodeNG or None
+ """
tback = None
+ """The traceback object to raise with.
+
+ :type: NodeNG or None
+ """
def postinit(self, exc=None, inst=None, tback=None):
+ """Do some setup after initialisation.
+
+ :param exc: What is being raised.
+ :type exc: NodeNG or None
+
+ :param inst: The "value" of the exception being raised.
+ :type inst: NodeNG or None
+
+ :param tback: The traceback object to raise with.
+ :type tback: NodeNG or None
+ """
self.exc = exc
self.inst = inst
self.tback = tback
else:
_astroid_fields = ('exc', 'cause')
- exc = None
cause = None
+ """The exception being used to raise this one.
+
+ :type: NodeNG or None
+ """
def postinit(self, exc=None, cause=None):
+ """Do some setup after initialisation.
+
+ :param exc: What is being raised.
+ :type exc: NodeNG or None
+
+ :param cause: The exception being used to raise this one.
+ :type cause: NodeNG or None
+ """
self.exc = exc
self.cause = cause
def raises_not_implemented(self):
+ """Check if this node raises a :class:`NotImplementedError`.
+
+ :returns: True if this node raises a :class:`NotImplementedError`,
+ False otherwise.
+ :rtype: bool
+ """
if not self.exc:
return False
for name in self.exc.nodes_of_class(Name):
@@ -1716,29 +3468,83 @@ class Raise(Statement):
class Return(Statement):
- """class representing a Return node"""
+ """Class representing an :class:`ast.Return` node.
+
+ >>> node = astroid.extract_node('return True')
+ >>> node
+ <Return l.1 at 0x7f23b8211908>
+ """
_astroid_fields = ('value',)
value = None
+ """The value being returned.
+
+ :type: NodeNG or None
+ """
def postinit(self, value=None):
+ """Do some setup after initialisation.
+
+ :param value: The value being returned.
+ :type value: NodeNG or None
+ """
self.value = value
class Set(_BaseContainer):
- """class representing a Set node"""
+ """Class representing an :class:`ast.Set` node.
+
+ >>> node = astroid.extract_node('{1, 2, 3}')
+ >>> node
+ <Set.set l.1 at 0x7f23b2e71d68>
+ """
def pytype(self):
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
return '%s.set' % BUILTINS
class Slice(NodeNG):
- """class representing a Slice node"""
+ """Class representing an :class:`ast.Slice` node.
+
+ >>> node = astroid.extract_node('things[1:3]')
+ >>> node
+ <Subscript l.1 at 0x7f23b2e71f60>
+ >>> node.slice
+ <Slice l.1 at 0x7f23b2e71e80>
+ """
_astroid_fields = ('lower', 'upper', 'step')
lower = None
+ """The lower index in the slice.
+
+ :type: NodeNG or None
+ """
upper = None
+ """The upper index in the slice.
+
+ :type: NodeNG or None
+ """
step = None
+ """The step to take between indexes.
+
+ :type: NodeNG or None
+ """
def postinit(self, lower=None, upper=None, step=None):
+ """Do some setup after initialisation.
+
+ :param lower: The lower index in the slice.
+ :value lower: NodeNG or None
+
+ :param upper: The upper index in the slice.
+ :value upper: NodeNG or None
+
+ :param step: The step to take between index.
+ :param step: NodeNG or None
+ """
self.lower = lower
self.upper = upper
self.step = step
@@ -1757,9 +3563,22 @@ class Slice(NodeNG):
return builtins.getattr('slice')[0]
def pytype(self):
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
return '%s.slice' % BUILTINS
def igetattr(self, attrname, context=None):
+ """Infer the possible values of the given attribute on the slice.
+
+ :param attrname: The name of the attribute to infer.
+ :type attrname: str
+
+ :returns: The inferred possible values.
+ :rtype: iterable(NodeNG)
+ """
if attrname == 'start':
yield self._wrap_attribute(self.lower)
elif attrname == 'stop':
@@ -1775,46 +3594,152 @@ class Slice(NodeNG):
class Starred(mixins.ParentAssignTypeMixin, NodeNG):
- """class representing a Starred node"""
+ """Class representing an :class:`ast.Starred` node.
+
+ >>> node = astroid.extract_node('*args')
+ >>> node
+ <Starred l.1 at 0x7f23b2e41978>
+ """
_astroid_fields = ('value',)
_other_fields = ('ctx', )
value = None
+ """What is being unpacked.
+
+ :type: NodeNG or None
+ """
def __init__(self, ctx=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param ctx: Whether the list is assigned to or loaded from.
+ :type ctx: Context or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.ctx = ctx
+ """Whether the starred item is assigned to or loaded from.
+
+ :type: Context or None
+ """
+
super(Starred, self).__init__(lineno=lineno,
col_offset=col_offset, parent=parent)
def postinit(self, value=None):
+ """Do some setup after initialisation.
+
+ :param value: What is being unpacked.
+ :type value: NodeNG or None
+ """
self.value = value
class Subscript(NodeNG):
- """class representing a Subscript node"""
+ """Class representing an :class:`ast.Subscript` node.
+
+ >>> node = astroid.extract_node('things[1:3]')
+ >>> node
+ <Subscript l.1 at 0x7f23b2e71f60>
+ """
_astroid_fields = ('value', 'slice')
_other_fields = ('ctx', )
value = None
+ """What is being indexed.
+
+ :type: NodeNG or None
+ """
slice = None
+ """The slice being used to lookup.
+
+ :type: NodeNG or None
+ """
def __init__(self, ctx=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param ctx: Whether the subscripted item is assigned to or loaded from.
+ :type ctx: Context or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.ctx = ctx
+ """Whether the subscripted item is assigned to or loaded from.
+
+ :type: Context or None
+ """
+
super(Subscript, self).__init__(lineno=lineno,
col_offset=col_offset, parent=parent)
# pylint: disable=redefined-builtin; had to use the same name as builtin ast module.
def postinit(self, value=None, slice=None):
+ """Do some setup after initialisation.
+
+ :param value: What is being indexed.
+ :type value: NodeNG or None
+
+ :param slice: The slice being used to lookup.
+ :type slice: NodeNG or None
+ """
self.value = value
self.slice = slice
class TryExcept(mixins.BlockRangeMixIn, Statement):
- """class representing a TryExcept node"""
+ """Class representing an :class:`ast.TryExcept` node.
+
+ >>> node = astroid.extract_node('''
+ try:
+ do_something()
+ except Exception as error:
+ print("Error!")
+ ''')
+ >>> node
+ <TryExcept l.2 at 0x7f23b2e9d908>
+ """
_astroid_fields = ('body', 'handlers', 'orelse',)
body = None
+ """The contents of the block to catch exceptions from.
+
+ :type: list(NodeNG) or None
+ """
handlers = None
+ """The exception handlers.
+
+ :type: list(ExceptHandler) or None
+ """
orelse = None
+ """The contents of the ``else`` block.
+
+ :type: list(NodeNG) or None
+ """
def postinit(self, body=None, handlers=None, orelse=None):
+ """Do some setup after initialisation.
+
+ :param body: The contents of the block to catch exceptions from.
+ :type body: list(NodeNG) or None
+
+ :param handlers: The exception handlers.
+ :type handlers: list(ExceptHandler) or None
+
+ :param orelse: The contents of the ``else`` block.
+ :type orelse: list(NodeNG) or None
+ """
self.body = body
self.handlers = handlers
self.orelse = orelse
@@ -1823,7 +3748,15 @@ class TryExcept(mixins.BlockRangeMixIn, Statement):
return name
def block_range(self, lineno):
- """handle block line numbers range for try/except statements"""
+ """Get a range from the given line number to where this node ends.
+
+ :param lineno: The line number to start the range at.
+ :type lineno: int
+
+ :returns: The range of line numbers that this node belongs to,
+ starting at the given line number.
+ :rtype: tuple(int, int)
+ """
last = None
for exhandler in self.handlers:
if exhandler.type and lineno == exhandler.type.fromlineno:
@@ -1836,17 +3769,53 @@ class TryExcept(mixins.BlockRangeMixIn, Statement):
class TryFinally(mixins.BlockRangeMixIn, Statement):
- """class representing a TryFinally node"""
+ """Class representing an :class:`ast.TryFinally` node.
+
+ >>> node = astroid.extract_node('''
+ try:
+ do_something()
+ except Exception as error:
+ print("Error!")
+ finally:
+ print("Cleanup!")
+ ''')
+ >>> node
+ <TryFinally l.2 at 0x7f23b2e41d68>
+ """
_astroid_fields = ('body', 'finalbody',)
body = None
+ """The try-except that the finally is attached to.
+
+ :type: list(TryExcept) or None
+ """
finalbody = None
+ """The contents of the ``finally`` block.
+
+ :type: list(NodeNG) or None
+ """
def postinit(self, body=None, finalbody=None):
+ """Do some setup after initialisation.
+
+ :param body: The try-except that the finally is attached to.
+ :type body: list(TryExcept) or None
+
+ :param finalbody: The contents of the ``finally`` block.
+ :type finalbody: list(NodeNG) or None
+ """
self.body = body
self.finalbody = finalbody
def block_range(self, lineno):
- """handle block line numbers range for try/finally statements"""
+ """Get a range from the given line number to where this node ends.
+
+ :param lineno: The line number to start the range at.
+ :type lineno: int
+
+ :returns: The range of line numbers that this node belongs to,
+ starting at the given line number.
+ :rtype: tuple(int, int)
+ """
child = self.body[0]
# py2.5 try: except: finally:
if (isinstance(child, TryExcept) and child.fromlineno == self.fromlineno
@@ -1856,33 +3825,100 @@ class TryFinally(mixins.BlockRangeMixIn, Statement):
class Tuple(_BaseContainer):
- """class representing a Tuple node"""
+ """Class representing an :class:`ast.Tuple` node.
+
+ >>> node = astroid.extract_node('(1, 2, 3)')
+ >>> node
+ <Tuple.tuple l.1 at 0x7f23b2e41780>
+ """
_other_fields = ('ctx',)
def __init__(self, ctx=None, lineno=None,
col_offset=None, parent=None):
+ """
+ :param ctx: Whether the tuple is assigned to or loaded from.
+ :type ctx: Context or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.ctx = ctx
+ """Whether the tuple is assigned to or loaded from.
+
+ :type: Context or None
+ """
+
super(Tuple, self).__init__(lineno, col_offset, parent)
def pytype(self):
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
return '%s.tuple' % BUILTINS
def getitem(self, index, context=None):
+ """Get an item from this node.
+
+ :param index: The node to use as a subscript index.
+ :type index: Const or Slice
+ """
return _container_getitem(self, self.elts, index, context=context)
class UnaryOp(NodeNG):
- """class representing an UnaryOp node"""
+ """Class representing an :class:`ast.UnaryOp` node.
+
+ >>> node = astroid.extract_node('-5')
+ >>> node
+ <UnaryOp l.1 at 0x7f23b2e4e198>
+ """
_astroid_fields = ('operand',)
_other_fields = ('op',)
operand = None
+ """What the unary operator is applied to.
+
+ :type: NodeNG or None
+ """
def __init__(self, op=None, lineno=None, col_offset=None, parent=None):
+ """
+ :param op: The operator.
+ :type: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.op = op
+ """The operator.
+
+ :type: str or None
+ """
+
super(UnaryOp, self).__init__(lineno, col_offset, parent)
def postinit(self, operand=None):
+ """Do some setup after initialisation.
+
+ :param operand: What the unary operator is applied to.
+ :type operand: NodeNG or None
+ """
self.operand = operand
# This is set by inference.py
@@ -1890,10 +3926,13 @@ class UnaryOp(NodeNG):
raise NotImplementedError
def type_errors(self, context=None):
- """Return a list of TypeErrors which can occur during inference.
+ """Get a list of type errors which can occur during inference.
- Each TypeError is represented by a :class:`BadUnaryOperationMessage`,
+ Each TypeError is represented by a :class:`BadBinaryOperationMessage`,
which holds the original exception.
+
+ :returns: The list of possible type errors.
+ :rtype: list(BadBinaryOperationMessage)
"""
try:
results = self._infer_unaryop(context=context)
@@ -1904,41 +3943,118 @@ class UnaryOp(NodeNG):
class While(mixins.BlockRangeMixIn, Statement):
- """class representing a While node"""
+ """Class representing an :class:`ast.While` node.
+
+ >>> node = astroid.extract_node('''
+ while condition():
+ print("True")
+ ''')
+ >>> node
+ <While l.2 at 0x7f23b2e4e390>
+ """
_astroid_fields = ('test', 'body', 'orelse',)
test = None
+ """The condition that the loop tests.
+
+ :type: NodeNG or None
+ """
body = None
+ """The contents of the loop.
+
+ :type: list(NodeNG) or None
+ """
orelse = None
+ """The contents of the ``else`` block.
+
+ :type: list(NodeNG) or None
+ """
def postinit(self, test=None, body=None, orelse=None):
+ """Do some setup after initialisation.
+
+ :param test: The condition that the loop tests.
+ :type test: NodeNG or None
+
+ :param body: The contents of the loop.
+ :type body: list(NodeNG) or None
+
+ :param orelse: The contents of the ``else`` block.
+ :type orelse: list(NodeNG) or None
+ """
self.test = test
self.body = body
self.orelse = orelse
@decorators.cachedproperty
def blockstart_tolineno(self):
+ """The line on which the beginning of this block ends.
+
+ :type: int
+ """
return self.test.tolineno
def block_range(self, lineno):
- """handle block line numbers range for and while statements"""
+ """Get a range from the given line number to where this node ends.
+
+ :param lineno: The line number to start the range at.
+ :type lineno: int
+
+ :returns: The range of line numbers that this node belongs to,
+ starting at the given line number.
+ :rtype: tuple(int, int)
+ """
return self. _elsed_block_range(lineno, self.orelse)
class With(mixins.BlockRangeMixIn, mixins.AssignTypeMixin, Statement):
- """class representing a With node"""
+ """Class representing an :class:`ast.With` node.
+
+ >>> node = astroid.extract_node('''
+ with open(file_path) as file_:
+ print(file_.read())
+ ''')
+ >>> node
+ <With l.2 at 0x7f23b2e4e710>
+ """
_astroid_fields = ('items', 'body')
items = None
+ """The pairs of context managers and the names they are assigned to.
+
+ :type: list(tuple(NodeNG, AssignName or None)) or None
+ """
body = None
+ """The contents of the ``with`` block.
+
+ :type: list(NodeNG) or None
+ """
def postinit(self, items=None, body=None):
+ """Do some setup after initialisation.
+
+ :param items: The pairs of context managers and the names
+ they are assigned to.
+ :type items: list(tuple(NodeNG, AssignName or None)) or None
+
+ :param body: The contents of the ``with`` block.
+ :type body: list(NodeNG) or None
+ """
self.items = items
self.body = body
@decorators.cachedproperty
def blockstart_tolineno(self):
+ """The line on which the beginning of this block ends.
+
+ :type: int
+ """
return self.items[-1][0].tolineno
def get_children(self):
+ """Get the child nodes below this node.
+
+ :returns: The children.
+ :rtype: iterable(NodeNG)
+ """
for expr, var in self.items:
yield expr
if var:
@@ -1948,56 +4064,123 @@ class With(mixins.BlockRangeMixIn, mixins.AssignTypeMixin, Statement):
class AsyncWith(With):
- """Asynchronous `with` built with the `async` keyword."""
+ """Asynchronous ``with`` built with the ``async`` keyword."""
class Yield(NodeNG):
- """class representing a Yield node"""
+ """Class representing an :class:`ast.Yield` node.
+
+ >>> node = astroid.extract_node('yield True')
+ >>> node
+ <Yield l.1 at 0x7f23b2e4e5f8>
+ """
_astroid_fields = ('value',)
value = None
+ """The value to yield.
+
+ :type: NodeNG or None
+ """
def postinit(self, value=None):
+ """Do some setup after initialisation.
+
+ :param value: The value to yield.
+ :type value: NodeNG or None
+ """
self.value = value
class YieldFrom(Yield):
- """ Class representing a YieldFrom node. """
+ """Class representing an :class:`ast.YieldFrom` node."""
class DictUnpack(NodeNG):
- """Represents the unpacking of dicts into dicts using PEP 448."""
+ """Represents the unpacking of dicts into dicts using :pep:`448`."""
class FormattedValue(NodeNG):
- """Represents a PEP 498 format string."""
+ """Class representing an :class:`ast.FormattedValue` node.
+
+ Represents a :pep:`498` format string.
+
+ >>> node = astroid.extract_node('f"Format {type_}"')
+ >>> node
+ <JoinedStr l.1 at 0x7f23b2e4ed30>
+ >>> node.values
+ [<Const.str l.1 at 0x7f23b2e4eda0>, <FormattedValue l.1 at 0x7f23b2e4edd8>]
+ """
_astroid_fields = ('value', 'format_spec')
value = None
+ """The value to be formatted into the string.
+
+ :type: NodeNG or None
+ """
conversion = None
+ """The type of formatting to be applied to the value.
+
+ .. seealso::
+ :class:`ast.FormattedValue`
+
+ :type: int or None
+ """
format_spec = None
+ """The formatting to be applied to the value.
+
+ .. seealso::
+ :class:`ast.FormattedValue`
+
+ :type: JoinedStr or None
+ """
def postinit(self, value, conversion=None, format_spec=None):
+ """Do some setup after initialisation.
+
+ :param value: The value to be formatted into the string.
+ :type value: NodeNG
+
+ :param conversion: The type of formatting to be applied to the value.
+ :type conversion: int or None
+
+ :param format_spec: The formatting to be applied to the value.
+ :type format_spec: JoinedStr or None
+ """
self.value = value
self.conversion = conversion
self.format_spec = format_spec
class JoinedStr(NodeNG):
- """Represents a list of string expressions to be joined."""
+ """Represents a list of string expressions to be joined.
+
+ >>> node = astroid.extract_node('f"Format {type_}"')
+ >>> node
+ <JoinedStr l.1 at 0x7f23b2e4ed30>
+ """
_astroid_fields = ('values',)
values = None
+ """The string expressions to be joined.
+
+ :type: list(FormattedValue or Const) or None
+ """
def postinit(self, values=None):
+ """Do some setup after initialisation.
+
+ :param value: The string expressions to be joined.
+
+ :type: list(FormattedValue or Const) or None
+ """
self.values = values
class Unknown(NodeNG):
- '''This node represents a node in a constructed AST where
+ """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.'''
+ """Inference on an Unknown node immediately terminates."""
yield util.Uninferable
diff --git a/astroid/nodes.py b/astroid/nodes.py
index 2b207d02..f9399a56 100644
--- a/astroid/nodes.py
+++ b/astroid/nodes.py
@@ -6,24 +6,12 @@
# 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
-"""
-on all nodes :
- .is_statement, returning true if the node should be considered as a
- statement node
- .root(), returning the root node of the tree (i.e. a Module)
- .previous_sibling(), returning previous sibling statement node
- .next_sibling(), returning next sibling statement node
- .statement(), returning the first parent node marked as statement node
- .frame(), returning the first node defining a new local scope (i.e.
- Module, FunctionDef or ClassDef)
- .set_local(name, node), define an identifier <name> on the first parent frame,
- with the node defining it. This is used by the astroid builder and should not
- be used from out there.
-
-on ImportFrom and Import :
- .real_name(name),
+"""Every available node class.
+.. seealso::
+ :doc:`ast documentation <green_tree_snakes:nodes>`
+All nodes inherit from :class:`~astroid.node_classes.NodeNG`.
"""
# pylint: disable=unused-import,redefined-builtin
diff --git a/astroid/protocols.py b/astroid/protocols.py
index f19a9f41..d7a38f58 100644
--- a/astroid/protocols.py
+++ b/astroid/protocols.py
@@ -484,6 +484,7 @@ def with_assigned_stmts(self, node=None, context=None, asspath=None):
return 42
with ContextManager() as f:
pass
+
# ContextManager().infer() will return ContextManager
# f.infer() will return 42.
diff --git a/astroid/scoped_nodes.py b/astroid/scoped_nodes.py
index 38e23c79..677cc7e1 100644
--- a/astroid/scoped_nodes.py
+++ b/astroid/scoped_nodes.py
@@ -116,14 +116,19 @@ class LocalsDictNodeNG(node_classes.LookupMixIn,
# attributes below are set by the builder module or by raw factories
- # dictionary of locals with name as key and node defining the local as
- # value
-
locals = {}
+ """A map of the name of a local variable to the node defining the local.
+
+ :type: dict(str, NodeNG)
+ """
def qname(self):
- """return the 'qualified' name of the node, eg module.name,
- module.class.name ...
+ """Get the 'qualified' name of the node.
+
+ For example: module.name, module.class.name ...
+
+ :returns: The qualified name.
+ :rtype: str
"""
# pylint: disable=no-member; github.com/pycqa/astroid/issues/278
if self.parent is None:
@@ -131,13 +136,21 @@ class LocalsDictNodeNG(node_classes.LookupMixIn,
return '%s.%s' % (self.parent.frame().qname(), self.name)
def frame(self):
- """return the first parent frame node (i.e. Module, FunctionDef or ClassDef)
+ """The first parent frame node.
+
+ A frame node is a :class:`Module`, :class:`FunctionDef`,
+ or :class:`ClassDef`.
+
+ :returns: The first parent frame node.
+ :rtype: Module or FunctionDef or ClassDef
"""
return self
def scope(self):
- """return the first node defining a new scope (i.e. Module,
- FunctionDef, ClassDef, Lambda but also GeneratorExp, DictComp and SetComp)
+ """The first parent node defining a new scope.
+
+ :returns: The first parent scope node.
+ :rtype: Module or FunctionDef or ClassDef or Lambda or GenExpr
"""
return self
@@ -159,11 +172,15 @@ class LocalsDictNodeNG(node_classes.LookupMixIn,
return builtin_lookup(name) # Module
def set_local(self, name, stmt):
- """define <name> in locals (<stmt> is the node defining the name)
- if the node is a Module node (i.e. has globals), add the name to
- globals
+ """Define that the given name is declared in the given statement node.
+
+ .. seealso:: :meth:`scope`
- if the name is already defined, ignore it
+ :param name: The name that is being defined.
+ :type name: str
+
+ :param stmt: The statement that defines the given name.
+ :type stmt: NodeNG
"""
#assert not stmt in self.locals.get(name, ()), (self, stmt)
self.locals.setdefault(name, []).append(stmt)
@@ -180,85 +197,159 @@ class LocalsDictNodeNG(node_classes.LookupMixIn,
child.parent = self
def add_local_node(self, child_node, name=None):
- """append a child which should alter locals to the given node"""
+ """Append a child that should alter the locals of this scope node.
+
+ :param child_node: The child node that will alter locals.
+ :type child_node: NodeNG
+
+ :param name: The name of the local that will be altered by
+ the given child node.
+ :type name: str or None
+ """
if name != '__class__':
# add __class__ node as a child will cause infinite recursion later!
self._append_node(child_node)
self.set_local(name or child_node.name, child_node)
def __getitem__(self, item):
- """method from the `dict` interface returning the first node
- associated with the given name in the locals dictionary
+ """The first node the defines the given local.
+ :param item: The name of the locally defined object.
:type item: str
- :param item: the name of the locally defined object
- :raises KeyError: if the name is not defined
+
+ :raises KeyError: If the name is not defined.
"""
return self.locals[item][0]
def __iter__(self):
- """method from the `dict` interface returning an iterator on
- `self.keys()`
+ """Iterate over the names of locals defined in this scoped node.
+
+ :returns: The names of the defined locals.
+ :rtype: iterable(str)
"""
return iter(self.keys())
def keys(self):
- """method from the `dict` interface returning a tuple containing
- locally defined names
+ """The names of locals defined in this scoped node.
+
+ :returns: The names of the defined locals.
+ :rtype: list(str)
"""
return list(self.locals.keys())
def values(self):
- """method from the `dict` interface returning a tuple containing
- locally defined nodes which are instance of `FunctionDef` or `ClassDef`
+ """The nodes that define the locals in this scoped node.
+
+ :returns: The nodes that define locals.
+ :rtype: list(NodeNG)
"""
return [self[key] for key in self.keys()]
def items(self):
- """method from the `dict` interface returning a list of tuple
- containing each locally defined name with its associated node,
- which is an instance of `FunctionDef` or `ClassDef`
+ """Get the names of the locals and the node that defines the local.
+
+ :returns: The names of locals and their asociated node.
+ :rtype: list(tuple(str, NodeNG))
"""
return list(zip(self.keys(), self.values()))
def __contains__(self, name):
+ """Check if a local is defined in this scope.
+
+ :param name: The name of the local to check for.
+ :type name: str
+
+ :returns: True if this node has a local of the given name,
+ False otherwise.
+ :rtype: bool
+ """
return name in self.locals
class Module(LocalsDictNodeNG):
+ """Class representing an :class:`ast.Module` node.
+
+ >>> node = astroid.extract_node('import astroid')
+ >>> node
+ <Import l.1 at 0x7f23b2e4e5c0>
+ >>> node.parent
+ <Module l.0 at 0x7f23b2e4eda0>
+ """
_astroid_fields = ('body',)
fromlineno = 0
+ """The first line that this node appears on in the source code.
+
+ :type: int or None
+ """
lineno = 0
+ """The line that this node appears on in the source code.
+
+ :type: int or None
+ """
# attributes below are set by the builder module or by raw factories
- # the file from which as been extracted the astroid representation. It may
- # be None if the representation has been built from a built-in module
file = None
- # Alternatively, if built from a string/bytes, this can be set
+ """The path to the file that this ast has been extracted from.
+
+ This will be ``None`` when the representation has been built from a
+ built-in module.
+
+ :type: str or None
+ """
file_bytes = None
- # encoding of python source file, so we can get unicode out of it (python2
- # only)
+ """The string/bytes that this ast was built from.
+
+ :type: str or bytes or None
+ """
file_encoding = None
- # the module name
+ """The encoding of the source file.
+
+ This is used to get unicode out of a source file.
+ Python 2 only.
+
+ :type: str or None
+ """
name = None
- # boolean for astroid built from source (i.e. ast)
+ """The name of the module.
+
+ :type: str or None
+ """
pure_python = None
- # boolean for package module
+ """Whether the ast was built from source.
+
+ :type: bool or None
+ """
package = None
- # dictionary of globals with name as key and node defining the global
- # as value
+ """Whether the node represents a package or a module.
+
+ :type: bool or None
+ """
globals = None
+ """A map of the name of a global variable to the node defining the global.
+
+ :type: dict(str, NodeNG)
+ """
# Future imports
future_imports = None
+ """The imports from ``__future__``.
+
+ :type: set(str) or None
+ """
special_attributes = objectmodel.ModuleModel()
+ """The names of special attributes that this module has.
- # names of python special attributes (handled by getattr impl.)
+ :type: objectmodel.ModuleModel
+ """
# names of module attributes available through the global scope
scope_attrs = {'__name__', '__doc__', '__file__', '__path__', '__package__'}
+ """The names of module attributes available through the global scope.
+
+ :type: str(str)
+ """
_other_fields = ('name', 'doc', 'file', 'path', 'package',
'pure_python', 'future_imports')
@@ -266,6 +357,28 @@ class Module(LocalsDictNodeNG):
def __init__(self, name, doc, file=None, path=None, package=None,
parent=None, pure_python=True):
+ """
+ :param name: The name of the module.
+ :type name: str
+
+ :param doc: The module docstring.
+ :type doc: str
+
+ :param file: The path to the file that this ast has been extracted from.
+ :type file: str or None
+
+ :param path:
+ :type path: str or None
+
+ :param package: Whether the node represents a package or a module.
+ :type package: bool or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+
+ :param pure_python: Whether the ast was built from source.
+ :type pure_python: bool or None
+ """
self.name = name
self.doc = doc
self.file = file
@@ -274,11 +387,24 @@ class Module(LocalsDictNodeNG):
self.parent = parent
self.pure_python = pure_python
self.locals = self.globals = {}
+ """A map of the name of a local variable to the node defining the local.
+
+ :type: dict(str, NodeNG)
+ """
self.body = []
+ """The contents of the module.
+
+ :type: list(NodeNG) or None
+ """
self.future_imports = set()
# pylint: enable=redefined-builtin
def postinit(self, body=None):
+ """Do some setup after initialisation.
+
+ :param body: The contents of the module.
+ :type body: list(NodeNG) or None
+ """
self.body = body
def _get_stream(self):
@@ -291,6 +417,12 @@ class Module(LocalsDictNodeNG):
@property
def file_stream(self):
+ """Get a stream to the underlying file or bytes.
+
+ .. deprecated:: 1.5
+
+ :type: file or io.BytesIO or None
+ """
warnings.warn("file_stream property is deprecated and "
"it is slated for removal in astroid 1.6."
"Use the new method 'stream' instead.",
@@ -299,11 +431,19 @@ class Module(LocalsDictNodeNG):
return self._get_stream()
def stream(self):
- """Get a stream to the underlying file or bytes."""
+ """Get a stream to the underlying file or bytes.
+
+ .. deprecated:: 1.5
+
+ :type: file or io.BytesIO or None
+ """
return self._get_stream()
def close(self):
- """Close the underlying file streams."""
+ """Close the underlying file streams.
+
+ .. deprecated:: 1.5
+ """
warnings.warn("close method is deprecated and it is "
"slated for removal in astroid 1.6, along "
"with 'file_stream' property. "
@@ -313,13 +453,34 @@ class Module(LocalsDictNodeNG):
stacklevel=2)
def block_range(self, lineno):
- """return block line numbers.
+ """Get a range from where this node starts to where this node ends.
+
+ :param lineno: Unused.
+ :type lineno: int
- start from the beginning whatever the given lineno
+ :returns: The range of line numbers that this node belongs to.
+ :rtype: tuple(int, int)
"""
return self.fromlineno, self.tolineno
def scope_lookup(self, node, name, offset=0):
+ """Lookup where the given variable is assigned.
+
+ :param node: The node to look for assignments up to.
+ Any assignments after the given node are ignored.
+ :type node: NodeNG
+
+ :param name: The name of the variable to find assignments for.
+ :type name: str
+
+ :param offset: The line offset to filter statements up to.
+ :type offset: int
+
+ :returns: This 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).
+ :rtype: tuple(str, list(NodeNG))
+ """
if name in self.scope_attrs and name not in self.locals:
try:
return self, self.getattr(name)
@@ -328,9 +489,19 @@ class Module(LocalsDictNodeNG):
return self._scope_lookup(node, name, offset)
def pytype(self):
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
return '%s.module' % BUILTINS
def display_type(self):
+ """A human readable type of this node.
+
+ :returns: The type of this node.
+ :rtype: str
+ """
return 'Module'
def getattr(self, name, context=None, ignore_locals=False):
@@ -355,7 +526,14 @@ class Module(LocalsDictNodeNG):
context=context)
def igetattr(self, name, context=None):
- """inferred getattr"""
+ """Infer the possible values of the given variable.
+
+ :param name: The name of the variable to infer.
+ :type name: str
+
+ :returns: The inferred possible values.
+ :rtype: iterable(NodeNG) or None
+ """
# set lookup name since this is necessary to infer on import nodes for
# instance
context = contextmod.copy_context(context)
@@ -368,23 +546,38 @@ class Module(LocalsDictNodeNG):
error.message, target=self, attribute=name, context=context))
def fully_defined(self):
- """return True if this module has been built from a .py file
- and so contains a complete representation including the code
+ """Check if this module has been build from a .py file.
+
+ If so, the module contains a complete representation,
+ including the code.
+
+ :returns: True if the module has been built from a .py file.
+ :rtype: bool
"""
return self.file is not None and self.file.endswith('.py')
def statement(self):
- """return the first parent node marked as statement node
- consider a module as a statement...
+ """The first parent node, including self, marked as statement node.
+
+ :returns: The first parent statement.
+ :rtype: NodeNG
"""
return self
def previous_sibling(self):
- """module has no sibling"""
+ """The previous sibling statement.
+
+ :returns: The previous sibling statement node.
+ :rtype: NodeNG or None
+ """
return
def next_sibling(self):
- """module has no sibling"""
+ """The next sibling statement node.
+
+ :returns: The next sibling statement node.
+ :rtype: NodeNG or None
+ """
return
if six.PY2:
@@ -398,10 +591,28 @@ class Module(LocalsDictNodeNG):
_absolute_import_activated = True
def absolute_import_activated(self):
+ """Whether :pep:`328` absolute import behaviour has been enabled.
+
+ :returns: True if :pep:`328` has been enabled, False otherwise.
+ :rtype: bool
+ """
return self._absolute_import_activated
def import_module(self, modname, relative_only=False, level=None):
- """import the given module considering self as context"""
+ """Get the ast for a given module as if imported from this module.
+
+ :param modname: The name of the module to "import".
+ :type modname: str
+
+ :param relative_only: Whether to only consider relative imports.
+ :type relative_only: bool
+
+ :param level: The level of relative import.
+ :type level: int or None
+
+ :returns: The imported module ast.
+ :rtype: NodeNG
+ """
if relative_only and level is None:
level = 0
absmodname = self.relative_to_absolute_name(modname, level)
@@ -416,9 +627,21 @@ class Module(LocalsDictNodeNG):
return MANAGER.ast_from_module_name(modname)
def relative_to_absolute_name(self, modname, level):
- """return the absolute module name for a relative import.
+ """Get the absolute module name for a relative import.
The relative import can be implicit or explicit.
+
+ :param modname: The module name to convert.
+ :type modname: str
+
+ :param level: The level of relative import.
+ :type level: int
+
+ :returns: The absolute module name.
+ :rtype: str
+
+ :raises TooManyLevelsError: When the relative import refers to a
+ module too far above this one.
"""
# XXX this returns non sens when called on an absolute import
# like 'pylint.checkers.astroid.utils'
@@ -445,11 +668,13 @@ class Module(LocalsDictNodeNG):
return modname
def wildcard_import_names(self):
- """return the list of imported names when this module is 'wildcard
- imported'
+ """The list of imported names when this module is 'wildcard imported'.
It doesn't include the '__builtins__' name which is added by the
current CPython implementation of wildcard imports.
+
+ :returns: The list of imported names.
+ :rtype: list(str)
"""
# We separate the different steps of lookup in try/excepts
# to avoid catching too many Exceptions
@@ -492,31 +717,88 @@ class Module(LocalsDictNodeNG):
return inferred
def public_names(self):
- """Get the list of the names which are publicly available in this module."""
+ """The list of the names that are publicly available in this module.
+
+ :returns: The list of publc names.
+ :rtype: list(str)
+ """
return [name for name in self.keys() if not name.startswith('_')]
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ For a :class:`Module` this is always ``True``.
+ :rtype: bool
+ """
return True
class ComprehensionScope(LocalsDictNodeNG):
+ """Scoping for different types of comprehensions."""
def frame(self):
+ """The first parent frame node.
+
+ A frame node is a :class:`Module`, :class:`FunctionDef`,
+ or :class:`ClassDef`.
+
+ :returns: The first parent frame node.
+ :rtype: Module or FunctionDef or ClassDef
+ """
return self.parent.frame()
scope_lookup = LocalsDictNodeNG._scope_lookup
class GeneratorExp(ComprehensionScope):
+ """Class representing an :class:`ast.GeneratorExp` node.
+
+ >>> node = astroid.extract_node('(thing for thing in things if thing)')
+ >>> node
+ <GeneratorExp l.1 at 0x7f23b2e4e400>
+ """
_astroid_fields = ('elt', 'generators')
_other_other_fields = ('locals',)
elt = None
+ """The element that forms the output of the expression.
+
+ :type: NodeNG or None
+ """
generators = None
+ """The generators that are looped through.
+
+ :type: list(Comprehension) or None
+ """
def __init__(self, lineno=None, col_offset=None, parent=None):
+ """
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.locals = {}
+ """A map of the name of a local variable to the node defining the local.
+
+ :type: dict(str, NodeNG)
+ """
+
super(GeneratorExp, self).__init__(lineno, col_offset, parent)
def postinit(self, elt=None, generators=None):
+ """Do some setup after initialisation.
+
+ :param elt: The element that forms the output of the expression.
+ :type elt: NodeNG or None
+
+ :param generators: The generators that are looped through.
+ :type generators: list(Comprehension) or None
+ """
self.elt = elt
if generators is None:
self.generators = []
@@ -524,21 +806,72 @@ class GeneratorExp(ComprehensionScope):
self.generators = generators
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ For a :class:`GeneratorExp` this is always ``True``.
+ :rtype: bool
+ """
return True
class DictComp(ComprehensionScope):
+ """Class representing an :class:`ast.DictComp` node.
+
+ >>> node = astroid.extract_node('{k:v for k, v in things if k > v}')
+ >>> node
+ <DictComp l.1 at 0x7f23b2e41d68>
+ """
_astroid_fields = ('key', 'value', 'generators')
_other_other_fields = ('locals',)
key = None
+ """What produces the keys.
+
+ :type: NodeNG or None
+ """
value = None
+ """What produces the values.
+
+ :type: NodeNG or None
+ """
generators = None
+ """The generators that are looped through.
+
+ :type: list(Comprehension) or None
+ """
def __init__(self, lineno=None, col_offset=None, parent=None):
+ """
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.locals = {}
+ """A map of the name of a local variable to the node defining the local.
+
+ :type: dict(str, NodeNG)
+ """
+
super(DictComp, self).__init__(lineno, col_offset, parent)
def postinit(self, key=None, value=None, generators=None):
+ """Do some setup after initialisation.
+
+ :param key: What produces the keys.
+ :type key: NodeNG or None
+
+ :param value: What produces the values.
+ :type value: NodeNG or None
+
+ :param generators: The generators that are looped through.
+ :type generators: list(Comprehension) or None
+ """
self.key = key
self.value = value
if generators is None:
@@ -547,20 +880,64 @@ class DictComp(ComprehensionScope):
self.generators = generators
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ For a :class:`DictComp` this is always :class:`Uninferable`.
+ :rtype: Uninferable
+ """
return util.Uninferable
class SetComp(ComprehensionScope):
+ """Class representing an :class:`ast.SetComp` node.
+
+ >>> node = astroid.extract_node('{thing for thing in things if thing}')
+ >>> node
+ <SetComp l.1 at 0x7f23b2e41898>
+ """
_astroid_fields = ('elt', 'generators')
_other_other_fields = ('locals',)
elt = None
+ """The element that forms the output of the expression.
+
+ :type: NodeNG or None
+ """
generators = None
+ """The generators that are looped through.
+
+ :type: list(Comprehension) or None
+ """
def __init__(self, lineno=None, col_offset=None, parent=None):
+ """
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.locals = {}
+ """A map of the name of a local variable to the node defining the local.
+
+ :type: dict(str, NodeNG)
+ """
+
super(SetComp, self).__init__(lineno, col_offset, parent)
def postinit(self, elt=None, generators=None):
+ """Do some setup after initialisation.
+
+ :param elt: The element that forms the output of the expression.
+ :type elt: NodeNG or None
+
+ :param generators: The generators that are looped through.
+ :type generators: list(Comprehension) or None
+ """
self.elt = elt
if generators is None:
self.generators = []
@@ -568,34 +945,82 @@ class SetComp(ComprehensionScope):
self.generators = generators
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ For a :class:`SetComp` this is always :class:`Uninferable`.
+ :rtype: Uninferable
+ """
return util.Uninferable
class _ListComp(node_classes.NodeNG):
- """class representing a ListComp node"""
+ """Class representing an :class:`ast.ListComp` node.
+
+ >>> node = astroid.extract_node('[thing for thing in things if thing]')
+ >>> node
+ <ListComp l.1 at 0x7f23b2e418d0>
+ """
_astroid_fields = ('elt', 'generators')
elt = None
+ """The element that forms the output of the expression.
+
+ :type: NodeNG or None
+ """
generators = None
+ """The generators that are looped through.
+
+ :type: list(Comprehension) or None
+ """
def postinit(self, elt=None, generators=None):
+ """Do some setup after initialisation.
+
+ :param elt: The element that forms the output of the expression.
+ :type elt: NodeNG or None
+
+ :param generators: The generators that are looped through.
+ :type generators: list(Comprehension) or None
+ """
self.elt = elt
self.generators = generators
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ For a :class:`ListComp` this is always :class:`Uninferable`.
+ :rtype: Uninferable
+ """
return util.Uninferable
if six.PY3:
class ListComp(_ListComp, ComprehensionScope):
- """class representing a ListComp node"""
+ """Class representing an :class:`ast.ListComp` node.
+
+ >>> node = astroid.extract_node('[thing for thing in things if thing]')
+ >>> node
+ <ListComp l.1 at 0x7f23b2e418d0>
+ """
_other_other_fields = ('locals',)
def __init__(self, lineno=None, col_offset=None, parent=None):
self.locals = {}
+ """A map of the name of a local variable to the node defining it.
+
+ :type: dict(str, NodeNG)
+ """
+
super(ListComp, self).__init__(lineno, col_offset, parent)
else:
class ListComp(_ListComp):
- """class representing a ListComp node"""
+ """Class representing an :class:`ast.ListComp` node.
+
+ >>> node = astroid.extract_node('[thing for thing in things if thing]')
+ >>> node
+ <ListComp l.1 at 0x7f23b2e418d0>
+ """
def _infer_decorator_callchain(node):
@@ -624,6 +1049,12 @@ def _infer_decorator_callchain(node):
class Lambda(mixins.FilterStmtsMixin, LocalsDictNodeNG):
+ """Class representing an :class:`ast.Lambda` node.
+
+ >>> node = astroid.extract_node('lambda arg: arg + 1')
+ >>> node
+ <Lambda.<lambda> l.1 at 0x7f23b2e41518>
+ """
_astroid_fields = ('args', 'body',)
_other_other_fields = ('locals',)
name = '<lambda>'
@@ -631,6 +1062,11 @@ class Lambda(mixins.FilterStmtsMixin, LocalsDictNodeNG):
# function's type, 'function' | 'method' | 'staticmethod' | 'classmethod'
@property
def type(self):
+ """Whether this is a method or function.
+
+ :returns: 'method' if this is a method, 'function' otherwise.
+ :rtype: str
+ """
# pylint: disable=no-member
if self.args.args and self.args.args[0].name == 'self':
if isinstance(self.parent.scope(), ClassDef):
@@ -638,30 +1074,85 @@ class Lambda(mixins.FilterStmtsMixin, LocalsDictNodeNG):
return 'function'
def __init__(self, lineno=None, col_offset=None, parent=None):
+ """
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.locals = {}
+ """A map of the name of a local variable to the node defining it.
+
+ :type: dict(str, NodeNG)
+ """
+
self.args = []
+ """The arguments that the function takes.
+
+ :type: Arguments or list
+ """
+
self.body = []
+ """The contents of the function body.
+
+ :type: list(NodeNG)
+ """
+
super(Lambda, self).__init__(lineno, col_offset, parent)
def postinit(self, args, body):
+ """Do some setup after initialisation.
+
+ :param args: The arguments that the function takes.
+ :type args: Arguments
+
+ :param body: The contents of the function body.
+ :type body: list(NodeNG)
+ """
self.args = args
self.body = body
def pytype(self):
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
if 'method' in self.type:
return '%s.instancemethod' % BUILTINS
return '%s.function' % BUILTINS
def display_type(self):
+ """A human readable type of this node.
+
+ :returns: The type of this node.
+ :rtype: str
+ """
if 'method' in self.type:
return 'Method'
return 'Function'
def callable(self):
+ """Whether this node defines something that is callable.
+
+ :returns: True if this defines something that is callable,
+ False otherwise.
+ For a :class:`Lambda` this is always ``True``.
+ :rtype: bool
+ """
return True
def argnames(self):
- """return a list of argument names"""
+ """Get the names of each of the arguments.
+
+ :returns: The names of the arguments.
+ :rtype: list(str)
+ """
# pylint: disable=no-member; github.com/pycqa/astroid/issues/291
# args is in fact redefined later on by postinit. Can't be changed
# to None due to a strong interaction between Lambda and FunctionDef.
@@ -677,7 +1168,11 @@ class Lambda(mixins.FilterStmtsMixin, LocalsDictNodeNG):
return names
def infer_call_result(self, caller, context=None):
- """infer what a function is returning when called"""
+ """Infer what the function returns when called.
+
+ :param caller: Unused
+ :type caller: object
+ """
# pylint: disable=no-member; github.com/pycqa/astroid/issues/291
# args is in fact redefined later on by postinit. Can't be changed
# to None due to a strong interaction between Lambda and FunctionDef.
@@ -685,6 +1180,23 @@ class Lambda(mixins.FilterStmtsMixin, LocalsDictNodeNG):
return self.body.infer(context)
def scope_lookup(self, node, name, offset=0):
+ """Lookup where the given names is assigned.
+
+ :param node: The node to look for assignments up to.
+ Any assignments after the given node are ignored.
+ :type node: NodeNG
+
+ :param name: The name to find assignments for.
+ :type name: str
+
+ :param offset: The line offset to filter statements up to.
+ :type offset: int
+
+ :returns: This 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).
+ :rtype: tuple(str, list(NodeNG))
+ """
# pylint: disable=no-member; github.com/pycqa/astroid/issues/291
# args is in fact redefined later on by postinit. Can't be changed
# to None due to a strong interaction between Lambda and FunctionDef.
@@ -700,18 +1212,47 @@ class Lambda(mixins.FilterStmtsMixin, LocalsDictNodeNG):
return frame._scope_lookup(node, name, offset)
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ For a :class:`Lambda` this is always ``True``.
+ :rtype: bool
+ """
return True
class FunctionDef(node_classes.Statement, Lambda):
+ """Class representing an :class:`ast.FunctionDef`.
+
+ >>> node = astroid.extract_node('''
+ ... def my_func(arg):
+ ... return arg + 1
+ ... ''')
+ >>> node
+ <FunctionDef.my_func l.2 at 0x7f23b2e71e10>
+ """
if six.PY3:
_astroid_fields = ('decorators', 'args', 'returns', 'body')
returns = None
else:
_astroid_fields = ('decorators', 'args', 'body')
decorators = None
+ """The decorators that are applied to this method or function.
+
+ :type: Decorators or None
+ """
special_attributes = objectmodel.FunctionModel()
+ """The names of special attributes that this function has.
+
+ :type: objectmodel.FunctionModel
+ """
is_function = True
+ """Whether this node indicates a function.
+
+ For a :class:`FunctionDef` this is always ``True``.
+
+ :type: bool
+ """
# attributes below are set by the builder module or by raw factories
_other_fields = ('name', 'doc')
_other_other_fields = ('locals', '_type')
@@ -719,8 +1260,35 @@ class FunctionDef(node_classes.Statement, Lambda):
def __init__(self, name=None, doc=None, lineno=None,
col_offset=None, parent=None):
+ """
+ :param name: The name of the function.
+ :type name: str or None
+
+ :param doc: The function's docstring.
+ :type doc: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.name = name
+ """The name of the function.
+
+ :type name: str or None
+ """
+
self.doc = doc
+ """The function's docstring.
+
+ :type doc: str or None
+ """
+
self.instance_attrs = {}
super(FunctionDef, self).__init__(lineno, col_offset, parent)
if parent:
@@ -729,6 +1297,18 @@ class FunctionDef(node_classes.Statement, Lambda):
# pylint: disable=arguments-differ; different than Lambdas
def postinit(self, args, body, decorators=None, returns=None):
+ """Do some setup after initialisation.
+
+ :param args: The arguments that the function takes.
+ :type args: Arguments or list
+
+ :param body: The contents of the function body.
+ :type body: list(NodeNG)
+
+ :param decorators: The decorators that are applied to this
+ method or function.
+ :type decorators: Decorators or None
+ """
self.args = args
self.body = body
self.decorators = decorators
@@ -739,11 +1319,14 @@ class FunctionDef(node_classes.Statement, Lambda):
@decorators_mod.cachedproperty
def extra_decorators(self):
- """Get the extra decorators that this function can haves
+ """The extra decorators that this function can have.
+
Additional decorators are considered when they are used as
- assignments, as in `method = staticmethod(method)`.
+ assignments, as in ``method = staticmethod(method)``.
The property will return all the callables that are used for
decoration.
+
+ :type: list(NodeNG)
"""
frame = self.parent.frame()
if not isinstance(frame, ClassDef):
@@ -776,9 +1359,11 @@ class FunctionDef(node_classes.Statement, Lambda):
@decorators_mod.cachedproperty
def type(self):
- """Get the function type for this node.
+ """The function type for this node.
Possible values are: method, function, staticmethod, classmethod.
+
+ :type: str
"""
builtin_descriptors = {'classmethod', 'staticmethod'}
@@ -839,6 +1424,10 @@ class FunctionDef(node_classes.Statement, Lambda):
@decorators_mod.cachedproperty
def fromlineno(self):
+ """The first line that this node appears on in the source code.
+
+ :type: int or None
+ """
# lineno is the line number of the first decorator, we want the def
# statement lineno
lineno = self.lineno
@@ -850,12 +1439,20 @@ class FunctionDef(node_classes.Statement, Lambda):
@decorators_mod.cachedproperty
def blockstart_tolineno(self):
+ """The line on which the beginning of this block ends.
+
+ :type: int
+ """
return self.args.tolineno
def block_range(self, lineno):
- """return block line numbers.
+ """Get a range from the given line number to where this node ends.
+
+ :param lineno: Unused.
+ :type lineno: int
- start from the "def" position whatever the given lineno
+ :returns: The range of line numbers that this node belongs to,
+ :rtype: tuple(int, int)
"""
return self.fromlineno, self.tolineno
@@ -879,14 +1476,22 @@ class FunctionDef(node_classes.Statement, Lambda):
error.message, target=self, attribute=name, context=context))
def is_method(self):
- """return true if the function node should be considered as a method"""
+ """Check if this function node represents a method.
+
+ :returns: True if this is a method, False otherwise.
+ :rtype: bool
+ """
# check we are defined in a ClassDef, because this is usually expected
# (e.g. pylint...) when is_method() return True
return self.type != 'function' and isinstance(self.parent.frame(), ClassDef)
@decorators_mod.cached
def decoratornames(self):
- """return a list of decorator qualified names"""
+ """Get the qualified names of each of the decorators on this function.
+
+ :returns: The names of the decorators.
+ :rtype: set(str)
+ """
result = set()
decoratornodes = []
if self.decorators is not None:
@@ -901,16 +1506,24 @@ class FunctionDef(node_classes.Statement, Lambda):
return result
def is_bound(self):
- """return true if the function is bound to an Instance or a class"""
+ """Check if the function is bound to an instance or class.
+
+ :returns: True if the function is bound to an instance or class,
+ False otherwise.
+ :rtype: bool
+ """
return self.type == 'classmethod'
def is_abstract(self, pass_is_abstract=True):
- """Returns True if the method is abstract.
+ """Check if the method is abstract.
- A method is considered abstract if
- - the only statement is 'raise NotImplementedError', or
- - the only statement is 'pass' and pass_is_abstract is True, or
- - the method is annotated with abc.astractproperty/abc.abstractmethod
+ A method is considered abstract if any of the following is true:
+ * The only statement is 'raise NotImplementedError'
+ * The only statement is 'pass' and pass_is_abstract is True
+ * The method is annotated with abc.astractproperty/abc.abstractmethod
+
+ :returns: True if the method is abstract, False otherwise.
+ :rtype: bool
"""
if self.decorators:
for node in self.decorators.nodes:
@@ -932,13 +1545,21 @@ class FunctionDef(node_classes.Statement, Lambda):
return True
def is_generator(self):
- """return true if this is a generator function"""
+ """Check if this is a generator function.
+
+ :returns: True is this is a generator function, False otherwise.
+ :rtype: bool
+ """
yield_nodes = (node_classes.Yield, node_classes.YieldFrom)
return next(self.nodes_of_class(yield_nodes,
skip_klass=(FunctionDef, Lambda)), False)
def infer_call_result(self, caller, context=None):
- """infer what a function is returning when called"""
+ """Infer what the function returns when called.
+
+ :returns: What the function returns.
+ :rtype: iterable(NodeNG or Uninferable) or None
+ """
if self.is_generator():
result = bases.Generator(self)
yield result
@@ -974,11 +1595,31 @@ class FunctionDef(node_classes.Statement, Lambda):
yield util.Uninferable
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ For a :class:`FunctionDef` this is always ``True``.
+ :rtype: bool
+ """
return True
class AsyncFunctionDef(FunctionDef):
- """Asynchronous function created with the `async` keyword."""
+ """Class representing an :class:`ast.FunctionDef` node.
+
+ A :class:`AsyncFunctionDef` is an asynchronous function
+ created with the `async` keyword.
+
+ >>> node = astroid.extract_node('''
+ async def func(things):
+ async for thing in things:
+ print(thing)
+ ''')
+ >>> node
+ <AsyncFunctionDef.func l.2 at 0x7f23b2e416d8>
+ >>> node.body[0]
+ <AsyncFor l.3 at 0x7f23b2e417b8>
+ """
def _rec_get_names(args, names=None):
@@ -1062,10 +1703,13 @@ def _class_type(klass, ancestors=None):
def get_wrapping_class(node):
- """Obtain the class that *wraps* this node
+ """Get the class that wraps the given node.
We consider that a class wraps a node if the class
is a parent for the said node.
+
+ :returns: The class that wraps the given node
+ :rtype: ClassDef or None
"""
klass = node.frame()
@@ -1080,6 +1724,16 @@ def get_wrapping_class(node):
class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
node_classes.Statement):
+ """Class representing an :class:`ast.ClassDef` node.
+
+ >>> node = astroid.extract_node('''
+ class Thing:
+ def my_meth(self, arg):
+ return arg + self.offset
+ ''')
+ >>> node
+ <ClassDef.Thing l.2 at 0x7f23b2e9e748>
+ """
# some of the attributes below are set by the builder module or
# by a raw factories
@@ -1088,33 +1742,111 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
_astroid_fields = ('decorators', 'bases', 'body') # name
decorators = None
+ """The decorators that are applied to this class.
+
+ :type: Decorators or None
+ """
special_attributes = objectmodel.ClassModel()
+ """The names of special attributes that this class has.
+
+ :type: objectmodel.ClassModel
+ """
_type = None
_metaclass_hack = False
hide = False
type = property(_class_type,
- doc="class'type, possible values are 'class' | "
- "'metaclass' | 'exception'")
+ doc=("The class type for this node.\n\n"
+ "Possible values are: class, metaclass, exception.\n\n"
+ ":type: str"))
_other_fields = ('name', 'doc')
_other_other_fields = ('locals', '_newstyle')
_newstyle = None
def __init__(self, name=None, doc=None, lineno=None,
col_offset=None, parent=None):
+ """
+ :param name: The name of the class.
+ :type name: str or None
+
+ :param doc: The function's docstring.
+ :type doc: str or None
+
+ :param lineno: The line that this node appears on in the source code.
+ :type lineno: int or None
+
+ :param col_offset: The column that this node appears on in the
+ source code.
+ :type col_offset: int or None
+
+ :param parent: The parent node in the syntax tree.
+ :type parent: NodeNG or None
+ """
self.instance_attrs = {}
self.locals = {}
+ """A map of the name of a local variable to the node defining it.
+
+ :type: dict(str, NodeNG)
+ """
+
self.keywords = []
+ """The keywords given to the class definition.
+
+ This is usually for :pep:`3115` style metaclass declaration.
+
+ :type: list(Keyword) or None
+ """
+
self.bases = []
+ """What the class inherits from.
+
+ :type: list(NodeNG)
+ """
+
self.body = []
+ """The contents of the class body.
+
+ :type: list(NodeNG)
+ """
+
self.name = name
+ """The name of the class.
+
+ :type name: str or None
+ """
+
self.doc = doc
+ """The class' docstring.
+
+ :type doc: str or None
+ """
+
super(ClassDef, self).__init__(lineno, col_offset, parent)
if parent is not None:
parent.frame().set_local(name, self)
# pylint: disable=redefined-outer-name
def postinit(self, bases, body, decorators, newstyle=None, metaclass=None, keywords=None):
+ """Do some setup after initialisation.
+
+ :param bases: What the class inherits from.
+ :type bases: list(NodeNG)
+
+ :param body: The contents of the class body.
+ :type body: list(NodeNG)
+
+ :param decorators: The decorators that are applied to this class.
+ :type decorators: Decorators or None
+
+ :param newstyle: Whether this is a new style class or not.
+ :type newstyle: bool or None
+
+ :param metaclass: The metaclass of this class.
+ :type metaclass: NodeNG or None
+
+ :param keywords: The keywords given to the class definition.
+ :type keywords: list(Keyword) or None
+ """
self.keywords = keywords
self.bases = bases
self.body = body
@@ -1144,35 +1876,69 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
_newstyle = None
newstyle = property(_newstyle_impl,
- doc="boolean indicating if it's a new style class"
- "or not")
+ doc=("Whether this is a new style class or not\n\n"
+ ":type: bool or None"))
@decorators_mod.cachedproperty
def blockstart_tolineno(self):
+ """The line on which the beginning of this block ends.
+
+ :type: int
+ """
if self.bases:
return self.bases[-1].tolineno
return self.fromlineno
def block_range(self, lineno):
- """return block line numbers.
+ """Get a range from the given line number to where this node ends.
+
+ :param lineno: Unused.
+ :type lineno: int
- start from the "class" position whatever the given lineno
+ :returns: The range of line numbers that this node belongs to,
+ :rtype: tuple(int, int)
"""
return self.fromlineno, self.tolineno
def pytype(self):
+ """Get the name of the type that this node represents.
+
+ :returns: The name of the type.
+ :rtype: str
+ """
if self.newstyle:
return '%s.type' % BUILTINS
return '%s.classobj' % BUILTINS
def display_type(self):
+ """A human readable type of this node.
+
+ :returns: The type of this node.
+ :rtype: str
+ """
return 'Class'
def callable(self):
+ """Whether this node defines something that is callable.
+
+ :returns: True if this defines something that is callable,
+ False otherwise.
+ For a :class:`ClassDef` this is always ``True``.
+ :rtype: bool
+ """
return True
def is_subtype_of(self, type_name, context=None):
+ """Whether this class is a subtype of the given type.
+
+ :param type_name: The name of the type of check against.
+ :type type_name: str
+
+ :returns: True if this class is a subtype of the given type,
+ False otherwise.
+ :rtype: bool
+ """
if self.qname() == type_name:
return True
for anc in self.ancestors(context=context):
@@ -1225,6 +1991,23 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
yield bases.Instance(self)
def scope_lookup(self, node, name, offset=0):
+ """Lookup where the given name is assigned.
+
+ :param node: The node to look for assignments up to.
+ Any assignments after the given node are ignored.
+ :type node: NodeNG
+
+ :param name: The name to find assignments for.
+ :type name: str
+
+ :param offset: The line offset to filter statements up to.
+ :type offset: int
+
+ :returns: This 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).
+ :rtype: tuple(str, list(NodeNG))
+ """
# If the name looks like a builtin name, just try to look
# into the upper scope of this class. We might have a
# decorator that it's poorly named after a builtin object
@@ -1258,16 +2041,22 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
@property
def basenames(self):
- """Get the list of parent class names, as they appear in the class definition."""
+ """The names of the parent classes
+
+ Names are given in the order they appear in the class definition.
+
+ :type: list(str)
+ """
return [bnode.as_string() for bnode in self.bases]
def ancestors(self, recurs=True, context=None):
- """return an iterator on the node base classes in a prefixed
- depth first order
+ """Iterate over the base classes in prefixed depth first order.
+
+ :param recurs: Whether to recurse or return direct ancestors only.
+ :type recurs: bool
- :param recurs:
- boolean indicating if it should recurse or return direct
- ancestors only
+ :returns: The base classes
+ :rtype: iterable(NodeNG)
"""
# FIXME: should be possible to choose the resolution order
# FIXME: inference make infinite loops possible here
@@ -1307,8 +2096,13 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
continue
def local_attr_ancestors(self, name, context=None):
- """return an iterator on astroid representation of parent classes
- which have <name> defined in their locals
+ """Iterate over the parents that define the given name.
+
+ :param name: The name to find definitions for.
+ :type name: str
+
+ :returns: The parents that define the given name.
+ :rtype: iterable(NodeNG)
"""
if self.newstyle and all(n.newstyle for n in self.ancestors(context)):
# Look up in the mro if we can. This will result in the
@@ -1326,23 +2120,40 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
yield astroid
def instance_attr_ancestors(self, name, context=None):
- """return an iterator on astroid representation of parent classes
- which have <name> defined in their instance attribute dictionary
+ """Iterate over the parents that define the given name as an attribute.
+
+ :param name: The name to find definitions for.
+ :type name: str
+
+ :returns: The parents that define the given name as
+ an instance attribute.
+ :rtype: iterable(NodeNG)
"""
for astroid in self.ancestors(context=context):
if name in astroid.instance_attrs:
yield astroid
def has_base(self, node):
+ """Whether this class directly inherits from the given node.
+
+ :param node: The node to check for.
+ :type node: NodeNG
+
+ :returns: True if this class directly inherits from the given node.
+ :rtype: bool
+ """
return node in self.bases
def local_attr(self, name, context=None):
- """return the list of assign node associated to name in this class
- locals or in its parents
+ """Get the list of assign nodes associated to the given name.
+
+ Assignments are looked for in both this class and in parents.
+
+ :returns: The list of assignments to the given name.
+ :rtype: list(NodeNG)
- :raises `AttributeInferenceError`:
- if no attribute with this name has been find in this class or
- its parent classes
+ :raises AttributeInferenceError: If no attribute with this name
+ can be found in this class or parent classes.
"""
result = []
if name in self.locals:
@@ -1358,12 +2169,15 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
context=context)
def instance_attr(self, name, context=None):
- """return the astroid nodes associated to name in this class instance
- attributes dictionary and in its parents
+ """Get the list of nodes associated to the given attribute name.
- :raises `AttributeInferenceError`:
- if no attribute with this name has been find in this class or
- its parent classes
+ Assignments are looked for in both this class and in parents.
+
+ :returns: The list of assignments to the given name.
+ :rtype: list(NodeNG)
+
+ :raises AttributeInferenceError: If no attribute with this name
+ can be found in this class or parent classes.
"""
# Return a copy, so we don't modify self.instance_attrs,
# which could lead to infinite loop.
@@ -1378,10 +2192,23 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
context=context)
def instantiate_class(self):
- """return Instance of ClassDef node, else return self"""
+ """Get an :class:`Instance` of the :class:`ClassDef` node.
+
+ :returns: An :class:`Instance` of the :class:`ClassDef` node,
+ or self if this is not possible.
+ :rtype: Instance or ClassDef
+ """
return bases.Instance(self)
def instanciate_class(self):
+ """A deprecated alias for :meth:`instanciate_class`.
+
+ .. deprecated:: 1.5
+
+ :returns: An :class:`Instance` of the :class:`ClassDef` node,
+ or self if this is not possible.
+ :rtype: Instance or ClassDef
+ """
warnings.warn('%s.instanciate_class() is deprecated and slated for '
'removal in astroid 2.0, use %s.instantiate_class() '
'instead.' % (type(self).__name__, type(self).__name__),
@@ -1389,19 +2216,30 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
return self.instantiate_class()
def getattr(self, name, context=None, class_context=True):
- """Get an attribute from this class, using Python's attribute semantic
-
- This method doesn't look in the instance_attrs dictionary
- since it's done by an Instance proxy at inference time. It
- may return a Uninferable object if the attribute has not been actually
- found but a __getattr__ or __getattribute__ method is defined.
- If *class_context* is given, then it's considered that the
+ """Get an attribute from this class, using Python's attribute semantic.
+
+ This method doesn't look in the :attr:`instance_attrs` dictionary
+ since it is done by an :class:`Instance` proxy at inference time.
+ It may return an :class:`Uninferable` object if
+ the attribute has not been
+ found, but a ``__getattr__`` or ``__getattribute__`` method is defined.
+ If ``class_context`` is given, then it is considered that the
attribute is accessed from a class context,
e.g. ClassDef.attribute, otherwise it might have been accessed
- from an instance as well. If *class_context* is used in that
+ from an instance as well. If ``class_context`` is used in that
case, then a lookup in the implicit metaclass and the explicit
metaclass will be done.
+ :param name: The attribute to look for.
+ :type name: str
+
+ :param class_context: Whether the attribute can be accessed statically.
+ :type class_context: bool
+
+ :returns: The attribute.
+ :rtype: list(NodeNG)
+
+ :raises AttributeInferenceError: If the attribute cannot be inferred.
"""
values = self.locals.get(name, [])
if name in self.special_attributes and class_context and not values:
@@ -1468,8 +2306,13 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
yield bases.BoundMethod(attr, self)
def igetattr(self, name, context=None, class_context=True):
- """inferred getattr, need special treatment in class to handle
- descriptors
+ """Infer the possible values of the given variable.
+
+ :param name: The name of the variable to infer.
+ :type name: str
+
+ :returns: The inferred possible values.
+ :rtype: iterable(NodeNG or Uninferable)
"""
# set lookup name since this is necessary to infer on import nodes for
# instance
@@ -1498,13 +2341,15 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
error.message, target=self, attribute=name, context=context))
def has_dynamic_getattr(self, context=None):
- """
- Check if the current instance has a custom __getattr__
- or a custom __getattribute__.
+ """Check if the class has a custom __getattr__ or __getattribute__.
If any such method is found and it is not from
builtins, nor from an extension module, then the function
will return True.
+
+ :returns: True if the class has a custom
+ __getattr__ or __getattribute__, False otherwise.
+ :rtype: bool
"""
def _valid_getattr(node):
root = node.root()
@@ -1525,6 +2370,12 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
"""Return the inference of a subscript.
This is basically looking up the method in the metaclass and calling it.
+
+ :returns: The inferred value of a subscript to this class.
+ :rtype: NodeNG
+
+ :raises AstroidTypeError: If this class does not define a
+ ``__getitem__`` method.
"""
try:
methods = dunder_lookup.lookup(self, '__getitem__')
@@ -1550,8 +2401,10 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
return next(method.infer_call_result(self, new_context))
def methods(self):
- """return an iterator on all methods defined in the class and
- its ancestors
+ """Iterate over all of the method defined in this class and its parents.
+
+ :returns: The methods defined on the class.
+ :rtype: iterable(FunctionDef)
"""
done = {}
for astroid in itertools.chain(iter((self,)), self.ancestors()):
@@ -1562,19 +2415,25 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
yield meth
def mymethods(self):
- """return an iterator on all methods defined in the class"""
+ """Iterate over all of the method defined in this class only.
+
+ :returns: The methods defined on the class.
+ :rtype: iterable(FunctionDef)
+ """
for member in self.values():
if isinstance(member, FunctionDef):
yield member
def implicit_metaclass(self):
- """Get the implicit metaclass of the current class
+ """Get the implicit metaclass of the current class.
For newstyle classes, this will return an instance of builtins.type.
For oldstyle classes, it will simply return None, since there's
no implicit metaclass there.
- """
+ :returns: The metaclass.
+ :rtype: builtins.type or None
+ """
if self.newstyle:
return builtin_lookup('type')[1][0]
return None
@@ -1588,6 +2447,10 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
in the class definition line (Python 3) or (Python 2) by
having a ``__metaclass__`` class attribute, or if there are
no explicit bases but there is a global ``__metaclass__`` variable.
+
+ :returns: The metaclass of this class,
+ or None if one could not be found.
+ :rtype: NodeNG or None
"""
for base in self.bases:
try:
@@ -1645,11 +2508,14 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
return klass
def metaclass(self):
- """Return the metaclass of this class.
+ """Get the metaclass of this class.
If this class does not define explicitly a metaclass,
then the first defined metaclass in ancestors will be used
instead.
+
+ :returns: The metaclass of this class.
+ :rtype: NodeNG or None
"""
return self._find_metaclass()
@@ -1727,10 +2593,11 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
def slots(self):
"""Get all the slots for this node.
- If the class doesn't define any slot, through `__slots__`
- variable, then this function will return a None.
- Also, it will return None in the case the slots weren't inferred.
- Otherwise, it will return a list of slot names.
+ :returns: The names of slots for this class.
+ If the class doesn't define any slot, through the ``__slots__``
+ variable, then this function will return a None.
+ Also, it will return None in the case the slots were not inferred.
+ :rtype: list(str) or None
"""
def grouped_slots():
# Not interested in object, since it can't have slots.
@@ -1818,9 +2685,11 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
def mro(self, context=None):
"""Get the method resolution order, using C3 linearization.
- It returns the list of ancestors sorted by the mro.
- This will raise `NotImplementedError` for old-style classes, since
- they don't have the concept of MRO.
+ :returns: The list of ancestors, sorted by the mro.
+ :rtype: list(NodeNG)
+
+ :raises NotImplementedError: If this is an old style class,
+ since they don't have the concept of an MRO.
"""
if not self.newstyle:
@@ -1830,6 +2699,12 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
return self._compute_mro(context=context)
def bool_value(self):
+ """Determine the boolean value of this node.
+
+ :returns: The boolean value of this node.
+ For a :class:`ClassDef` this is always ``True``.
+ :rtype: bool
+ """
return True