从TestPyPI安装的Python包目录结构与上传时不一致致报错
问题描述
我创建了name_generator_nicomp包并上传至TestPyPI。包内逻辑需要读取一个文本文件,本地开发时将文件放在独立文件夹中,运行正常。
在另一台机器通过以下命令安装该包:
python3 -m pip install --index-url https://test.pypi.org/simple/ name-generator-nicomp --upgrade
运行测试脚本时:
if __name__ == "__main__": from name_generator_nicomp.NameGenerator import NameGenerator nameGenerator = NameGenerator()
包内执行以下代码时失败:
with importlib.resources.open_text("src.data", self.noun_file) as my_file:
报错信息:
ModuleNotFoundError: No module named 'src'
构建生成的.gz包中存在src目录及内部的data目录,TestPyPI仓库也保留该结构,但安装到本地后,所有代码和数据文件都在同一文件夹,无其他目录层级。
我的pyproject.toml文件内容如下:
[project] name = "name_generator_nicomp" version = "0.0.2" authors = [ { name="xxx xxxxxx", email="xxx.com" }, ] description = "Some description." readme = "README.md" requires-python = ">=3.8" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ] [project.urls] Homepage = "https://github.com/nicomp42/name_generator" Issues = "https://github.com/nicomp42/name_generator/issues" [build-system] requires = ["hatchling"] build-backend = "hatchling.build"
完整报错栈:
Traceback (most recent call last): File "C:\Users\nicholdw\eclipse-workspace\myNameGenerator\mainPackage\main.py", line 3, in <module> nameGenerator = NameGenerator() File "C:\Users\nicholdw\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\name_generator_nicomp\NameGenerator.py", line 36, in __init__ self.prepare() File "C:\Users\nicholdw\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\name_generator_nicomp\NameGenerator.py", line 47, in prepare with importlib.resources.open_text("src.data", self.noun_file) as my_file: File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\importlib\resources.py", line 82, in open_text open_binary(package, resource), encoding=encoding, errors=errors File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\importlib\resources.py", line 43, in open_binary package = _common.get_package(package) File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\importlib\_common.py", line 66, in get_package resolved = resolve(package) File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\importlib\_common.py", line 57, in resolve return cand if isinstance(cand, types.ModuleType) else importlib.import_module(cand) File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1050, in _gcd_import File "<frozen importlib._bootstrap>", line 1027, in _find_and_load File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 1050, in _gcd_import File "<frozen importlib._bootstrap>", line 1027, in _find_and_load File "<frozen importlib._bootstrap>", line 1004, in _find_and_load_unlocked ModuleNotFoundError: No module named 'src'
解决方案
问题根源在于Hatchling构建时扁平化了src目录结构,同时资源文件的读取路径没有适配安装后的层级。
1. 调整包结构与构建配置
方式一:修改pyproject.toml指定源码目录
在pyproject.toml中添加Hatchling的构建配置,保留包的层级结构:
[tool.hatch.build] sources = ["src"]
或者更精确地指定包路径:
[tool.hatch.build.targets.wheel] packages = ["src/name_generator_nicomp"]
方式二:规范本地目录结构
将data目录作为包的子目录,确保结构如下:
src/ └── name_generator_nicomp/ ├── __init__.py ├── NameGenerator.py └── data/ ├── __init__.py # 必须添加,让Python识别为模块 └── [你的名词文件].txt
2. 修改资源读取代码
安装后src层级不再存在,需要将读取路径改为包内的相对路径:
# 替换原代码 with importlib.resources.open_text("name_generator_nicomp.data", self.noun_file) as my_file:
更推荐使用相对导入,避免硬编码包名:
from importlib.resources import open_text from . import data with open_text(data, self.noun_file) as my_file:
3. 重新构建上传
修改完成后,重新构建并上传至TestPyPI:
python -m build python -m twine upload --repository testpypi dist/*
内容的提问来源于stack exchange,提问作者nicomp
相关产品推荐
相关产品推荐

