← Debugging Guides

阅读中文版本

Python ModuleNotFoundError and circular ImportError — Fix Imports

Diagnose Python import failures by checking sys.executable and sys.path, finding shadowing modules and circular imports, then installing into the active environment.

beginnerdebuggingpythonimports

Symptoms

  • ModuleNotFoundError: No module named 'requests'
  • ImportError: cannot import name 'UserService' from partially initialized module
  • The package works in one terminal but not in a script, cron job, or container
  • The traceback points to a file with the same name as the module being imported

Possible causes

  • The dependency was installed into a different interpreter or virtual environment
  • A local file such as requests.py or json.py shadows the installed package
  • Two modules import each other at module scope, so one is only partially initialized
  • The project root or src directory is missing from sys.path when run as a script

Diagnosis steps

Confirm which interpreter is running

python -c "import sys; print(sys.executable); print(*sys.path, sep='\n')"

Interpretation

Compare the executable with the environment where you installed packages. A system Python next to a project venv explains most ModuleNotFoundError reports.

Check where the module resolves, if at all

python -c "import importlib.util; print(importlib.util.find_spec('requests'))"

Interpretation

None means the module is not importable from this interpreter. A path inside your project means a local file is shadowing the installed package.

Verify the installed distribution

python -m pip show requests && python -m pip list | grep -i requests

Interpretation

pip show reports the location it installed into. If that path is not in sys.path, the install belongs to another environment.

Time the import chain for circular failures

python -X importtime -c "import app" 2>&1 | tail -25

Interpretation

A partially initialized module in the traceback confirms a cycle. The import time log shows which module was still loading when the other tried to use it.

Root cause

Python resolves imports through sys.path and executes a module only once. A missing package means no path entry contains it for this interpreter, often because pip installed into a different environment. A circular import fails because module A starts executing, imports B, and B tries to read a name from A before A has defined it, leaving A partially initialized.

Fix

Activate the project environment and install with python -m pip so the package lands in the running interpreter. Remove or rename local files that shadow standard or third-party modules. Break import cycles by moving shared types to a separate module, importing inside the function that needs it, or using TYPE_CHECKING for type-only imports. Run modules with python -m package.module so package-relative imports resolve.

Risk note

Adding broad paths to sys.path or PYTHONPATH can mask a broken package layout and import the wrong code. Importing inside functions hides cycles but can move the failure to runtime. Installing globally with sudo risks breaking system tools that depend on the distribution's packages.

Verify the fix

Run the failing entry point from a clean shell with the same interpreter and confirm the import succeeds. Execute the test suite and check no partially initialized module warnings appear, then repeat inside the container or cron environment where the failure started.

Two different import failures

ModuleNotFoundError means the module was never found on sys.path. A circular import looks different:

ImportError: cannot import name 'UserService' from partially initialized module
'app.services' (most likely due to a circular import)

The module exists; it simply had not finished executing when another module asked for a name from it.

Check the interpreter first

python -c "import sys; print(sys.executable); print(*sys.path, sep='\n')"
python -c "import importlib.util; print(importlib.util.find_spec('requests'))"
python -m pip show requests

If find_spec returns None, the package is absent for this interpreter. If it returns a path inside your repository, a local requests.py is shadowing the real package. If pip shows a site-packages directory not present in sys.path, you installed into a different environment.

Fix the real cause

python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python -m app.main

For a cycle, move shared definitions to a third module, or defer the import:

def create_user(payload):
    from app.services import UserService
    return UserService.create(payload)

Prefer python -m package.module over running the file path directly, because it sets up package context correctly.

Verify

Re-run the failing entry point from a clean shell, then in the container or cron environment. python -m pytest should collect and pass without import warnings. If the fix only works in your IDE, the environment still differs: compare sys.executable there before declaring success.