fix(code-graph): python __init__.py at root must not emit module scope
Problem
python_module_from_path collapses pkg/__init__.py → pkg by
stripping the trailing .__init__ segment. However, a bare __init__.py
at the repository root has no package prefix, so strip_suffix leaves
the string unchanged. The is_empty() guard on the next line does not
catch it, and "__init__" escapes as the module scope.
Consequence: every symbol defined in a root-level __init__.py is
recorded with module_scope = "\"__init__\"" in the graph, and every
relative import from that file resolves against a non-existent module
called "__init__", silently producing bad edges.
Fix
Add an explicit module == "__init__" guard and return None,
consistent with the is_empty() guard already present.
Also in this MR
- Move the misplaced doc comment from
resolve_python_relative_import
topython_module_from_pathwhere it belongs. - Add unit tests for both
python_module_from_pathandresolve_python_relative_import— neither function had any.
Tests
cargo test -p code-graph -- python
New tests added:
module_from_path_regular_filemodule_from_path_package_initmodule_from_path_nested_package_initmodule_from_path_top_level_filemodule_from_path_bare_init_is_none← regression test for the bugrelative_import_one_dotrelative_import_two_dotsrelative_import_too_many_dots_returns_nonerelative_import_dot_only_same_packagerelative_import_absolute_path_returns_none
What does this MR do and why?
Related Issues
Testing
Performance Analysis
- This merge request does not introduce any performance regression. If a performance regression is expected, explain why.
Agent context — long-form analysis, file-by-file walkthroughs, profiler output, alternatives considered
- fix(code-graph): python init.py at root must not emit module scope
python_module_from_path strips a dot-prefixed .__init__ segment when
a file lives inside a package (e.g. pkg/__init__.py → pkg). A bare
__init__.py at the repository root has no package prefix, so
strip_suffix leaves the string unchanged and the empty-check on the
next line lets "__init__" escape as the module scope.
Any symbol defined in a root-level __init__.py would therefore be
recorded with module_scope = "__init__", and every relative import
resolved from it would target a non-existent module called "__init__",
silently polluting the graph.
Fix: add an explicit guard for module == "__init__" and return None,
consistent with the empty-string guard already present.
Also add unit tests for both python_module_from_path and
resolve_python_relative_import, which previously had none, and move the
misplaced doc comment from resolve_python_relative_import to
python_module_from_path where it belongs.
What does this MR do and why?
A root-level init.py with no enclosing package was incorrectly assigned the module scope "init". As a result, symbols and relative imports originating from that file could be linked to a non-existent module in the graph. This change treats a repository-root init.py as having no module scope, preventing incorrect graph edges.
Testing
Added ten unit tests covering normal paths, the init.py regression case, and documented edge cases of relative-import resolution. Neither function had test coverage before this change.
Run with:
cargo test -p code-graph -- python
Performance Analysis
[x] This merge request does not introduce any performance regression.
[skip query-dsl-version-check].