使用Poetry发布PyPI包后遇ModuleNotFoundError:找不到file_b模块
问题
我用Poetry创建了一个名为file-a的Python包,目录结构如下:
my-app/ ├─ src/ │ ├─ __init__.py │ ├─ models/ │ ├─ helpers/ │ ├─ file_a.py │ ├─ file_b.py ├─ __init__.py ├─ tests/ │ ├─ tests.py ├─ __init__.py ├─ pyproject.toml
开发阶段,在file_a.py里用from file_b import FileB导入类,tests.py里用from file_a import FileA导入,一切正常。但发布到PyPI后,在其他项目中执行以下代码:
from file_a import FileA a = FileA()
出现报错:
Traceback (most recent call last): File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/runpy.py", line 194, in _run_module_as_main return _run_code(code, main_globals, None, File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/runpy.py", line 87, in _run_code exec(code, run_globals) File "src/__main__.py", line 1, in <module> from kinetic_sdk import KineticSdk File "/Users/me/Library/Caches/pypoetry/virtualenvs/kinetic-python-example-17HFj6yJ-py3.8/lib/python3.8/site-packages/file_a.py", line 1, in <module> from file_b import FileB ModuleNotFoundError: No module named 'file_b'
原因分析
开发时,src目录被Python解释器加入了sys.path,直接用from file_b import...能找到同目录下的模块。但发布后,包被安装到site-packages目录,此时file_a.py和file_b.py属于file_a(包名file-a会被Python转换为file_a作为导入名称)的子模块,不再是顶级模块,直接导入file_b自然找不到。
解决方法
1. 使用相对导入
修改file_a.py中的导入语句,明确从当前包的同目录导入:
from .file_b import FileB
这种方式适合包内部模块间的依赖引用,逻辑清晰。
2. 使用绝对导入(基于包名)
以包名为前缀进行导入,确保无论运行环境如何都能定位到模块:
from file_a.file_b import FileB
这种方式更直观,尤其适合复杂项目结构。
3. 调整目录结构(推荐)
当前目录下src直接存放.py文件的方式不符合Python包的标准结构,建议调整为src下包含与包名对应的子目录:
my-app/ ├─ src/ │ ├─ file_a/ # 对应包名file-a,Python导入时用file_a │ │ ├─ __init__.py │ │ ├─ models/ │ │ ├─ helpers/ │ │ ├─ file_a.py │ │ ├─ file_b.py ├─ tests/ │ ├─ tests.py ├─ pyproject.toml
同时在pyproject.toml中正确配置包路径:
[tool.poetry] name = "file-a" packages = [{ include = "file_a", from = "src" }]
如果希望用户能直接from file_a import FileA,可以在src/file_a/__init__.py中导出类:
# src/file_a/__init__.py from .file_a import FileA from .file_b import FileB
内容的提问来源于stack exchange,提问作者Alex Ramirez
相关产品推荐
相关产品推荐

