Python源码分发包如何正确包含非Python杂项文件
核心问题
你之前的配置不生效,本质是对setuptools的资源文件规则理解有偏差:
package_data、include_package_data两个配置只对packages参数中声明的Python包(即带__init__.py的目录)生效,你当前的res文件夹是项目根目录下的独立目录,不属于任何已声明的Python包,这两个规则根本扫描不到该路径下的文件。MANIFEST.in默认仅控制源码包(.tar.gz格式的sdist)内的文件列表,不会自动决定哪些文件会被安装到site-packages目录,就算你写规则把html打进源码包,安装时也不会复制到对应位置。data_files的设计用途就是把文件安装到系统环境的全局路径(比如环境根目录、系统共享目录),本来就不会复制到包目录下,不符合你的需求。
解决方法
二选一即可,优先推荐方案1,兼容性和规范性最好。
方案1:调整目录结构(推荐)
把res目录移动到你已经声明的tool包下,调整后的项目结构:
ProjectA ├─ tool/ │ ├─ __init__.py │ ├─ modulea.py │ └─ res/ │ ├─ template_a.html │ ├─ template_b.html │ └─ template_c.html ├─ constant.py ├─ project_a.py ├─ MANIFEST.in(如果用package_data配置可以删掉这个文件) └─ setup.py
修改setup.py的配置,两种写法选一个就行:
- 用
package_data(最直观,不需要依赖MANIFEST.in)
setup( # 其余原有配置保持不变 packages = ['tool'], package_data = { 'tool': ['res/*.html'] }, )
- 用
include_package_data配合MANIFEST.insetup.py中打开配置:
setup( # 其余原有配置保持不变 packages = ['tool'], include_package_data = True, )
MANIFEST.in写入规则:
graft tool/res
代码中读取html文件时,不要写硬编码的相对路径,用Python3.7+自带的importlib.resources获取实际安装路径,避免路径错误:
from importlib.resources import files template_path = files('tool.res').joinpath('template_a.html')
方案2:不改动现有目录结构
如果不想移动res文件夹,就把项目根目录声明为Python包:
- 在ProjectA根目录新建空的
__init__.py文件 - 修改
setup.py配置:
setup( # 其余原有配置保持不变 packages = ['tool', ''], # 空字符串代表根目录作为Python包 package_data = { '': ['res/*.html'] }, )
读取文件时对应路径为res.template_a.html即可。
验证步骤
配置修改完成后,先在项目根目录执行pip install -e .做可编辑安装,到对应虚拟环境的site-packages目录下检查html文件是否存在;再执行pip wheel .生成whl安装包,用压缩软件打开whl包确认html文件已被包含——whl内存在的文件,安装时一定会被复制到对应位置。
内容的提问来源于stack exchange,提问作者YTKme
相关产品推荐
相关产品推荐

