pytest两种启动方式的差异及ModuleNotFoundError报错原因与底层原理解析
python -m pytest Works But pytest Doesn't (ModuleNotFoundError for 'server') Let’s break down exactly why these two commands behave so differently, and what’s going on under the hood to cause that ModuleNotFoundError.
The Core Issue: Python’s Module Search Path (sys.path)
The root of the problem lies in how Python builds its module search list (sys.path) when you run these two commands. This list determines where Python looks for modules to import.
When you run python -m pytest
Using python -m pytest tells Python to load the pytest module as an executable script. This does two critical things for your project:
- It adds your current working directory (the
src/folder you’re in when running the command) to the very start ofsys.path. - It then launches the pytest runner from this context.
Since src/ is in sys.path, Python can immediately find the server module when conftest.py tries to import it—because server/ is a subdirectory of src/ (and has an __init__.py, so it’s recognized as a valid Python package).
When you run pytest directly
Running pytest as a standalone command works from a different context:
- It executes the
pytestexecutable located in your virtual environment’sbin/folder. - By default, pytest adds the directory containing your test files (your
src/tests/folder) tosys.path—but it doesn’t automatically include the parentsrc/folder.
So when conftest.py tries to import server, Python looks for it in src/tests/ (and other standard system paths) and comes up empty, hence the ModuleNotFoundError.
Underlying Mechanism Deep Dive
To get a bit more technical:
python -m <module>: This invokes Python’s built-in module loader, which setssys.path[0]to your current working directory (os.getcwd()). This is the same behavior you get when running a script withpython my_script.py—it prioritizes the folder you’re in when you run the command.- Standalone
pytestcommand: The pytest executable sets up its own runtime environment. By default, it focuses on the test directory, not the parent application directory. Unless you explicitly configure it to look elsewhere, it won’t scansrc/for your application modules.
Quick Fixes to Make pytest Work Directly
If you want to run pytest without relying on python -m pytest, here are two simple solutions:
- Add
src/tosys.pathinconftest.py:import sys from pathlib import Path # Add the parent directory (src/) to Python's module search path sys.path.append(str(Path(__file__).parent.parent)) - Configure pytest via
pyproject.toml:
Create apyproject.tomlfile in yoursrc/folder with this content:
This tells pytest to add the current[tool.pytest.ini_options] pythonpath = ["."]src/directory tosys.path, matching the behavior ofpython -m pytest.
内容的提问来源于stack exchange,提问作者Alexey Orlov

