Core
agenda ¶
Agendas indicate the work to be done to symbols.
SourcedUse
dataclass
¶
Represents a usage of a name which is imported, occurring in a definition target
(which is an AST node in src, the file the definition is being moved from).
DepartingImport
dataclass
¶
ArrivingImport
dataclass
¶
Departure
dataclass
¶
Bases: NamedPatch
A definition or importation leaving.
Arrival
dataclass
¶
Bases: NamedPatch
A definition or importation arriving.
Documented
dataclass
¶
Bases: NamedPatch
A documented definition or importation.
OrderOfBusiness
dataclass
¶
OrderOfBusiness(cop: list[SourcedAgendum] = list(), lop: list[Agendum] = list(), doc: list[Agendum] = list())
What to cop vs. what to lop (move/copy vs. delete), or, as a mutually exclusive option, what to doc (document i.e. enumerate).
Agenda ¶
Source code in src/mvdef/core/agenda.py
no_clash ¶
No repetition, and * must be used on its own.
Source code in src/mvdef/core/agenda.py
intake ¶
Prepare to cop/lop, or doc (ensure no double bookings!)
Note: prevents mixed usage of doc() with either cop() or lop().
doc ¶
manifest ¶
Manifest of definitions from applying the targeted agenda to the target file.
Source code in src/mvdef/core/agenda.py
unidiff ¶
Unified diff from applying the targeted agenda to the target file. If the
file does not exist yet, pass in an empty string for old to avoid reading it.
Source code in src/mvdef/core/agenda.py
def_rng ¶
Get the line range of a definition with the target name.
Source code in src/mvdef/core/agenda.py
def_depth ¶
Get the tree depth of a definition with the target name.
unique_name_list ¶
Preserve unique names for each node type, in order of first appearance.
Source code in src/mvdef/core/agenda.py
sew_in_imports ¶
Leave sep of 2 lines if definitions go first, 1 line for anything else.
Source code in src/mvdef/core/agenda.py
calculate_import_spacing ¶
A quick estimate of how big a gap to leave after the supplied import(s),
returning the gap (0, 1, or 2) and the first import line number [0 if none].
Also, if the gap is 1 (indicating import-first order), check if the first is the
special __future__.annotations import (which must be left the first import).
To do this thoroughly would presumably require interfacing with isort.
Source code in src/mvdef/core/agenda.py
pre_simulate ¶
resimulate ¶
resimulate(input_text: str, *, imports_in: list[ArrivingImport], imports_out: list[DepartingImport], recheck: Checker | None = None) -> str
Second pass if necessary to remove import statements that would not be used
after moving the mv definition(s) out of the file.
Source code in src/mvdef/core/agenda.py
recheck ¶
First pass, with no change to import statements.
Source code in src/mvdef/core/agenda.py
simulate ¶
This method has no side effects on the state of self.
Source code in src/mvdef/core/agenda.py
patch_dependents ¶
Patch any uses which depend on getting a new import. Turn the list of AST-sourced name binding uses into a list of patches to apply (prepend). Ensure not to patch any that are already present in the dst file.
Source code in src/mvdef/core/agenda.py
map_import_usage ¶
AST ancestor subtrees of the node where each source import was marked as being 'used' (NB only one value: overwritten during walk, so it appears that we don't have access to all uses, only its last use).
However! Since we access the scopes during the walk, if we know they have at
least one use (src_imp_name_trees) we can look up all uses of the same name.
This gets stored as all_src_imp_name_trees, and it tells us "what's above each
usage node in the tree walked by Checker. We can match self.ref.target_defs
to this 'ancestry' tree, to get all definition-scoped import uses (and which
definitions they come from).
Having obtained those uses, we need to compare them to the imports themselves.
This takes us from all_src_imp_name_trees to sourced_uses.
There are 2 possible ways we can cross-reference the uses to the imports
- lopped::Patch.rng <-> used_on_line_ranges::Patch.rng
- imports::Importation.source <-> ref.import_uses::(scope, node)
(1) Use line ranges [rejected: match AST nodes and unparse instead]
>>> used_on_line_ranges = {
name: [
Patch((name_node.lineno, name_node.end_lineno))
for scope, name_node in use_list
]
for name, use_list in self.ref.import_uses.items()
}
(2) Match use name ancestor to a moved definition (AST node). If an import use
occurs within a moved definition, colocate its import alongside, into dst.
- NB: we store in used the node which uses the name.
- NB: we store in imports the pyflakes.checker.Importation "binding".
This function is hardcoded to use self.ref, as we would never consider using
self.dst_ref (which by definition does not contain the target_defs to move)
or the recheck of src (which may have caused removal of used imports).
Source code in src/mvdef/core/agenda.py
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | |
check ¶
Override the pyflakes Checker to extract info for our purposes.
Checker ¶
Bases: FailableMixIn, Checker
A subclass of the pyflakes Checker (overriding specific parts).
Source code in src/mvdef/core/check.py
handleNode ¶
CLASSDEF ¶
FUNCTIONDEF ¶
unused_imports
cached
¶
Import strings (in m.message_args[0] for each UnusedImport message m):
- "import a( as o)" -> "a( as o)"
- "from a import b( as o)" -> "a.b( as o)"
- "from a.b import c( as o)" -> "a.b.c( as o)"
- "from . import a( as o)" -> ".a( as o)"
- "from .a import b( as o)" -> ".a.b( as o)"
- "from .a.b import c( as o)" -> ".a.b.c( as o)"
Source code in src/mvdef/core/check.py
diff ¶
Diff two files (in a way that can be applied as a patch).
Differ
dataclass
¶
Differ(src: Path, *, mv: list[str], source_ref: Checker, dst: Path | None = None, dest_ref: Checker | None = None, escalate: bool = False, verbose: bool = False)
Dataclass storing the source (and potentially destination) of symbols.
Importantly, the symbol names are stored as a list mv.
populate_agenda ¶
Call Agenda.remove or Agenda.bring with the mv list.
unidiff ¶
The unified diff of the agenda (if agenda is empty, populates it first).
execute ¶
See autoflake8, which uses rename (replace) with NamedTemporaryFile: https://github.com/fsouza/autoflake8/blob/main/autoflake8/fix.py#L668
Also autoflake, which doesn't: https://github.com/PyCQA/autoflake/blob/main/autoflake.py#L970
Source code in src/mvdef/core/diff.py
manifest ¶
parse ¶
parse ¶
kwargs::{escalate: bool = False, target_cls: bool = False, target_all: bool = False}
Source code in src/mvdef/core/parse.py
reparse ¶
Parse new text with the settings from an existing parsed result (a Checker object).
Create a new Checker with the same settings as the current instaance, but change the input file contents (equivalent to overwriting the file and parsing it again).