.. _inference: Inference Introduction ====================== What/where is 'inference' ? --------------------------- The inference is a mechanism through which *astroid* tries to interpret statically your Python code. How does it work ? ------------------ The magic is handled by :meth:`NodeNG.infer` method. *astroid* usually provides inference support for various Python primitives, such as protocols and statements, but it can also be enriched via `inference transforms`. In both cases the :meth:`infer` must return a *generator* which iterates through the various *values* the node could take. In some case the value yielded will not be a node found in the AST of the node but an instance of a special inference class such as :obj:`Uninferable`, or :class:`Instance`. Namely, the special singleton :obj:`Uninferable` is yielded when the inference reaches a point where it can't follow the code and is so unable to guess a value; and instances of the :class:`Instance` class are yielded when the current node is inferred to be an instance of some known class. Crash course into astroid's inference -------------------------------------- Let's see some examples on how the inference might work in ``astroid``. First we'll need to do a detour through some of the ``astroid``'s APIs. ``astroid`` offers a relatively similar API to the builtin ``ast`` module, that is, you can do ``astroid.parse(string)`` to get an AST out of the given string:: >>> tree = astroid.parse('a + b') >>> tree >>> >>> print(tree.repr_tree()) Module( name='', doc=None, file='', path=[''], package=False, pure_python=True, future_imports=set(), body=[Expr(value=BinOp( op='+', left=Name(name='a'), right=Name(name='b')))]) The :meth:`repr_tree` is super useful to inspect how a tree actually looks. Most of the time you can access the same fields as those represented in the output of :meth:`repr_tree` so you can do ``tree.body[0].value.left`` to get the left hand side operand of the addition operation. Another useful function that you can use is :func:`astroid.extract_node`, which given a string, tries to extract one or more nodes from the given string:: >>> node = astroid.extract_node(''' ... a = 1 ... b = 2 ... c ''') In that example, the node that is going to be returned is the last node from the tree, so it will be the ``Name(c)`` node. You can also use :func:`astroid.extract_node` to extract multiple nodes:: >>> nodes = astroid.extract_node(''' ... a = 1 #@ ... b = 2 #@ ... c ''') You can use ``#@`` comment to annotate the lines for which you want the corresponding nodes to be extracted. In that example, what we're going to extract is two ``Expr`` nodes, which is in astroid's parlance, two statements, but you can access their underlying ``Assign`` nodes using the ``.value`` attribute. Now let's see how can we use ``astroid`` to infer what's going on with your code. The main method that you can use is :meth:`infer`. It returns a generator with all the potential values that ``astroid`` can extract for a piece of code:: >>> name_node = astroid.extract_node(''' ... a = 1 ... b = 2 ... c = a + b ... c ''') >>> inferred = next(name_node.infer()) >>> inferred >>> inferred.value 3 From this example you can see that ``astroid`` is capable of *inferring* what ``c`` might hold, which is a constant value with the number 3.