Skip to content

fix(resolution): resolve Python module members through an aliased from-import (#1626) - #1635

Open
maxmilian wants to merge 1 commit into
colbymchenry:mainfrom
maxmilian:fix/1626-python-aliased-module
Open

fix(resolution): resolve Python module members through an aliased from-import (#1626)#1635
maxmilian wants to merge 1 commit into
colbymchenry:mainfrom
maxmilian:fix/1626-python-aliased-module

Conversation

@maxmilian

Copy link
Copy Markdown
Contributor

Fixes the from … import … as … half of #1626.

resolvePythonModuleMember rebuilds the submodule's dotted path by joining the import source with the local name. Under from pkg import mod as alias that produces pkg.alias — a module that doesn't exist — so the file lookup finds nothing, the member never resolves, and the call lands in unresolved_refs with status='failed'. codegraph_callers then reports the target as having fewer callers than it does, which is exactly the wrong "is this dead code?" answer that #578 produced for the unaliased form.

Joining with the exported name fixes it. For an unaliased import the two names are identical, so nothing changes there; the namespace form (exportedName === '*') keeps binding at the local name, which is what it already did.

Scope: the report has two halves and only one reproduces

The issue also lists import build_api_contract as builderbuilder.source_fingerprint() as producing no edge. That form resolves on current main. It's a namespace import that binds at source — the real module name — so it never goes through the local-name join this PR fixes.

I checked rather than assumed: with the resolver change reverted, a probe on the plain-aliased call site in the test fixture still reports one calls edge. So if @JoeyNPP is still seeing that case fail on a real project, there's a second cause and it isn't this one — worth keeping #1626 open on that half, or splitting it out.

Tests

One case added beside the existing #578 test in resolution.test.ts (same integration shape — real CodeGraph.init with index: true), asserting both halves:

  • from pkg import module as mod_aliasmod_alias.func() resolves to pkg/module.py — fails before the change (expected [] to have a length of 1)
  • import top_level as tltl.top_func() resolves — green before and after, pinned so fixing one half can't break the other

Full suite: 178 files / 3053 tests passing (3052 on main plus this one). tsc --noEmit clean.

Reported by @JoeyNPP.

…m-import (colbymchenry#1626)

resolvePythonModuleMember rebuilt the submodule's dotted path by joining the
import source with the LOCAL name. Under 'from pkg import mod as alias' that
produces 'pkg.alias' — a module that does not exist — so the file lookup found
nothing and the call fell through to unresolved_refs with status='failed'.
codegraph_callers then reported the target as having fewer callers than it
does, which is the same wrong 'is this dead code?' answer colbymchenry#578 produced for
the unaliased form.

Join with the exported name instead. For an unaliased import the two names are
identical, so nothing changes there; '*' (the namespace form) keeps using the
local name, which is what it already bound to.

Scope note: the issue also reports 'import top as alias' failing. That form is
a namespace import and binds at source, so it resolves on current main — a
probe against the reverted resolver confirms it already produces its call edge.
The regression test pins both halves so the working one cannot silently break.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant