_imports2s module
- exception pyflyby._imports2s.ImportAlreadyExistsError
- pyflyby._imports2s.ImportPathForRelativeImportsCtx(codeblock)
Context manager that temporarily modifies
sys.pathso that relative imports for the givencodeblockwork as expected.- Return type:
ContextManager[Any,bool|None]
- exception pyflyby._imports2s.LineNumberAmbiguousError
- exception pyflyby._imports2s.LineNumberNotFoundError
- exception pyflyby._imports2s.NoImportBlockError
- class pyflyby._imports2s.SourceToSourceFileImportsTransformation(arg: Any)
- _apply_local_import_removals()
Apply the local-import removals recorded by
remove_import.The removals are grouped by (block, statement start line) so that all aliases removed from one statement are handled in a single rewrite, and statements are processed bottom-up within each block so that edits never shift the line numbers of statements not yet processed.
- Return type:
None
- _create_import_block_from_group(group, lines, start_line, end_line)
Create an import block from a group of import statements.
Extracts the import lines from source text, creates a PythonBlock and transformation, and adds it to import_blocks (wrapped with line metadata).
- Parameters:
group (
list[Union[Import,ImportFrom]]) – Consecutive import AST nodes to extract.lines (
list[str]) – All source lines of the file (1-indexed vialines[lineno - 1]).start_line (
int) – First line number of the group (1-indexed).end_line (
int) – Last line number of the group, accounting for multiline imports.
- Return type:
None
- _extract_imports_from_statement(stmt)
Recursively extract imports from a statement’s body (e.g., FunctionDef, ClassDef).
- Return type:
None
- _extract_local_import_blocks()
Recursively extract import blocks from function and class bodies. This allows us to find and remove unused imports within functions/classes.
- Return type:
None
- _line_contains_import(line, imp)
Check if a line contains the given import statement.
Parse the line as an import statement and compare Import objects, rather than using string matching which is fragile with spacing.
- Return type:
bool
- _original_block_startpos: dict[int, int]
- _pending_local_removals: list[tuple[Import, int]]
- _remove_local_imports_from_output(output)
Post-process the output to remove local imports that have been deleted.
This is necessary because local imports are embedded in function bodies, which are stored in self.blocks as plain text. When we remove imports from local import blocks, we need to also remove those lines from the output.
- Return type:
- _rewrite_local_import_statement(lines, rel, imps, lineno)
Rewrite the import statement starting at
lines[rel]with the imports inimpsremoved. Co-located code – other aliases in the same statement, semicolon-separated statements on the same line, parenthesized continuation lines – is preserved; the physical lines are deleted only when nothing else remains on them.- Parameters:
lines (
List[str]) – Source lines of the block, modified in place.rel (
int) – Index intolinesof the first line of the import statement.imps (
List[Import]) – The Import s to remove from the statement.lineno (
int) – Absolute line number in the file (for logging).
- Return type:
None
- _split_semicolon_chained_imports(output)
Split semicolon-chained import statements into separate lines.
For local import blocks that have semicolon_suffixes (code after semicolons), replace those lines with the import on one line and the remaining code on the next.
- Return type:
- add_import(imp, lineno=inf)
Add the specified import. Picks an existing global import block to add to, or if none found, creates a new one near the beginning of the module.
- Parameters:
lineno (
Any) – Line before which to add the import.Infmeans no constraint.- Return type:
None
- blocks: list[SourceToSourceImportBlockTransformation | SourceToSourceTransformation]
- find_import_block_by_lineno(lineno)
Find the import block containing the given line number.
Handles both top-level and local (function/class) import blocks. For local imports wrapped in _LocalImportBlockWrapper, checks the original line range. For regular imports, checks the line number range.
- Return type:
Union[SourceToSourceImportBlockTransformation,_LocalImportBlockWrapper] SourceToSourceImportBlockTransformation or _LocalImportBlockWrapper
- import_blocks: list[SourceToSourceImportBlockTransformation | _LocalImportBlockWrapper]
- insert_new_blocks_after_comments(blocks)
- Return type:
None
- insert_new_import_block()
Adds a new empty imports block. It is added before the first non-comment statement. Intended to be used when the input contains no import blocks (before uses).
- Return type:
- insert_new_import_block_after_future_imports()
- Return type:
- preprocess()
- Return type:
None
- remove_import(imp, lineno)
Remove the given import.
- Return type:
Import
- select_import_block_by_closest_prefix_match(imp, max_lineno)
Heuristically pick an import block that
imp“fits” best into. The selection is based on the block that contains the import with the longest common prefix.- Parameters:
max_lineno (
Union[int,float]) – Only return import blocks earlier thanmax_lineno.- Return type:
SourceToSourceImportBlockTransformationSourceToSourceImportBlockTransformation
- tidy_local_imports: bool = False
- class pyflyby._imports2s.SourceToSourceImportBlockTransformation(arg: Any)
-
- preprocess()
- Return type:
None
- pretty_print(params=None)
- Return type:
str
- class pyflyby._imports2s.SourceToSourceTransformation(arg: Any)
- _output: PythonBlock
- preprocess()
- Return type:
None
- class pyflyby._imports2s.SourceToSourceTransformationBase(arg: Any)
- classmethod _from_source_code(codeblock)
- Return type:
- input: PythonBlock
- output(params=None)
Pretty-print and return as a PythonBlock.
- Return type:
PythonBlockPythonBlock
- preprocess()
- Return type:
None
- class pyflyby._imports2s._LocalImportBlockWrapper(transform, start_lineno, end_lineno=None, semicolon_suffixes=None)
Wrapper for import blocks found within function/class bodies. Preserves the original line number range since the block’s internal line numbers may not match the file’s line numbers.
This will be useful for tidy imports which only know how to handle top level import.
- _id: str
- _original_imports: set[Import]
- _semicolon_suffixes: dict[int, str]
- end_lineno: int
- get_removed_imports()
Return the set of imports that have been removed from this block.
- Return type:
set[Import]
- start_lineno: int
- transform: SourceToSourceImportBlockTransformation
- class pyflyby._imports2s._NoImportBlockTransformer(block, transformations, transform_strings)
AST-aware textual rewriter for a single block of (non-top-level-import) code. See _transform_noimport_block for the behavior contract.
All state is set up in __init__; call run once to produce the rewritten PythonBlock.
- _abspos(lineno, col_offset)
Return the absolute byte offset of a (1-based
lineno,col_offset) AST position.- Return type:
int
- _add_name_edit(node, end_node, v)
Queue a replacement of the span from
node’s start throughend_node’s end with the literalv.- Return type:
None
- _add_regex_edit(node)
Queue a _regex_replace rewrite over
node’s own source span.- Return type:
None
- _block: PythonBlock
- _data: bytes
- _edits: list[tuple[int, int, bytes]]
- _handle_attribute_chain(node)
Rewrite a head-anchored dotted-name reference.
nodeis the outermost ast.Attribute of a chain; if the chain’s base is not a bare name, recurse into it instead.- Return type:
None
- _key_specs: list[tuple[tuple[str, ...], str]]
- _line_starts: list[int]
- _match_key(components)
Return the (components, replacement) of the longest transformation key that is a component-wise prefix of
components, or None if none matches.- Return type:
Optional[tuple[tuple[str,...],str]]
- _node_end(node)
Return the absolute byte offset of
node’s end position.- Return type:
int
- _node_start(node)
Return the absolute byte offset of
node’s start position.- Return type:
int
- _regex_replace(text)
Apply each transformation to
textas a word-boundary regex substitution. Used for spans that contain only dotted names (local imports) or that we deliberately rewrite verbatim (strings).- Return type:
str
- _transform_strings: bool
- _visit(node)
Recursively walk
node, queuing edits for matching name references, attribute chains, local imports, and (whentransform_strings) string literals.- Return type:
None
- run()
Walk the AST collecting edits, then apply them and return the rewritten block. Returns the (re-wrapped) input unchanged if no references matched.
- Return type:
PythonBlock
- pyflyby._imports2s._group_consecutive_imports(body)
Group consecutive import statements from an AST body.
- Parameters:
body (
list[stmt]) – List of AST nodes from a function/class body- Returns:
List of groups, where each group is a list of consecutive import statements
- Return type:
list[list[Union[Import,ImportFrom]]]
- pyflyby._imports2s._is_future_only_import_block(block)
- Return type:
bool
- pyflyby._imports2s._maybe_insert_pass(lines, idx, indent, lineno)
Insert a
passstatement at idx when removing a line would leave a block-opener (a line ending with:) without a body.After a line has been deleted at position idx, this function walks backwards to find the nearest non-empty preceding line. If that line ends with
:(a compound-statement header such asdef,class,if, etc.) and the next non-empty line after idx is at an equal or lower indentation level, the block body is gone and apassstatement is inserted at idx using indent spaces.- Parameters:
lines (
list[str]) – Source lines of the block, already modified (the import line has been deleted before this call).idx (
int) – Index into lines where the deleted line used to be.indent (
int) – Column offset (number of leading spaces) of the deleted line, used to indent the insertedpass.lineno (
int) – Absolute line number in the file (used only for logging).
- Return type:
None
- pyflyby._imports2s._transform_noimport_block(block, transformations, transform_strings)
Apply
transformationsto a block of (non-top-level-import) code.Unlike top-level import blocks – which are parsed and rewritten exactly – the rest of the code body can only be transformed heuristically. We do so in an AST-aware way:
References to dotted names are matched head-anchored and component-wise, so e.g.
foo.baris rewritten infoo.barandfoo.bar.bazbut not inx.foo.bar(wherefoo.baris an attribute of some other objectx).String literals are left alone by default, so the contents of e.g.
"foo.bar"are not altered. Passtransform_strings=Trueto additionally rewrite inside string literals (including docstrings and f-string text).Comments are never modified.
Local (e.g. function-body)
importstatements are rewritten with the same crude textual replacement used for top-level imports; this is safe because import statements contain only dotted names.
Note: on Python < 3.12 the positions of an f-string’s internal nodes are unreliable (PEP 701), so f-strings are treated opaquely there – their expression parts are not rewritten, and their text is only rewritten (as a whole) when
transform_stringsis true. On Python >= 3.12, f-string expression parts are rewritten like any other code.See https://github.com/deshaw/pyflyby/issues/175.
- Return type:
PythonBlockPythonBlock
- pyflyby._imports2s.fix_unused_and_missing_imports(codeblock, add_missing=True, remove_unused='AUTOMATIC', add_mandatory=True, db=None, params=None, tidy_local_imports=False)
Check for unused and missing imports, and fix them automatically.
Also formats imports.
By default only top-level imports are tidied. Set
tidy_local_imports=Trueto also remove unused imports inside function and class bodies.Individual imports can be excluded from removal by adding
# tidy-imports: ignore-importas a trailing comment. This is whitespace sentitive between and must be a single space after the #, and after the :In the example below,
m1andm3are unused, so are automatically removed.npwas undefined, so animport numpy as npwas automatically added.>>> codeblock = PythonBlock( ... 'from foo import m1, m2, m3, m4\n' ... 'm2, m4, np.foo', filename="/tmp/foo.py")
>>> print(fix_unused_and_missing_imports(codeblock, add_mandatory=False)) [PYFLYBY] /tmp/foo.py: removed unused 'from foo import m1' [PYFLYBY] /tmp/foo.py: removed unused 'from foo import m3' [PYFLYBY] /tmp/foo.py: added 'import numpy as np' import numpy as np from foo import m2, m4 m2, m4, np.foo
- Parameters:
tidy_local_imports (
bool) – IfTrue, also tidy imports within function and class bodies. Defaults toFalse.- Return type:
PythonBlockPythonBlock