Python项目文件层级问题:Docker运行时模块导入失败
问题描述
我的Python项目文件层级结构如下(src下还有更多子文件夹):
ip-rep/ │ ├── ip_rep/ │ ├── __init__.py │ ├── run.py │ ├── src/ │ ├── __init__.py │ ├── cli_tool/ │ ├── __init__.py │ └── cli_loader.py ├── tests/ │ ├── test_cli_loader │ └── test_cli_loader.py │ ├── Dockerfile ├── bash_start.sh
Dockerfile简化配置:
RUN mkdir app WORKDIR /app ADD ip_rep /app/ip_rep ADD load_ips.sh /app/ RUN chmod +x /app/load_ips.sh ENTRYPOINT ["/bin/bash", "load_ips.sh"]
启动脚本load_ips.sh简化内容:
python ip_rep/run.py
run.py中的导入语句:
from ip_rep.src.cli_tool.cli_loader import CliTool
运行时出现错误:
Traceback (most recent call last): File "ip_rep/run.py", line 9, in <module> from ip_rep.src.cli_tool.cli_loader import CliTool ModuleNotFoundError: No module named 'ip_rep'
如果移除导入语句中的ip_rep仅保留src.路径,本地测试将无法正常运行,请问问题出在哪?
问题原因与解决办法
核心原因
Docker容器内运行python ip_rep/run.py时,Python会自动把**脚本所在的目录(/app/ip_rep)**加入sys.path,而非当前工作目录/app。此时ip_rep目录本身是sys.path里的一个路径,Python会把它当成顶层包的根目录,所以你用from ip_rep.src...导入时,Python在sys.path里找不到名为ip_rep的子包,自然报错。
而本地测试时,你大概率是从项目根目录(ip-rep/)运行测试,此时ip_rep是顶层包,Python能识别到它,所以带ip_rep的导入能正常工作。
兼容本地测试与Docker运行的两种方案
方案一:以模块方式运行脚本(推荐)
修改load_ips.sh,先把项目根目录(/app)加入Python的路径,再用-m参数以模块方式启动run.py:
export PYTHONPATH=/app python -m ip_rep.run
这种方式下,Python会把/app当成包的根目录,ip_rep作为顶层包被识别,和本地测试的环境一致,导入语句无需修改。
方案二:用相对导入+测试环境补全路径
- 修改
run.py的导入语句为相对导入:
from .src.cli_tool.cli_loader import CliTool
- 在测试目录下添加
conftest.py(或直接在测试脚本开头)补全路径,让测试能识别到顶层包:
import sys from pathlib import Path # 把项目根目录(ip-rep)加入sys.path sys.path.append(str(Path(__file__).parent.parent.parent))
这样Docker运行时,run.py在ip_rep目录下,相对导入能正常找到src;本地测试时,补全路径后Python能识别ip_rep顶层包,测试也能正常运行。
内容的提问来源于stack exchange,提问作者Ema Il
相关产品推荐
相关产品推荐

