Repository navigation
Python: from app import x links to a project variable named app, not the app package #2584
Description
Summary
In Python, from app import email creates an imports edge from the importing file to any project variable named app, such as the usual FastAPI/Flask app = FastAPI() in app/main.py. The edge is exact-match at 0.9. The package itself (app/__init__.py) gets no edge unless the file also has a separate import app. Every test or module that imports from a package named like a variable is then reported as a dependent of that variable's file.
Reproduction (verified)
On main at 8fe3156, built from source, Linux (WSL2), Node 22.23.2, WASM extractor (CODEGRAPH_KERNEL=0). Four files:
# app/__init__.py
(empty)# app/email.py
def send():
return 1# app/main.py
app = object()# tests/test_email.py
from app import email
def test_send():
email.send()codegraph init -i, then the imports / calls edges (target kind included):
tests/test_email.py -imports-> variable app [app/main.py:1] @1 exact-match/0.9
tests/test_email.py -imports-> file app/email.py [app/email.py:1] @1 import/0.9
test_send -calls-> function send [app/email.py:1] @5 import/0.85
Expected: no edge to the variable app in app/main.py. tests/test_email.py imports the package app, so if the module-name ref links anywhere it should be app/__init__.py.
Variants, same build:
| Change | Edge for the from app module name |
|---|---|
| as above | -> variable app [app/main.py:1], exact-match/0.9 |
app/main.py is x = object() instead |
none |
variable moved to server.py at the root (app = object()) |
-> variable app [server.py:1], exact-match/0.9 |
import app added above the from app import email line |
-> file app/__init__.py from both lines, import/0.9 |
The email edge and the send call are correct in every row.
Likely cause (inferred from reading the code)
- For
from X import ..., the Python hook returnsXas the module name, and the extractor pushes it as animportsref withreferenceName: 'app'. - The import resolver looks refs up by import-mapping
localName, both inresolveModuleImportToFileand in the main mapping loop. The mapping forfrom app import emailhaslocalNameemail, so nothing matchesapp. Withimport apppresent there is a mapping keyedapp, which is why the last variant links the package. - The ref then reaches name matching. A variable is an importable kind, so the only
appin the project is taken by the single-candidate shortcut at 0.9. Theimportspost-check accepts it for the same reason.
A ref that names the module of a from X import statement is a module path, so it could resolve to a file or package or not at all, and never by symbol name.
Related
- Python:
from <external> import namebinds to an unrelated project symbol of the same name (exact-match) — false import cycles #2566 (open):from <external> import namebinds the imported name to an unrelated project symbol by exact match. This issue is about the module name of an internal package, not the imported name, and a different extractor ref. - fix(python): resolve imports from the package roots the project has #1921 (open PR): Python imports resolved from the project's package roots. A build of the inth3shadows fork that carries fix(python): resolve imports from the package roots the project has #1921 (and fix(python): resolve attribute-receiver calls by evidence, never by bare name #1704 / fix(python): type attributes set by a factory or a base class (#1704, #750) #1926) gives the same edge as above, so as carried there it does not cover this case. I have not built the current PR head.
- wrong import relationship in table edges #2409 (open):
import logginglinks to the project'sapp/core/logging.py. That is a file-suffix match withresolvedBy: import, a different path. - An import of a workspace package resolves onto a non-exported local variable of the same name (157 edges in vitejs/vite) #1719 (closed): the TypeScript form, a workspace-package import that resolved onto a same-named local variable.
Not checked
- Dotted module names (
from app.api import routes). - Relative imports (
from . import x,from .. import x). - A function or class named like the package, instead of a variable.
- The native kernel extractor (only
CODEGRAPH_KERNEL=0was run). - Windows and macOS.
Activity