MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / resolvePythonModuleMember

Function resolvePythonModuleMember

src/resolution/import-resolver.ts:1607–1659  ·  view source on GitHub ↗

* Resolve a Python qualified reference whose receiver is an imported MODULE: * `certs.where()` after `from . import certs`, `mod.func()` after `import mod` * or `from pkg import mod`. The receiver names a submodule (a file), not a * symbol, so the generic symbol lookup in `resolveViaImport` can't

(
  ref: UnresolvedRef,
  imports: ImportMapping[],
  context: ResolutionContext
)

Source from the content-addressed store, hash-verified

1605 * to the other strategies untouched.
1606 */
1607function resolvePythonModuleMember(
1608 ref: UnresolvedRef,
1609 imports: ImportMapping[],
1610 context: ResolutionContext
1611): ResolvedRef | null {
1612 const dotIdx = ref.referenceName.indexOf('.');
1613 if (dotIdx <= 0) return null;
1614 const receiver = ref.referenceName.substring(0, dotIdx);
1615 // The immediate member of the module (first segment after the receiver).
1616 const member = ref.referenceName.substring(dotIdx + 1).split('.')[0];
1617 if (!member) return null;
1618
1619 for (const imp of imports) {
1620 if (imp.localName !== receiver) continue;
1621
1622 // `import mod` / `import numpy as np` bind the module at `source` itself;
1623 // `from . import certs` / `from pkg import mod` bind a SUBMODULE whose
1624 // dotted path is the source joined with the imported name.
1625 const modulePath = imp.isNamespace
1626 ? imp.source
1627 : imp.source.endsWith('.')
1628 ? imp.source + imp.localName
1629 : imp.source + '.' + imp.localName;
1630
1631 // resolveImportPath only maps RELATIVE dotted paths (`.mod`, `..pkg.mod`); an
1632 // ABSOLUTE package path (`pkg.module` from `from pkg import module`, or a bare
1633 // `import pkg.mod`) resolves to null there, so fall back to the dotted-module
1634 // file lookup — the same asymmetry resolveModuleImportToFile already handles
1635 // for the file→file import edge. Without this, a `module.func()` call after
1636 // `from pkg import module` dropped its `calls` edge even though the import
1637 // edge resolved (#578).
1638 let resolvedPath = resolveImportPath(modulePath, ref.filePath, ref.language, context);
1639 if (!resolvedPath) {
1640 resolvedPath = findPythonModuleFile(modulePath, context, ref.filePath)?.filePath ?? null;
1641 }
1642 if (!resolvedPath || resolvedPath === ref.filePath) continue;
1643
1644 // Find the member as a top-level definition in the module file. Exclude
1645 // `method` so `mod.foo` never lands on a same-named class method.
1646 const target = context.getNodesInFile(resolvedPath).find(
1647 (n) =>
1648 n.name === member &&
1649 (n.kind === 'function' ||
1650 n.kind === 'class' ||
1651 n.kind === 'variable' ||
1652 n.kind === 'constant')
1653 );
1654 if (target) {
1655 return { original: ref, targetNodeId: target.id, confidence: 0.85, resolvedBy: 'import' };
1656 }
1657 }
1658 return null;
1659}
1660
1661/**
1662 * Resolve a whole-MODULE import to that module's file (a file→file dependency).

Callers 1

resolveViaImportFunction · 0.85

Calls 3

resolveImportPathFunction · 0.85
findPythonModuleFileFunction · 0.85
getNodesInFileMethod · 0.65

Tested by

no test coverage detected