* fix(resolution): resolve Python module members through an aliased from-import (#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 #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> (cherry picked from commit f7a8940e679b5d4093dd2d00412306a6b4800723) * fix(resolution): restore aliased Python module import edges (#1626) Use the exported module name in the file-import resolver, matching the member resolver from upstream PR #1635. Keep both aliased call assertions and verify the file-to-file imports edge in the #1626 regression test. Update the Unreleased note to cover file dependencies. Validation on Node 22.19.0: npm run build; supplied cg1626 repro; vitest run __tests__/resolution.test.ts -t 1626. Pass evidence saved in /workspace/cg1626-PASS.json and /workspace/cg1626-VERIFY.json. --------- Co-authored-by: Max Hsu <maxmilian@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
This commit is contained in:
co-authored by
Max Hsu
Claude
Colby McHenry
parent
2f8cce5c57
commit
7be699cd91
@@ -1692,11 +1692,19 @@ function resolvePythonModuleMember(
|
||||
// `import mod` / `import numpy as np` bind the module at `source` itself;
|
||||
// `from . import certs` / `from pkg import mod` bind a SUBMODULE whose
|
||||
// dotted path is the source joined with the imported name.
|
||||
//
|
||||
// Join with the EXPORTED name, not the local one: under
|
||||
// `from pkg import mod as alias` the receiver is `alias` but the module on
|
||||
// disk is `pkg.mod`, and building `pkg.alias` looked for a file that does
|
||||
// not exist — so the aliased form dropped its `calls` edge while the plain
|
||||
// form (where the two names coincide) worked (#1626). For an unaliased
|
||||
// import the two are identical, so this changes nothing there.
|
||||
const moduleName = imp.exportedName === '*' ? imp.localName : imp.exportedName;
|
||||
const modulePath = imp.isNamespace
|
||||
? imp.source
|
||||
: imp.source.endsWith('.')
|
||||
? imp.source + imp.localName
|
||||
: imp.source + '.' + imp.localName;
|
||||
? imp.source + moduleName
|
||||
: imp.source + '.' + moduleName;
|
||||
|
||||
// resolveImportPath only maps RELATIVE dotted paths (`.mod`, `..pkg.mod`); an
|
||||
// ABSOLUTE package path (`pkg.module` from `from pkg import module`, or a bare
|
||||
@@ -1884,9 +1892,12 @@ function resolveModuleImportToFile(
|
||||
modulePath = imp.source;
|
||||
} else if (ref.language === 'python') {
|
||||
// `from . import certs` — the imported NAME is a submodule of the source.
|
||||
// As in resolvePythonModuleMember, use the exported name so an alias
|
||||
// still links to the real module file (#1626).
|
||||
const moduleName = imp.exportedName === '*' ? imp.localName : imp.exportedName;
|
||||
modulePath = imp.source.endsWith('.')
|
||||
? imp.source + imp.localName
|
||||
: imp.source + '.' + imp.localName;
|
||||
? imp.source + moduleName
|
||||
: imp.source + '.' + moduleName;
|
||||
} else {
|
||||
// A named TS/JS import binds a symbol, not a module — leave it alone.
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user