Tests ast
tests_ast
Read-only AST inspection: tests, classes, imports, helpers, markers.
All helpers operate on ast.Module / ast.stmt nodes from the stdlib
ast module — no libcst, no mutation, no I/O beyond Path.read_text
when an entry point takes a path. This file gathers every read-side AST
primitive used by the fix pipeline so that cst_rewrite / stages_*
can stay focused on side-effects.
Future: the higher-level pieces (top_level_test_classes,
top_level_helpers, collect_imported_names) may move to
axm-ast once that package exposes raw ast.Module access. The
fine-grained walkers (class_is_pathological, marker_fixtures_in_unit)
are too specific to pytest semantics to belong in a general lib.
class_is_pathological(cls)
Return a reason if the class cannot be safely flattened, else None.
Pathological = uses self.<attr> inside methods, has __init__,
inherits from anything other than object (or empty bases).
Source code in packages/axm-audit/src/axm_audit/core/fix/tests_ast.py
collect_imported_names(tree)
Return {imported_name: (import_stmt, enclosing_block_or_None)}.
Walks the whole module — not just top-level — so that if TYPE_CHECKING
blocks are scanned too. enclosing_block is the if TYPE_CHECKING:
statement (or similar) wrapping the import, or None for top-level.
For from x import y and from x import y as z, the mapping uses
the local binding name (y or z).
Source code in packages/axm-audit/src/axm_audit/core/fix/tests_ast.py
collect_referenced_names(tree)
Names actually referenced from live top-level symbols.
Restricted to Name(Load) reachable from:
* decorators on top-level FunctionDef / ClassDef
* class bases and keywords
* argument annotations + default expressions of top-level functions
* function bodies of top-level FunctionDef / ClassDef methods
(excluding nested string literals, which ast.walk would otherwise
pick up if someone embedded a textwrap.dedent block)
* top-level Assign / AnnAssign right-hand sides
Walking the whole module — as the previous implementation did —
picks up identifiers inside dead branches, string literals parsed by
callers via ast.parse(some_dedent_block), etc. and triggers F401
backfills for names that aren't really used.
Source code in packages/axm-audit/src/axm_audit/core/fix/tests_ast.py
file_has_pathological_class(source)
True iff source contains a Test* class that class_is_pathological
flags AND that has divergent method canonicals.
Used by plan_naming SPLIT and _execute_split to short-circuit
when Stage 0 was unable to flatten — avoids planning a SPLIT that
will only partially route and leave the file mid-state.
Cheap: only walks classes, no canonicalisation. Pathological with a single canonical is fine: the class is homogeneous and SPLIT will move it as a block.
Source code in packages/axm-audit/src/axm_audit/core/fix/tests_ast.py
func_body_hash(func)
Stable string hash of a function body (for collision dedup).
Comparison is structural via ast.unparse on the body — ignores docstrings, comments, and minor formatting.
Source code in packages/axm-audit/src/axm_audit/core/fix/tests_ast.py
marker_fixtures_in_unit(node)
Return fixture names declared via @pytest.mark.usefixtures("X", ...).
Source code in packages/axm-audit/src/axm_audit/core/fix/tests_ast.py
| Python | |
|---|---|
top_level_helpers(tree)
Return {name: (body_hash, node)} for every top-level helper.
A helper is a top-level FunctionDef / ClassDef that is NOT a test
(test_* / Test*) plus single-target uppercase NAME = ...
constants. Fixtures (@pytest.fixture) are included — they're
helpers from the body-conflict perspective.
Source code in packages/axm-audit/src/axm_audit/core/fix/tests_ast.py
top_level_test_classes(tree)
Test classes at module level that contain test_ methods.