fix: resolve absolute Python imports under src/ layout#607
Open
jepzone wants to merge 1 commit into
Open
Conversation
Extend resolve_absolute_import (the helper backing the Python dependency-graph builder and dynamic-import finder) to also probe src/-prefixed paths when the scan root or project root holds a src/ directory. Without these probes a project using the standard PEP 621 src layout — sources under <project>/src/<pkg>/... and scanned with --path . from the project root — could not resolve any of its own absolute imports. Every file under src/<pkg>/ then ended up with importer_count == 0 and the orphan-file detector emitted false-positive findings for entire production packages. Probe order is now: 1. <scan_root>/<dotted/path> 2. <project_root>/<dotted/path> 3. <scan_root>/src/<dotted/path> (only if src/ exists) 4. <project_root>/src/<dotted/path> (only if src/ exists) src/ candidates are appended only when those directories exist, keeping flat-layout behavior identical. The existing scan_root / project_root probes still run first, so flat layouts win when both exist. Adds tests in desloppify/languages/python/tests/test_py_deps_src_layout.py covering: - module, package __init__, and nested module resolution under src/ - flat layout still resolves correctly (no /src/ in result) - unresolvable modules return None - flat layout is preferred when both <root>/pkg and <root>/src/pkg exist - build_dep_graph end-to-end: shared module under src/pkg/ correctly records importer_count >= 2 (the original bug scenario)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
For a project using the standard PEP 621
src/layout — sources under<project_root>/src/<pkg>/...— scanning withdesloppify scan --path .from the project root never resolves any of the project's own absolute
imports.
resolve_absolute_importindesloppify/languages/python/detectors/deps_resolution.pycurrentlyprobes only:
<scan_root>/<dotted/path><project_root>/<dotted/path>For a file like
src/getaccept_worker/entities/activity.pyimported asfrom getaccept_worker.entities.activity import Activity, both candidatesmiss (the file lives under
src/getaccept_worker/..., not under the rootor scan root directly). The resolver returns
None, so every file undersrc/<pkg>/ends up withimporter_count == 0and the orphan-filedetector emits false-positive findings for entire production packages.
Repro
In a src-layout project (e.g. one with
[tool.hatch.build.targets.wheel] packages = ["src/getaccept_worker", "tools"]in
pyproject.toml):Direct check on this project:
Fix
Extend
resolve_absolute_importto additionally probesrc/-prefixedpaths under both the scan root and project root. New probe order:
<scan_root>/<dotted/path><project_root>/<dotted/path><scan_root>/src/<dotted/path>(only whensrc/exists)<project_root>/src/<dotted/path>(only whensrc/exists)src/candidates are appended only when those directories actually exist,so flat-layout behavior is identical. The existing
scan_root/project_rootprobes still run first, so flat layouts win when bothexist.
This is the conservative fix described as "the simple src-fallback" and
matches the layout declared by both Hatchling (
packages = ["src/<pkg>"])and setuptools (
[tool.setuptools.packages.find] where = ["src"]).A follow-up could parse those declarations explicitly, but the simple
fallback is enough to fix the common case.
After the fix on the repro project,
activity.pycorrectly reportsimporter_count == 21and the false-positive orphan findings are gone.Tests
New file:
desloppify/languages/python/tests/test_py_deps_src_layout.pyCovers:
src/pkg/mod.py__init__.pyresolution undersrc/pkg/src/pkg/a/b/c.py/src/in result)None<root>/pkgand<root>/src/pkgexistbuild_dep_graphend-to-end: shared module undersrc/pkg/correctlyrecords
importer_count >= 2(the original bug scenario)7 new tests; all 287 tests in
desloppify/languages/python/tests/andall 5810 tests in
desloppify/tests/still pass.