Skip to content

follow-up: entrypoint wrapper-eligibility misclassifies a repo module that shadows a stdlib name (sys/os/asyncio) #2543

Description

@carlos-alm

Deferred from PR #2542 review (Greptile finding on src/extractors/python.ts:296 / mirrored crates/codegraph-core/src/extractors/python.rs, find_enclosing_call_name / STDLIB_PROCESS_LAUNCHER_MODULES).

Background: #2420 needed to distinguish a wrapper call (sys.exit(main())) from the real entrypoint target (main) so only one gets role: 'entry'. Three review rounds converged on: a wrapper is excluded from bare-name resolution only if its import source is one of a small curated set of stdlib modules (sys, os, asyncio) — everything else (a local instance, a same-repo module import, a third-party package) flows through the normal bare-name resolution check.

Finding: the curated-set check matches by import source name only (import asyncio → source "asyncio"), not by whether that import actually resolved to a stdlib module vs. an in-repo file. If a repository defines its own top-level module literally named asyncio.py (or sys.py/os.py) and a qualifying guard calls asyncio.run(main()) intending to invoke that local module's run, the check still treats it as the external stdlib passthrough — main gets the label instead of run, reproducing the original #2420 bug for this shape.

Why this wasn't fixed inline: closing this gap precisely requires knowing whether the import actually resolved to an in-repo file, not just its source name. That information exists in the graph (as imports-kind edges, created during import resolution) but only after the build's import-resolution phase completes — extraction time (where the current wrapper/entrypointWrappedBy decision is made) runs before that. Deciding wrapper eligibility from real resolved-import data would mean moving (or duplicating) this decision into the post-hoc projection stage (projectEntrypointAttribution / project_entrypoint_attribution), correlating each wrapper's import statement to its actual resolved target — a real design change, not a quick patch, and squarely the kind of "needs its own design" work #2420's own original issue text flagged as out of scope for a first pass.

Severity/likelihood: low. Triggering this requires a repository to define its own module with the exact same name as a Python stdlib module (sys, os, or asyncio) — already unusual and arguably confusing/discouraged Python practice independent of this tool. Unlike the three shapes fixed in #2420 (a local instance, an unwrapped call, a same-repo module import under an ordinary name), this one needs a deliberate stdlib-name collision to manifest.

Suggested approach for whoever picks this up: extend the wrapper-eligibility check in projectEntrypointAttribution/project_entrypoint_attribution to consult the file's actual imports edges (or an equivalent resolved-import record) rather than (or in addition to) the curated stdlib-name set — i.e., only treat a wrapper as "definitely external" when its import source name is in the curated set and no imports edge exists from the guard's file to an in-repo target for that same source. Needs the equivalent change in both engines per the dual-engine architecture.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions