class State(_MinimalState): (source)
The Project's state: container and accessors for analyses results.
Analyses
Node ancestors
Maps each node to their parents in the syntax-tree.
Accessors: get_parent(), get_parents(),
get_parent_instance(), get_enclosing_scope(),
get_all_enclosing_scopes().
Locals
Accessors: get_locals(), get_local(), get_attribute()
Imports resolution
Resolved imports are made available directly in the Imp instances.
Accessors: Imp.orgmodule, Imp.orgname, Imp.target().
Chains of definitions
Accessors: get_def(), goto_defs(), goto_def(), goto_definition(), goto_references().
Reachability
Accessor: is_reachable().
Instance variables
Accessors: get_ivars(), get_ivar()
Class MROs
Accessor: get_mro().
Function parameters for humans
Accessors: Arg.default, Arg.kind, Arg.to_parameter().
Symbolic evaluation
Accessor: literal_eval.
Basic type inference
Accessor: get_type.
| Method | expand |
Resove a name expression to it's qualified name. by using information only available in the current module. |
| Method | expand |
Resove a dottedname to it's qualified name. by using information only available in the current module. |
| Method | get |
Returns all scopes enclosing this definition. |
| Method | get |
Iterate over all modules in the project. This include dependency modules. |
| Method | get |
Returns all names bound when wildcard importing the given module. |
| Method | get |
Get attributes definitions matching the name in the scope node. It fisrt call get_local() (get_ivar() if include_ivars=True); if no locals matches the name or ignore_locals=True and the scope is a module, it calls ... |
| Method | get |
Def-Use chains accessor: returns the Def instance of this node. All ast nodes categorized as a use or a definition have a coresponding Def instance. Use this method to access it. |
| Method | get |
Finds the definitions having the given qualname. |
| Method | get |
Get the computed value for the __all__ variable of this module. |
| Method | get |
Get the first enclosing scope of this use or deinition. Returns None only of the definition is a Module. |
| Method | get |
Returns the filename of the given ast node. If the node does not exist in the system, it returns None. |
| Method | get |
Get the instance variable definitions of the given name in class node. Only assigments present in methods directly in the body of the class are considered here. If you want to lookup instance variables in super classes as well, pass``include_inherited=True``. |
| Method | get |
Get the mapping of instance variables of the given class. |
| Method | get |
Get the local definitions of the given name in scope node. |
| Method | get |
Get the mapping of locals of the given node. |
| Method | get |
Undocumented |
| Method | get |
Returns the module with the given name if it's in the system, else None. |
| Method | get |
Get an iterator on the elements of the MRO of class node. |
| Method | get |
Returns the direct parent of the given node in the syntax tree. |
| Method | get |
Returns the first parent of the node in the syntax tree matching the given type info. |
| Method | get |
Get the parent package of the given module. |
| Method | get |
Returns all syntax tree parents of the node in the syntax tree up to the root module. |
| Method | get |
Returns the qualified name of this definition. If the definition is an imported name, returns the qualified name of the the imported symbol. |
| Method | get |
If this node is a module, returns it's Mod instance, else find the parent Module and return it's Mod instance. |
| Method | get |
Should only be called for statements. |
| Method | get |
Get a sub-module of the given module. |
| Method | get |
Infer the type of the given node or definition. |
| Method | goto |
Use-Def chains accessor (wraps goto_defs) that returns only one Def, or raise StaticException. It returns the first reachable definition in the list. It does not ensure that the list is only composed by one element, unless ... |
| Method | goto |
Go to the genuine definition of this expression. This is not a simple use-def chains accessor, it's recursive. By default it follows imports but not aliases. |
| Method | goto |
Use-Def chains accessor: returns the definition points of the use node. |
| Method | goto |
Finds all Name and Attribute references pointing to the given definition. |
| Method | goto |
Simple, lazy identifier -> defs resolving. |
| Method | is |
Whether the node is reachable. |
| Method | literal |
Powerfull ast.literal_eval() function. Does not support dicts at the moment. |
| Instance Variable | msg |
Undocumented |
| Method | _get |
In the absence of definition of __all__, we use this function to compute names bound when wildcard importing the given module. |
| Method | _goto |
Find attribute references. |
| Method | _goto |
Finds all Name or Import references, it follows imports, but bot aliases. |
| Method | _raise |
Undocumented |
| Method | _softfilter |
Undocumented |
| Method | _softfilter |
Undocumented |
| Method | _softfilter |
Undocumented |
| Instance Variable | _ancestors |
Mapping of AST nodes to the list of their parents. |
| Instance Variable | _def |
Def-Use chains. |
| Instance Variable | _dunder |
Mapping from Mod instances explicit __all__ values or None. |
| Instance Variable | _ivars |
Mapping from class instances to instance variables definitions stored as mapping for fast name based access. |
| Instance Variable | _locals |
Mapping of locals. |
| Instance Variable | _modules |
Mapping from module names to Mod instances. |
| Instance Variable | _mros |
Mapping from class instances to their resolved MRO. A warning is logged when the MRO of a class could not be computed or is ambiguous. Qualname as strings replaces unresolved classes in the MRO. |
| Instance Variable | _unreachable |
Set of unreachable nodes. |
| Instance Variable | _use |
Use-Def chains. |
Resove a name expression to it's qualified name. by using information only available in the current module.
Only the first name in the expression is resolved, does not recurse in attributes definitions, simply append the rest of the names at the end.
>>> p = Project() >>> node = ast.parse('from twisted.web.template import Tag as T; T') >>> p.add_module(node, 'test') <Mod(name=test)> >>> p.analyze_project() >>> use = node.body[-1].value >>> p.state.expand_expr(use) 'twisted.web.template.Tag'
Returns None if the name is unbound or the expression is not composed by names.
Scope, name: str, is_annotation: bool = False) -> str | None:
(source)
¶
Resove a dottedname to it's qualified name. by using information only available in the current module.
Only the first name in the dottedname is resolved, does not recurse in attributes definitions, simply append the rest of the names at the end.
>>> p = Project() >>> m = p.add_module(ast.parse('from twisted.web.template import Tag as T'), 'test') >>> p.analyze_project() >>> p.state.expand_name(m, 'T.something') # expand 'T' in the context of m 'twisted.web.template.Tag.something'
Returns None is the name is unbound.
Returns all names bound when wildcard importing the given module.
| Raises | |
StaticException | If something went wrong. |
| Note | |
| If __all__ is defined, it simply returns the computed literal value. No checks is done to verify if names are actually defined. | |
ast.ClassDef | ast.Module | Mod | Cls, name: str, *, ignore_locals: bool = False, noraise: bool = False, filter_unreachable: bool = True, include_ivars: bool = False, include_inherited: bool = True) -> Sequence[ NameDef]:
(source)
¶
Get attributes definitions matching the name in the scope node.
It fisrt call get_local() (get_ivar() if include_ivars=True);
if no locals matches the name or ignore_locals=True and the scope is a module, it calls get_sub_module().
Note
It always filter out killed definitions.
>>> src = ''' ... class A: ... def f(self, x): ... self.x = x ... class B(A): ... ... class C(B): ... ... ''' >>> p = Project() >>> m = p.add_module(ast.parse(src), 't') >>> p.analyze_project() >>> C = m.node.body[-1] >>> p.state.get_attribute(C, 'f') [<Func(name=f)>]
| Parameters | |
node:ast.ClassDef | ast.Module | Mod | Cls | The AST or Def scope. |
name:str | The name of the attribute we're looking-up. |
ignorebool | Whether to ignore the locals, this will only lookup in sub-modules. |
noraise:bool | Don't raise exceptions, returns an empty list in these cases. |
filterbool | Whether to filter unreachable definitions, True by default. |
includebool | Whether to include instance context definitions, False by default. |
includebool | Whether to include inherited definitions, True by default. |
| Returns | |
Sequence[ | Undocumented |
| Raises | |
StaticTypeError | If the node is not a module or a class. |
StaticAttributeError | If the attribute is not found. |
StaticException | Other kind of exceptions can also be raised by callees. |
Def-Use chains accessor: returns the Def instance of this node.
All ast nodes categorized as a use or a definition have a coresponding Def instance.
Use this method to access it.
| Parameters | |
node:ast.AST | The AST node of a definition or use. |
noraise:bool | Don't raise exceptions if the node is not a definition or use in the system:
simply returns None in these cases. |
| Returns | |
Def | Mod | None | Undocumented |
| Raises | |
StaticValueError | If the node is not a use or definition. |
StaticStateIncomplete | If the node is not in the system. |
Finds the definitions having the given qualname.
>>> p = Project() >>> node = ast.parse('class Reactor:\n class System:\n target = "win32"') >>> p.add_module(node, 'test') <Mod(name=test)> >>> p.analyze_project() >>> p.state.get_defs_from_qualname('test.Reactor.System.target') [<Var(name=target)>]
Get the computed value for the __all__ variable of this module.
If __all__ variable is not defined or too complex returns None.
| Raises | |
StaticTypeError | If mod is actually not a module. |
StaticStateIncomplete | If no information is registered for the module mod. |
Get the first enclosing scope of this use or deinition. Returns None only of the definition is a Module.
Returns the filename of the given ast node. If the node does not exist in the system, it returns None.
Cls | ast.ClassDef, name: str, *, include_inherited: bool = False):
(source)
¶
Get the instance variable definitions of the given name in class node. Only assigments present in methods directly in the body of the class are considered here. If you want to lookup instance variables in super classes as well, pass``include_inherited=True``.
| Returns | |
| List of definitions matching the provided name. An empty list will be returned if the name is not defined. |
ast.ClassDef | Cls, *, include_inherited: bool = False) -> Mapping[ str, Sequence[ NameDef]]:
(source)
¶
Get the mapping of instance variables of the given class.
>>> p = Project() >>> m = p.add_module(ast.parse('class C:\n' ... ' def __init__(self, x):\n' ... ' self._x = x'), 'test') >>> p.analyze_project() >>> C, = p.state.get_local(m, 'C') >>> ivars = [f'{v.name()!r} {p.state.get_location(v)}' for v in chain(*p.state.get_ivars(C).values())] >>> print('\n'.join(ivars)) '_x' ast.Attribute at test:3:2
Mod | Def | ast.AST, name: str, *, include_inherited: bool = False) -> Sequence[ NameDef | None]:
(source)
¶
Mod | Def | ast.AST, *, include_inherited: bool = False) -> Mapping[ str, Sequence[ NameDef | None]]:
(source)
¶
Get the mapping of locals of the given node.
>>> src = ''' ... class A: ... def f(self, x): ... self.x = x ... class B(A): ... ... class C(B): ... ... ''' >>> p = Project() >>> m = p.add_module(ast.parse(src), 't') >>> p.analyze_project() >>> A = m.node.body[-3] >>> B = m.node.body[-2] >>> C = m.node.body[-1] >>> dict(p.state.get_locals(A)) {'f': [<Func(name=f)>]} >>> dict(p.state.get_locals(B)) {} >>> dict(p.state.get_locals(B, include_inherited=True)) {'f': [<Func(name=f)>]} >>> dict(p.state.get_locals(C, include_inherited=True)) {'f': [<Func(name=f)>]}
| Raises | |
StaticValueError | If the given node cannot have locals (it's not a scope definition). |
Cls | ast.ClassDef, *, include_unknown: Literal[ True], include_self: bool = True) -> Iterator[ Cls | str]:Cls | ast.ClassDef, *, include_unknown: Literal[ False] = False, include_self: bool = True) -> Iterator[ Cls]:Get an iterator on the elements of the MRO of class node.
>>> src = ''' ... from x import thing ... class A(thing, object):... ... class B(A): ... ... class C(B): ... ... ''' >>> p = Project() >>> m = p.add_module(ast.parse(src), 't') >>> p.analyze_project() >>> C = m.node.body[-1] >>> list(p.state.get_mro(C)) [<Cls(name=C)>, <Cls(name=B)>, <Cls(name=A)>] >>> list(p.state.get_mro(C, include_self=False)) [<Cls(name=B)>, <Cls(name=A)>] >>> list(p.state.get_mro(C, include_self=False, include_unknown=True)) [<Cls(name=B)>, <Cls(name=A)>, 'x.thing', 'object'] >>> list(p.state.get_mro(C, include_unknown=True)) [<Cls(name=C)>, <Cls(name=B)>, <Cls(name=A)>, 'x.thing', 'object']
Returns the direct parent of the given node in the syntax tree.
| Raises | |
StaticValueError | If node is a module, is has no parents. |
ast.AST | Def, cls: type[ T] | tuple[ type[ T], ...]) -> T:
(source)
¶
Returns the first parent of the node in the syntax tree matching the given type info.
| Raises | |
StaticValueError | If the the node has no parents of the requested type. |
Get the parent package of the given module.
Returns None if the given module is a root module or the parent package is not found in the system.
Returns all syntax tree parents of the node in the syntax tree up to the root module.
| Raises | |
StaticStateIncomplete | If no parents informations is available. |
Returns the qualified name of this definition. If the definition is an imported name, returns the qualified name of the the imported symbol.
A qualified named a name by wich a definition can be found. The same object could have several qualified named depending on where it's imported.
If this node is a module, returns it's Mod instance,
else find the parent Module and return it's Mod instance.
| Raises | |
StaticException | If something is wrong. |
Infer the type of the given node or definition.
While basic type inference is provided, libstatic does not carry the complexity to support full-featured type-checking.
It can infer the type of any literal expression, when a name is encountered all it's potential defintions are looked up and the inferred type is derived from a union of all the possible types. There is support for attribute annotations, functions, modules or attribute access, instance variables and methods, properties and other fundamentals.
- Notably missing features includes:
- Type aliases detection
- TypedDict and a lot more of the typing features
Limited support for some of these items might be added in the future.
Use-Def chains accessor (wraps goto_defs) that returns only one Def, or raise StaticException.
It returns the first reachable definition in the list. It does not ensure that the list is only
composed by one element, unless raise_on_ambiguity=True.
| Parameters | |
node:ast.AST | Undocumented |
noraise:bool | Don't raise exceptions, simply returns None in these cases. |
raisebool | Raise StaticAmbiguity when the use has several reachable definitions.
Cannot be used with noraise=True. |
| Returns | |
Def | None | Undocumented |
| Raises | |
StaticAmbiguity | If raise_on_ambiguity=True and the symbol definition is ambiguous. |
StaticException | All other exceptions raised by goto_defs. |
ast.AST, *, raise_on_ambiguity: bool = False, follow_aliases: bool = False, follow_imports: bool = True) -> Def:
(source)
¶
Go to the genuine definition of this expression. This is not a simple use-def chains accessor, it's recursive. By default it follows imports but not aliases.
>>> p = Project() >>> _ = p.add_module(ast.parse('def deprecated(f):...'), 'deprecated') >>> src1 = p.add_module(ast.parse('''\ ... from deprecated import deprecated ... @deprecated ... def f():...'''), 'src1') >>> src2 = p.add_module(ast.parse('''\ ... import src1 ... @src1.deprecated ... class C:...'''), 'src2') >>> p.analyze_project() >>> func_dec = src1.node.body[-1].decorator_list[0] >>> p.state.goto_definition(func_dec) <Func(name=deprecated)> >>> cls_dec = src1.node.body[-1].decorator_list[0] >>> p.state.goto_definition(cls_dec) <Func(name=deprecated)>
Use-Def chains accessor: returns the definition points of the use node.
Note
- It does not recurse on follow-up definitions in case of aliases.
- It does not filter unreachable definitions
- Builtins are supported only if the builtins module has been added to the project.
| Parameters | |
node:ast.AST | The AST node of a use. |
noraise:bool | Don't raise exception if the node is unbound or not a use in the system: simply returns an empty list in these cases. By default, the returned list always have at least one element, otherwise an exception is raised. |
| Returns | |
Sequence[ | A collection of Def instances |
| Raises | |
StaticImportError | If the node is an unbound import. |
StaticNameError | If the node is unbound. |
StaticValueError | If the node is not a use. |
StaticStateIncomplete | If the node is not in the system. |
NameDef | ast.AST, filter_unreachable: bool = False) -> Iterator[ Def]:
(source)
¶
Finds all Name and Attribute references pointing to the given definition.
>>> p = Project() >>> dep = p.add_module(ast.parse('def deprecated(f):...'), 'deprecated') >>> _ = p.add_module(ast.parse('''\ ... from deprecated import deprecated ... @deprecated ... def f():...'''), 'src1') >>> _ = p.add_module(ast.parse('''\ ... import src1 ... @src1.deprecated ... class C:...'''), 'src2') >>> p.analyze_project() >>> dep_func = dep.node.body[-1] >>> list(p.state.goto_references(dep_func)) [<Def(node=<Name>)>, <Def(node=<Attribute>)>]
Scope, name: str, *, is_annotation: bool = False) -> Sequence[ NameDef]:
(source)
¶
Simple, lazy identifier -> defs resolving.
"Lookup" a name in the context of the provided scope, it does not use the chains Note that nonlocal and global keywords are ignored by this function.
>>> p = Project() >>> m = p.add_module(ast.parse('from twisted.web.template import Tag as T;'), 'test') >>> p.analyze_project() >>> p.state.goto_symbol_def(m, 'T') [<Imp(name=T)>]
| Raises | |
StaticNameError | For unbound names. |
ast.AST, *, known_values: Mapping[ str, Any] | None = None, raise_on_ambiguity: bool = False, follow_imports: bool = False) -> LiteralValue:
(source)
¶
Powerfull ast.literal_eval() function. Does not support dicts at the moment.
>>> p = Project() >>> node = ast.parse('from x import x;e="bar";x+["1", 2+3, e]') >>> node2 = ast.parse('from test import e;"best "+e') >>> p.add_module(node, 'test') <Mod(name=test)> >>> p.add_module(node2, 'test2') <Mod(name=test2)> >>> p.analyze_project() >>> expr = node.body[-1].value >>> p.state.literal_eval(expr, known_values={'x':['foo']}) ['foo', '1', 5, 'bar'] >>> expr2 = node2.body[-1].value >>> p.state.literal_eval(expr2) Traceback (most recent call last): libstatic.exceptions.StaticUnknownValue: test2:1:17: Unkown value: test.e >>> p.state.literal_eval(expr2, follow_imports=True) 'best bar'
In the absence of definition of __all__, we use this function to compute names bound when wildcard importing the given module.
NameDef, seen: set[ Def], filter_unreachable: bool) -> Iterator[ Def]:
(source)
¶
Find attribute references.
- Pitfalls:
- inherited attributes access in subclasses are not considered
NameDef, seen: set[ Def], filter_unreachable: bool) -> Iterator[ Def]:
(source)
¶
Finds all Name or Import references, it follows imports, but bot aliases.
Sequence[ Def], *, unreachable: bool, killed: bool) -> Sequence[ Def]:
(source)
¶
Undocumented
Mapping from class instances to instance variables definitions stored as mapping for fast name based access.