Skip to content

Fix Python submodule imports from external source roots - #3275

Open
hopstreax wants to merge 1 commit into
Graphify-Labs:v8from
hopstreax:investigate/3272-package-submodule-import
Open

Fix Python submodule imports from external source roots#3275
hopstreax wants to merge 1 commit into
Graphify-Labs:v8from
hopstreax:investigate/3272-package-submodule-import

Conversation

@hopstreax

Copy link
Copy Markdown
Contributor

Summary

Fixes #3272 by correcting Python submodule resolution when imports originate outside the package's source root.

Previously, imports such as:

from towmo.core import helper

could fail to resolve helper.py when the importing file was outside a src/-style package tree, such as a test file under tests/.

Changes

  • Added dynamic Python source-root discovery based on __init__.py package 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:

    • Imports from both inside and outside src/.
    • Multiple source roots with distinct packages.
    • Ambiguous packages across multiple source roots.

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 --check passes cleanly.

The single broader-suite failure is the existing Windows MAX_PATH failure in test_c_include_out_of_root_target_id_is_deterministic_across_checkout_paths and is unrelated to this change.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant