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

1 participant