Awesome
astypes
Python library to statically detect types for AST nodes.
A good use case is a linter that needs to run some rules only for particular types. For instance, to check arguments of something.format(a=b)
only if something
has type str
.
python3 -m pip install astypes
Usage
Astypes uses astroid to infer definitions of nodes. So, if your code works with ast nodes, you'll need to convert them into astroid first:
import astroid
import astypes
module = astroid.parse(source_code)
node = astypes.find_node(module, ast_node)
And when you have an astroid node, you can get its type:
node_type = astype.get_node(node)
print(node_type.annotation)
Example:
import astroid
import astypes
node = astroid.extract_node('1 + 2.3')
t = astypes.get_type(node)
print(t.annotation) # 'float'
For a real-world usage example, check out infer-types. It is a CLI tool that automatically adds type annotations into Python code using astypes.
How it works
You can find most of the logic in astypes/_handlers.py. In short:
- The type of some nodes is easy to infer. For example,
13
is alwaysint
. - Some nodes are also can be inferred but only if we make some assumptions. Assumptions that we make are the ones that are true in 99% of cases. For example, we assume that
list(x)
returns typelist
. It might be not true if you shadowlist
with something else. - If the type cannot be assumed just by looking at the node, we try to use astroid to infer the type.
- If the returned value is a function call, we use astroid to find the definition of the function. The annotated return annotation of the function is what we need.
- If the resolved function doesn't have annotation, we use typeshed_client to get its annotation from typeshed. For example, for all built-in functions.