Skip to content

Python: aliased module imports (import x as y, from p import x as y) still produce zero call edges — remaining gap after #578 / #715 #1626

Description

@JoeyNPP

Summary

#578 (module-attribute call sites after from pkg import module) was fixed by #715 and the plain form now resolves correctly. But the aliased forms still produce no calls edges on 1.6.0 (latest, npm). The call lands in unresolved_refs with status='failed' and the caller is silently absent from codegraph_callers and from the MCP codegraph_explore blast-radius summary.

Repro (1.6.0, win32-x64, Python project)

# services/kit.py
def sync_subscribers(get_db):
    ...

# routes/email.py
from services import kit as kit_service        # <-- aliased from-import

def handler():
    kit_service.sync_subscribers(get_db)       # no calls edge
# hook.py
import build_api_contract as builder           # <-- aliased plain import

builder.source_fingerprint()                   # no calls edge

Observed on a real repo (side-by-side in the same index, same session):

Import form calls edge created?
from services import email_send -> email_send.log_sent() yes (fixed by #715)
from services import leads as leads_svc -> leads_svc.convert_lead_to_buyer() no
import build_api_contract as builder -> builder.source_fingerprint() no

Module-level vs function-scoped import makes no difference — both aliased forms miss.

unresolved_refs rows for the failing sites look like:

('builder.source_fingerprint', 'calls', 'failed')
('kit_service.sync_subscribers', 'calls', 'failed')

Why it bites

Same consequence as #578: codegraph_callers reports a function as having one caller (a script) when a live route handler also calls it through the alias — "is this dead code?" gets the wrong answer. The MCP codegraph_explore output is also self-inconsistent in this case: the blast-radius header says "1 caller in scripts/kit_sync.py" while the verbatim source it prints below shows the aliased call site.

Suggested fix

Wherever #715 taught the Python resolver that a bare imported-module name qualifies attribute calls, the alias table needs to participate: import x as y / from p import x as y should register y as a binding for module x in the same scope map.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions