我在遇到同样的问题时找到了这篇文章。
我的经验与其他答案中的经验相矛盾。
include_package_data=True
确实包含了
bdist 中的数据!在 setuptools
文档
中的解释缺乏上下文和故障排除提示,但是
include_package_data
按照广告所说的那样工作。
我的设置:
- Windows / Cygwin
- git 版本 2.21.0
- Python 3.8.1 Windows 发行版
setuptools
v47.3.1
check-manifest
v0.42
以下是我的操作指南。
如何包含软件包数据
这是我在 PyPI 上发布的一个项目的文件结构。
(它将应用程序安装在 __main__.py
中)。
├── LICENSE.md
├── MANIFEST.in
├── my_package
│ ├── __init__.py
│ ├── __main__.py
│ └── _my_data <---- folder with data
│ ├── consola.ttf <---- data file
│ └── icon.png <---- data file
├── README.md
└── setup.py
起始点
这是在setup.py
中用于setuptools.setup()
的通用起始点。
setuptools.setup(
...
packages=setuptools.find_packages(),
...
)
setuptools.find_packages()
包含了我的所有包在分发中。我唯一的包是 my_package
。
Python 不认为我的数据子文件夹 _my_data
是一个包,因为它不包含 __init__.py
文件,所以 find_packages()
找不到它。
一个经常被引用但错误的解决方案是在 _my_data
文件夹中放置一个空的 __init__.py
文件。
这样可以使它成为一个包,因此它可以在分发中包括文件夹 _my_data
。但是_my_data
内部的数据文件不会被包含。
因此,将 _my_data
转换为包 没有帮助。
解决方法如下:
sdist
已经包含了数据文件
- 添加
include_package_data=True
来在 bdist
中也包含数据文件
实验(如何测试解决方案)
有三个步骤可以使这个实验具有可重复性:
$ rm -fr build/ dist/ my_package.egg-info/
$ check-manifest
$ python setup.py sdist bdist_wheel
我会逐步解释以下内容:
- 清除旧版本构建:
$ rm -fr build/ dist/ my_package.egg-info/
- 运行
check-manifest
确保 MANIFEST.in
与版本控制下的 Git 文件索引匹配:
$ check-manifest
如果
MANIFEST.in
不存在,
请从 Git 版本控制下的文件索引中创建它:
$ check-manifest --create
这里是创建的 MANIFEST.in
文件:
include *.md
recursive-include my_package *.png
recursive-include my_package *.ttf
这个文件没有手动编辑的必要。
只要所有应该在版本控制下的内容都在版本控制下(即是Git索引的一部分),check-manifest --create
就会做正确的事情。
注意:如果文件符合以下任一条件,则不属于Git索引:
- 在
.gitignore
中被忽略
- 在
.git/info/exclude
中被排除
- 或者仅仅是还未被添加到索引中的新文件
如果有任何不应该受版本控制的文件却被纳入了版本控制,check-manifest
会发出警告并指出建议从Git索引中删除哪些文件。
- 构建:
$ python setup.py sdist bdist_wheel
现在检查
sdist
(源分发)和
bdist_wheel
(构建分发),看它们是否包含数据文件。
查看
sdist
的内容(只显示相关行):
$ tar --list -f dist/my_package-0.0.1a6.tar.gz
my_package-0.0.1a6/
...
my_package-0.0.1a6/my_package/__init__.py
my_package-0.0.1a6/my_package/__main__.py
my_package-0.0.1a6/my_package/_my_data/
my_package-0.0.1a6/my_package/_my_data/consola.ttf <-- yay!
my_package-0.0.1a6/my_package/_my_data/icon.png <-- yay!
...
因为在MANIFEST.in
中列出了数据文件,所以sdist
已经包含了这些文件。不需要额外操作来将数据文件包含在sdist
中。
查看bdist
的内容(它是一个.zip文件,使用zipfile.ZipFile
进行解析):
$ python check-whl.py
my_package/__init__.py
my_package/__main__.py
my_package-0.0.1a6.dist-info/LICENSE.md
my_package-0.0.1a6.dist-info/METADATA
my_package-0.0.1a6.dist-info/WHEEL
my_package-0.0.1a6.dist-info/entry_points.txt
my_package-0.0.1a6.dist-info/top_level.txt
my_package-0.0.1a6.dist-info/RECORD
注意:您需要创建自己的
check-whl.py
脚本以生成上述输出。它只有三行代码:
from zipfile import ZipFile
path = "dist/my_package-0.0.1a6-py3-none-any.whl"
print('\n'.join(ZipFile(path).namelist()))
正如预期的那样,bdist
缺少数据文件。
_my_data
文件夹完全丢失。
如果我创建一个_my_data/__init__.py
会怎样?我重复实验,发现数据文件仍然不在那里!_my_data/
文件夹已经被包含了,但它不包含数据文件!
解决方案
与其他人的经验相反,这个方法是可行的:
setuptools.setup(
...
packages=setuptools.find_packages(),
include_package_data=True,
...
)
修复后,重新进行实验:
$ rm -fr build/ dist/ my_package.egg-info/
$ check-manifest
$ python.exe setup.py sdist bdist_wheel
确保 sdist
仍然包含数据文件:
$ tar --list -f dist/my_package-0.0.1a6.tar.gz
my_package-0.0.1a6/
...
my_package-0.0.1a6/my_package/__init__.py
my_package-0.0.1a6/my_package/__main__.py
my_package-0.0.1a6/my_package/_my_data/
my_package-0.0.1a6/my_package/_my_data/consola.ttf <-- yay!
my_package-0.0.1a6/my_package/_my_data/icon.png <-- yay!
...
查看 bdist
的内容:
$ python check-whl.py
my_package/__init__.py
my_package/__main__.py
my_package/_my_data/consola.ttf <--- yay!
my_package/_my_data/icon.png <--- yay!
my_package-0.0.1a6.dist-info/LICENSE.md
my_package-0.0.1a6.dist-info/METADATA
my_package-0.0.1a6.dist-info/WHEEL
my_package-0.0.1a6.dist-info/entry_points.txt
my_package-0.0.1a6.dist-info/top_level.txt
my_package-0.0.1a6.dist-info/RECORD
如何不测试数据文件是否已包含
我建议使用上述方法来检查sdist
和bdist
以进行故障排除/测试。
可编辑模式下的pip安装不是有效的测试
注意:pip install -e .
不能 显示数据文件是否已包含在bdist
中。
符号链接会导致安装行为就像数据文件已包含一样(因为它们已经存在于开发者的计算机上)。
在pip install my_package
之后,数据文件位于虚拟环境的lib/site-packages/my_package/
文件夹中,使用与whl
内容列表中所示的完全相同的文件结构。
发布到TestPyPI是缓慢的测试方式
发布到TestPyPI,然后安装并查看lib/site-packages/my_packages
是一种有效的测试方法,但时间成本太高。
pyproject.toml
正确地将数据文件打包到wheels和sdists中,无需setup.py
文件。 - wim