Fix Python submodule imports from external source roots - #3275
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Resolves absolute Python imports made from outside the package tree (e.g. tests/ importing from src/) by discovering source-root directories across the corpus with _discover_python_source_roots and probing them in _resolve_python_module_path via a new source_roots argument. Resolution fails closed when multiple source roots yield conflicting candidates for the same module, binding only when there's a single unambiguous target.
No blocking issues surfaced. 3 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1722 functions depend on the 144 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 522 callers, 43 callees - new:
_rebuild_code()— 113 callers, 50 callees - new:
_extract_generic()— 18 callers, 25 callees - new:
extract_js()— 85 callers, 4 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
dispatch_command()— 2 callers, 123 callees - new:
extract_objc()— 27 callers, 9 callees - new:
_resolve_js_module_path()— 27 callers, 6 callees - …and 32 more — each is listed as a finding
Verification — 1722 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 735 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_collect\_python\_symbol\_resolution\_facts.
The verifier did not have enough to check \_collect\_python\_symbol\_resolution\_facts, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set
Could not verify: Could not verify \_resolve\_python\_module\_path.
The verifier did not have enough to check \_resolve\_python\_module\_path, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `current_path` is annotated `Path` — outside the synthesizable primitive/collection set
· 40 more finding(s) on lines outside this diff (see the check run).
Summary
Fixes #3272 by correcting Python submodule resolution when imports originate outside the package's source root.
Previously, imports such as:
could fail to resolve
helper.pywhen the importing file was outside asrc/-style package tree, such as a test file undertests/.Changes
Added dynamic Python source-root discovery based on
__init__.pypackage boundaries.Pass discovered source roots into Python module resolution as fallback candidates.
Preserved the existing resolution order and relative-import behavior.
Added fail-closed handling for ambiguous matches across multiple source roots.
Discover source roots once per extraction batch to avoid repeated directory traversal.
Added regression tests for:
src/.Validation
12 passed— focused Python resolution tests.19 passed, 442 deselected— Python-focused suite.339 passed, 4 skipped, 1 failed— broader extraction/build suite.git diff --checkpasses cleanly.The single broader-suite failure is the existing Windows
MAX_PATHfailure intest_c_include_out_of_root_target_id_is_deterministic_across_checkout_pathsand is unrelated to this change.