_autoimp module
- exception pyflyby._autoimp.LoadSymbolError
- class pyflyby._autoimp.ScopeStack(arg, _class_delayed=None)
A stack of namespace scopes, as a tuple of
dicts.Each entry is a
dict.Ordered from most-global to most-local. Builtins are always included. Duplicates are removed.
- _abc_impl = <_abc._abc_data object>
- _cached_has_star_import = False
- _with_new_scope(*, include_class_scopes, new_class_scope, unhide_classdef)
Return a new
ScopeStackwith an additional empty scope.- Parameters:
include_class_scopes (
bool) – Whether to include previous scopes that are meant for ClassDefs.new_class_scope (
bool) – Whether the new scope is for a ClassDef.unhide_classdef (
bool) – Unhide class definitiion scope (when we enter a method)
- Return type:
ScopeStack
- clone_top()
Return a new
ScopeStackreferencing the same namespaces asself, but cloning the topmost namespace (and aliasing the others).
- has_star_import()
Return whether there are any star-imports in this ScopeStack. Only relevant in AST-based static analysis mode.
- Return type:
bool
- merged_to_two()
Return a 2-tuple of dicts.
These can be used for functions that take a
globalsandlocalsargument, such aseval.If there is only one entry, then return it twice.
If there are more than two entries, then create a new dict that merges the more-global ones. The most-local stack will alias the dict from the existing ScopeStack.
- Return type:
tupleof (dict,dict)
- class pyflyby._autoimp._ClassScope
- pyflyby._autoimp._IMPORT_FAILED: Set[Any] = {}
Set of imports we’ve already attempted and failed.
- class pyflyby._autoimp._MissingImportFinder(scopestack, *, find_unused_imports, parse_docstrings)
A helper class to be used only by _find_missing_imports_in_ast.
This class visits every AST node and collects symbols that require importing. A symbol requires importing if it is not already imported or otherwise defined/assigned in this scope.
For attributes like “foo.bar.baz”, we need to be more sophisticated:
Suppose the user imports “foo.bar” and then accesses “foo.bar.baz.quux”. Baz may be already available just by importing foo.bar, or it may require further import. We decide as follows. If foo.bar is not a module, then we assume whatever’s under it can’t be imported. If foo.bar is a module but does not have a ‘baz’ attribute, then it does require import.
- _NewScopeCtx(include_class_scopes=False, new_class_scope=False, unhide_classdef=False, check_unused_imports=True)
Context manager that temporarily pushes a new empty namespace onto the stack of namespaces.
- _UpScopeCtx()
Context manager that temporarily moves up one in the scope stack
- _check_load(fullname, scopestack, lineno)
Check if the symbol needs import. (As a side effect, if the object is a _UseChecker, this will mark it as used.
TODO: It would be better to refactor symbol_needs_import so that it just returns the object it found, and we mark it as used here.)
-
_deferred_load_checks:
list[tuple[str,ScopeStack,Optional[int]]]
- _finish_deferred_load_checks()
- _get_scope_info()
-
_lineno:
Optional[int]
- _remove_from_missing_imports(fullname)
- _scan_node(node)
- _scan_unused_imports()
- _visit_Load(fullname)
- _visit_Load_defered(fullname)
- _visit_Load_defered_global(fullname)
Some things will be resolved in global scope later.
- _visit_Load_immediate(fullname)
- _visit_Store(fullname, value=None)
Visit a Store action, check for unused import and add current value to the last scope.
- _visit_StoreImport(node, modulename)
- _visit__all__(node)
- _visit_fullname(fullname, ctx)
- _visit_typecomment(typecomment)
Warning, when a type comment the node is a string, not an ast node. We also get two types of type comments:
The signature one just after a function definition
- def foo(a):
# type: int -> None pass
And the variable annotation ones:
- def foo(a #type: int
): pass
ast parse “func_type” mode only support the first one.
- Return type:
None
- find_missing_imports(node)
- generic_visit(node)
Generic visitor that visits all of the node’s field values, in the order declared by
node._fields.Called if no explicit visitor function exists for a node.
-
missing_imports:
List[Tuple[Optional[int],DottedIdentifier]]
-
parse_docstrings:
bool
- scan_for_import_issues(codeblock)
-
scopestack:
ScopeStack
-
unused_imports:
Optional[List[Tuple[int,str]]]
- visit(node)
Visit a node.
- visit_Assign(node)
- visit_AsyncFunctionDef(node)
- visit_Attribute(node)
- visit_Call(node)
- visit_ClassDef(node)
- visit_Constant(node)
- visit_Delete(node)
- visit_Dict(node)
- visit_DictComp(node)
- visit_ExceptHandler(node)
- Return type:
None
- visit_Expr(node)
- visit_FunctionDef(node)
- visit_GeneratorExp(node)
- visit_ImportFrom(node)
- visit_Lambda(node)
- visit_ListComp(node)
- visit_Match(node)
- visit_MatchAs(node)
- visit_MatchMapping(node)
- visit_Module(node)
- visit_Name(node)
- visit_Pass(node)
- visit_SetComp(node)
- visit_alias(node, modulename=None)
- visit_arg(node)
- visit_arguments(node)
- Return type:
None
- visit_comprehension(node)
- visit_match_case(node)
- class pyflyby._autoimp._UseChecker(name, source, lineno)
An object that can check whether it was used.
-
lineno:
int
-
name:
str
-
source:
str
-
used:
bool= False
-
lineno:
- pyflyby._autoimp._find_earliest_backjump_label(bytecode)
Find the earliest target of a backward jump.
These normally represent loops.
For example, given the source code:
>>> def f(): ... if foo1(): ... foo2() ... else: ... foo3() ... foo4() ... while foo5(): # L7 ... foo6()
The earliest target of a backward jump would be the ‘while’ loop at L7, at bytecode offset 38:
>>> _find_earliest_backjump_label(f.__code__.co_code) 38
Note that in this example there are earlier targets of jumps at bytecode offsets 20 and 28, but those are targets of _forward_ jumps, and the clients of this function care about the earliest _backward_ jump.
If there are no backward jumps, return an offset that points after the end of the bytecode.
- Parameters:
bytecode (
bytes) – Compiled bytecode, e.g.function.__code__.co_code.- Return type:
int- Returns:
The earliest target of a backward jump, as an offset into the bytecode.
- pyflyby._autoimp._find_loads_without_stores_in_code(co, loads_without_stores)
Find global LOADs without corresponding STOREs, by disassembling code. Recursive helper for _find_missing_imports_in_code.
- Parameters:
co (
types.CodeType) – Code object, e.g.function.__code__loads_without_stores (
set) – Mutable set to which we add loads without stores.
- Returns:
None
- pyflyby._autoimp._find_missing_imports_in_ast(node, namespaces)
Find missing imports in an AST node. Helper function to find_missing_imports.
>>> node = ast.parse("import numpy; numpy.arange(x) + arange(x)") >>> _find_missing_imports_in_ast(node, [{}]) [DottedIdentifier('arange'), DottedIdentifier('x')]
- Return type:
listofDottedIdentifier
- pyflyby._autoimp._find_missing_imports_in_code(co, namespaces)
Find missing imports in a code object. Helper function to find_missing_imports.
>>> f = lambda: foo.bar(x) + baz(y) >>> [str(m) for m in _find_missing_imports_in_code(f.__code__, [{}])] ['baz', 'foo.bar', 'x', 'y']
>>> f = lambda x: (lambda: x+y) >>> _find_missing_imports_in_code(f.__code__, [{}]) [DottedIdentifier('y')]
- Return type:
listofstr
- pyflyby._autoimp._try_import(imp, namespace)
Try to execute an import. Import the result into the namespace
namespace.Print to stdout what we’re about to do.
Only import into
namespaceif we won’t clobber an existing definition.- Parameters:
imp (
Importorstr) – The import to execute, e.g. “from numpy import arange”namespace (
dict) – Namespace to import into.
- Returns:
Trueon success,Falseon failure
- pyflyby._autoimp.auto_import_symbol(fullname, namespaces, db=None, autoimported=None, post_import_hook=None)
Try to auto-import a single name.
- Parameters:
fullname (
str) – Fully-qualified module name, e.g. “sqlalchemy.orm”.namespaces (
listofdict, e.g. [globals()].) – Namespaces to check. Namespace[-1] is the namespace to import into.db (ImportDB) – Import database to use.
autoimported – If not
None, then a dictionary of identifiers already attempted.auto_importwill not attempt to auto-import symbols already in this dictionary, and will add attempted symbols to this dictionary, with valueTrueif the autoimport succeeded, orFalseif the autoimport did not succeed.post_import_hook (
callable) – A callable that is invoked if an import was successfully made. It is invoked with the Import object representing the successful import
- Return type:
bool- Returns:
Trueif the symbol was already in the namespace, or the auto-import succeeded;Falseif the auto-import failed.
- pyflyby._autoimp.clear_failed_imports_cache()
Clear the cache of previously failed imports.
- pyflyby._autoimp.get_known_import(fullname, db=None)
Get the deepest known import.
For example, suppose:
The user accessed “foo.bar.baz”,
We know imports for “foo”, “foo.bar”, and “foo.bar.quux”.
Then we return “import foo.bar”.
- Parameters:
fullname (DottedIdentifier) – Fully-qualified name, such as “scipy.interpolate”
- pyflyby._autoimp.load_symbol(fullname, namespaces, autoimport=False, db=None, autoimported=None)
Load the symbol
fullname.>>> import os >>> load_symbol("os.path.join.__name__", {"os": os}) 'join'
>>> load_symbol("os.path.join.asdf", {"os": os}) Traceback (most recent call last): ... pyflyby._autoimp.LoadSymbolError: os.path.join.asdf: AttributeError: 'function' object has no attribute 'asdf'
>>> load_symbol("os.path.join", {}) Traceback (most recent call last): ... pyflyby._autoimp.LoadSymbolError: os.path.join: NameError: os
- Parameters:
fullname (
str) – Fully-qualified symbol name, e.g. “os.path.join”.namespaces (
dictorlistofdict) – Namespaces to check.autoimport – If
False(default), the symbol must already be imported. IfTrue, then auto-import the symbol first.db (ImportDB) – Import database to use when
autoimport=True.autoimported – If not
None, then a dictionary of identifiers already attempted.auto_importwill not attempt to auto-import symbols already in this dictionary, and will add attempted symbols to this dictionary, with valueTrueif the autoimport succeeded, orFalseif the autoimport did not succeed.
- Returns:
Object.
- Raises:
LoadSymbolError – Object was not found or there was another exception.
- pyflyby._autoimp.scan_for_import_issues(codeblock, find_unused_imports=True, parse_docstrings=False)
Find missing and unused imports, by lineno.
>>> arg = "import numpy, aa.bb as cc\nnumpy.arange(x)\narange(x)" >>> missing, unused = scan_for_import_issues(arg) >>> missing [(2, DottedIdentifier('x')), (3, DottedIdentifier('arange')), (3, DottedIdentifier('x'))] >>> unused [(1, Import('from aa import bb as cc'))]
- Parameters:
parse_docstrings (
bool) –Whether to parse docstrings. Compare the following examples. When parse_docstrings=True, ‘bar’ is not considered unused because there is a string that references it in braces:
>>> scan_for_import_issues("import foo as bar, baz\n'{bar}'\n") ([], [(1, Import('import baz')), (1, Import('import foo as bar'))]) >>> scan_for_import_issues("import foo as bar, baz\n'{bar}'\n", parse_docstrings=True) ([], [(1, Import('import baz'))])
- pyflyby._autoimp.symbol_needs_import(fullname, namespaces)
Return whether
fullnameis a symbol that needs to be imported, given the current namespace scopes.A symbol needs importing if it is not previously imported or otherwise assigned.
namespacesnormally includes builtins and globals as well as symbols imported/assigned locally within the scope.If the user requested “foo.bar.baz”, and we see that “foo.bar” exists and is not a module, we assume nothing under foo.bar needs import. This is intentional because (1) the import would not match what is already in the namespace, and (2) we don’t want to do call getattr(foo.bar, “baz”), since that could invoke code that is slow or has side effects.
- Parameters:
fullname (
DottedIdentifier) – Fully-qualified symbol name, e.g. “os.path.join”.namespaces (
listofdict) – Stack of namespaces to search for existing items.
- Return type:
bool- Returns:
Trueiffullnameneeds import, elseFalse
- pyflyby._autoimp.take_arg(op)