本文详细说明了如何规范使用 src 布局避免 ModuleNotFoundError: No module named 'src强调不会 src 写入 import 语句是通过可安装的包装来安装的 + pyproject.toml 稳定、可移植、符合要求 PEP 517 模块分析。
本文详细说明了如何规范使用 `src` 布局避免 `modulenotfounderror: no module named 'src'`,强调不会 `src` 写入 import 语句是通过可安装的包装来安装的 + `pyproject.toml` 稳定、可移植、符合要求 pep 517 模块分析。
在 Python 在工程实践中,“src 目录不是一个可导入的模块名称,而是一个常规的源代码根容器目录(source layout)。你遇到的 ModuleNotFoundError: No module named 'src' 不是环境配置失败,而是设计层面的根本误用:from src.config import ... 这种写法是违反的 Python 包管理的核心原则——src 在任何情况下都不应该出现 import 路径中。
根据 Python Packaging User Guide,src/ 包裹的唯一职责是实际包裹 Python 包(如 afrr, config 等等),而不是自己做包。因此,您的目录结构应调整为:
/
├── pyproject.toml ← 替代 setup.py,现代标准
├── src/
│ └── afrr/ ← 真正的可导入包(含) __init__.py)
│ ├── __init__.py
│ ├── dumper.py
│ └── cleaner.py
│ └── config.py ← 如果是独立模块(非包),可以保留;如果需要组织为包,建议 src/myproject/config.py
│ └── tests/ ← ❌ 试验不应放在那里 src 内!见下文说明
└── tests/ ← ✅ 测试应与 src 平级(推荐)
└── test_afrr_dumper.py✅ 正确的导入方法(修改后)⚠️ 关键修正:
tests/目录不应嵌套在内src/下。测试代码不属于发布包的内容,混入src/会导致find_packages()错误包括测试模块、污染安装包和破坏隔离。
假设你把核心包命名为 afrr(即 src/afrr/ 是包),把 config.py 移至 src/afrr/config.py 或者作为独立的顶层模块(如 src/config.py 且 src 配置为 package_dir),所有导入必须基于包名,而不是目录名:
立即学习“Python免费学习笔记(深入);
# ✅ 正确:从包 afrr 导入
from afrr.dumper import dump_afrr_data
from afrr.config import PROCESSED_DIR # 若 config.py 在 src/afrr/ 下
# ✅ 或(若 config.py 在 src/ 并已配置根部 package_dir={"": "src"}):
from config import PROCESSED_DIR❌ 错误示例(永远不要写):
from src.afrr.dumper import ... # src 不是包名 from src.config import ... # 同上✅ 现代可安装配置(
pyproject.toml)
创建 pyproject.toml(取代 setup.py),启用 src 布局并声明包名:
Python数据分析助手
为业务和科研数据的快速处理提供Python数据清理、统计分析和可视化建议。
下载[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "afrr" version = "0.1.0" dependencies = [ "pandas>=1.0.0", ] [project.optional-dependencies] test = ["pytest"] [project.urls] Homepage = "https://example.com" [tool.hatch.build.targets.sdist] include = ["src/**"] [tool.hatch.build.targets.wheel] source = "src"
然后执行:
pip install -e . # 安装为可编辑模式(editable install)
该命令会将 src/ 下的 afrr(以及其他符合命名规则的包)注册 Python 的 sys.path,使 import afrr 全局可用 —— 无需设置 PYTHONPATH,跨平台稳定,不依赖运行位置。
移出测试文件 src/,在项目根目录下 tests/:
/
├── pyproject.toml
├── src/
│ └── afrr/
│ ├── __init__.py
│ ├── dumper.py # 含 def dump_afrr_data(...)
│ └── config.py
└── tests/
└── test_afrr_dumper.pytests/test_afrr_dumper.py 内容应为:
import pytest
from afrr.dumper import dump_afrr_data
from afrr.config import PROCESSED_DIR
def test_dump_works():
assert callable(dump_afrr_data)
assert isinstance(PROCESSED_DIR, str)运行测试(确保项目根目录):
pytest tests/ -v # 或指定 Python path(已安装的自动识别 afrr 包) python -m pytest tests/ -v? 总结:永久解决三个步骤
-
清理 import 路径:删除一切
from src.xxx,只使用真实包名(如afrr,config); -
重构目录:
src/仅作为源码容器,tests/与src/平级,pyproject.toml明确source = "src"; -
可编辑安装:
pip install -e .配置,永久生效,支持 IDE 自动补充、调试和 CI/CD。
该方案完全避免了手动环境变量、路径硬编码或 IDE 具体设置,符合 Python 最好的社区实践,也是 hatch、poetry、setuptools 等主流默认推荐工程路径。