如何将其他文件添加到***?
Posted
技术标签:
【中文标题】如何将其他文件添加到***?【英文标题】:How do you add additional files to a wheel? 【发布时间】:2014-08-12 09:40:03 【问题描述】:如何控制***中包含哪些文件? MANIFEST.in
似乎没有被 python setup.py bdist_wheel
使用。
更新:
我对从源 tarball 安装与从***安装之间的区别是错误的。源码分发包含MANIFEST.in
中指定的文件,但安装的包只有python文件。需要采取步骤来识别应安装的其他文件,无论安装是通过源代码分发、egg 还是 wheel。也就是说,额外的包文件需要package_data,而包外的文件(如命令行脚本或系统配置文件)需要data_files。
原始问题
我有a project,我一直使用python setup.py sdist
构建我的包,MANIFEST.in
控制包含和排除的文件,pyroma 和check-manifest 确认我的设置。
我最近将其转换为双 Python 2 / 3 代码,并添加了一个 setup.cfg 与
[bdist_wheel]
universal = 1
我可以用python setup.py bdist_wheel
制作一个***,它似乎是一个万能***。但是,它不包括MANIFEST.in
中指定的所有文件。
安装了什么?
我挖得更深了,现在对包装和***有了更多的了解。这是我学到的:
我上传了两个包文件到multigtfs project on PyPi:
multigtfs-0.4.2.tar.gz
- 源 tar 包,包含 MANIFEST.in
中的所有文件。
multigtfs-0.4.2-py2.py3-none-any.whl
- 有问题的二进制分布。
我创建了两个新的虚拟环境,都使用 Python 2.7.5,并安装了每个包 (pip install multigtfs-0.4.2.tar.gz
)。这两个环境几乎相同。它们有不同的 .pyc
文件,它们是“编译”的 Python 文件。有日志文件记录磁盘上的不同路径。从源 tar 球安装包括一个文件夹 multigtfs-0.4.2-py27.egg-info
,详细说明了安装,而***安装有一个 multigtfs-0.4.2.dist-info
文件夹,其中包含该过程的详细信息。不过从使用multigtfs项目的代码来看,两种安装方式没有区别。
明确地说,我的测试也没有使用 .zip 文件,因此测试套件将失败:
$ django-admin startproject demo
$ cd demo
$ pip install psycopg2 # DB driver for PostGIS project
$ createdb demo # Create PostgreSQL database
$ psql -d demo -c "CREATE EXTENSION postgis" # Make it a PostGIS database
$ vi demo/settings.py # Add multigtfs to INSTALLED_APPS,
# Update DATABASE to set ENGINE to django.contrib.gis.db.backends.postgis
# Update DATABASE to set NAME to test
$ ./manage.py test multigtfs.tests # Run the tests
...
IOError: [Errno 2] No such file or directory: u'/Users/john/.virtualenvs/test/lib/python2.7/site-packages/multigtfs/tests/fixtures/test3.zip'
指定附加文件
使用答案中的建议,我向setup.py
添加了一些额外的指令:
from __future__ import unicode_literals
# setup.py now requires some funky binary strings
...
setup(
name='multigtfs',
packages=find_packages(),
package_data=b'multigtfs': ['test/fixtures/*.zip'],
include_package_data=True,
...
)
这会将 zip 文件(以及 README)安装到文件夹中,并且测试现在可以正常运行。感谢您的建议!
【问题讨论】:
缺少哪些文件? 任何非 Python 文件,例如文档或测试装置。我的应用程序包含一些在测试中使用的 .zip 文件,有些人可能认为二进制分发中不需要这些文件。其他人可能有运行时需要的非 Python 文件。 我很难理解你的问题。 setup.py应该如何在***中包含文件(标签描述为空,所以我不知道你指的是什么)? wheel 是 Python 的内置包格式,如果两者都可用,则通常优于 .egg 格式。要构建一个***,请运行python setup.py bdist_wheel
。请参阅wheel.readthedocs.org(不回答我的问题)和pythonwheels.com 的文档。
神奇的组合是使用MANIFEST.in
指定文件,然后在setup.py中添加include_package_data=True
。
【参考方案1】:
您是否尝试过在您的setup.py
中使用package_data
? MANIFEST.in
似乎针对 python 版本
在探索https://github.com/pypa/sampleproject 之后,他们的MANIFEST.in
说:
# If using Python 2.6 or less, then have to include package data, even though
# it's already declared in setup.py
include sample/*.dat
这似乎暗示这种方法已经过时了。同时,他们在setup.py
中声明:
setup(
name='sample',
...
# If there are data files included in your packages that need to be
# installed, specify them here. If using Python 2.6 or less, then these
# have to be included in MANIFEST.in as well.
include_package_data=True,
package_data=
'sample': ['package_data.dat'],
,
...
)
(我不确定他们为什么在MANIFEST.in
中选择通配符,在setup.py
中选择文件名。它们指的是同一个文件)
除了更简单之外,这似乎再次暗示package_data
路由优于MANIFEST.in
方法。好吧,除非你必须支持 2.6,否则我会向你祈祷。
【讨论】:
很好的答案,这确实是罪魁祸首。这里也是nice article about this issue。 这个答案在 Python 3.8 中不再适用。下面的答案有效。我对其进行了编辑以添加include_package_data=True
,因此它实际上可以与晚期模型 Python 一起使用。
@rjurney 感谢您的编辑!它是否仍然适用于带有该标志的 3.0MANIFEST.in
没有做任何事情感到非常困惑。这立即解决了我的问题。【参考方案2】:
在您对MANIFEST.in
或setup.py
进行任何更改之前,您必须删除旧的输出目录。 Setuptools 正在缓存一些数据,这可能会导致意外结果。
rm -rf build *.egg-info
如果您不这样做,则预计不会正常工作。
现在不碍事了。
如果您正在构建源分发版 (sdist
),那么您可以使用以下任何方法。
如果您正在构建*** (bdist_wheel
),则include_package_data
和MANIFEST.in
将被忽略,您必须使用package_data
和data_files
。
INCLUDE_PACKAGE_DATA
这是一个不错的选择,但bdist_wheel
不接受它。
setup(
...
include_package_data=True
)
# MANIFEST.in
include package/data.json
DATA_FILES 用于非包数据
这是最灵活的选项,因为您可以将存储库中的任何文件添加到 sdist
或 bdist_wheel
setup(
....
data_files=[
('output_dir',['conf/data.json']),
]
# For sdist, output_dir is ignored!
#
# For bdist_wheel, data.json from conf dir in root of your repo
# and stored at `output_dir/` inside of the sdist package.
)
包内非python文件的PACKAGE_DATA
与上述类似,但对于bdist_wheel
,让我们将数据文件放入包中。 sdist
与 sdist
相同,但比 data_files
有更多限制,因为文件只能从您的包子目录中获取。
setup(
...
package_data='package':'data.json',
# data.json must be inside of your actual package
)
【讨论】:
您能添加一个使用glob
模式的示例吗?我猜data_files
这个元组会起作用:('output_dir': ['conf/*.json'])
@piRSquared globbing 不受直接支持,但您可以在此处使用其他答案中的示例:glob('conf/*.json')
data_files 格式不正确,应该是 ,
而不是 :
如:data_files=[('my_data', ['data/data_file'])],
Reference doc 我会编辑,但编辑需要 6 个字符...
@AndrewFraser .. 已修复。
评论“INCLUDE_PACKAGE_DATA 是一个不错的选择,但 bdist_wheel 不支持它”:这不完全正确,应该在答案中澄清:如果数据文件包含在包子目录之一中和include_package_data=True
并且它们被列在Manifest.in
然后它们将被包括在内。【参考方案3】:
您可以在setup.py
中使用package_data
和data_files
指定其他文件,但它们是ridiculously hard to get right (and buggy)。
另一种方法是使用MANIFEST.in
并在setup()
的setup()
中添加include_package_data=True
作为indicated here。
使用此指令,MANIFEST.in
将用于指定不仅要包含在源 tarball/zip 中的文件,还要包含在 wheel 和 win32 安装程序中。这也适用于任何 python 版本(我在从 py2.6 到 py3.6 的项目上进行了测试)。
2020 年更新:Python 3 中的***似乎不再支持 MANIFEST.in,尽管它仍然在 tar.gz 中,即使您设置了include_package_data=True
。
解决方法如下:您需要同时指定 include_package_data
和 packages
。
如果您的 Python 模块位于“pymod”文件夹中,则以下是适当的设置:
setup( ...
include_package_data = True,
packages = ['pymod'],
)
如果您的 python 脚本位于根目录,请使用:
setup( ...
include_package_data = True,
packages = ['.'],
)
然后您可以使用 7-zip 等 zip 存档软件打开您的 .whl 文件,以检查您想要的所有文件是否确实在其中。
【讨论】:
这应该是当前公认的答案!在另一个答案中使用package_data=...
充满危险(阅读链接,以及链接后面的链接)
NumPy 在numpy.distutils.core
中采用setup
,我无法让***与include_package_data=True
一起工作。它只听package_data
。
(1) Wheels do(尽管有文档)尊重 MANIFEST.in 加上 include_package_data = True 的组合,然而 (2) 仅此适用于“包数据”,也就是位于包目录中的东西,而不是项目根目录
这对我有用 python 3.6.9
和 pip 21.01
。我在setup()
中使用packages=find_packages()
并将其更改为packages=find_packages() + ['.']
,以及include_package_data=True
。
@BradSolomon :您能否更好地解释第二点,例如如果我使用src/layout
,如何在根目录中包含文件?另外,我注意到诸如 jupyter-notebook、black editor 之类的项目没有使用MANIFEST.in
结构来包含数据文件,而是使用复杂的package_data
结构@987654323 @,他们为什么要这样做?而像 django 这样的项目正在使用常规的MANIFEST.in
。另外,切换到flit
这样的工具会更好吗?【参考方案4】:
您可以使用data_files 指令指定要安装的额外文件。那是你要找的吗?这是一个小例子:
from setuptools import setup
from glob import glob
setup(
name='extra',
version='0.0.1',
py_modules=['extra'],
data_files=[
('images', glob('assets/*.png')),
],
)
【讨论】:
这看起来很有希望,但 2 小时后我无法让 data_files 或 package_files 工作。您是否知道任何使用这些功能的项目我可以寻找工作代码? +1 使用 python 3.8.5。这是迄今为止唯一对我有用的答案。【参考方案5】:include_package_data
是要走的路,它适用于 sdist andwheels。
但是你必须做对,我花了几个月的时间才弄明白,所以这就是我学到的。
诀窍本质上是在选项名称include_PACKAGE_data
中给出的:数据文件需要在包子文件夹中
当且仅当
include_package_data
是真的
数据文件在MANIFEST.in
中列出(*另见我在末尾关于setuptools_scm
的注释)
数据文件在包目录下
然后将包含数据文件。
工作示例:
鉴于项目具有以下结构和文件:
|- MANIFEST.in
|- setup.cfg
|- setup.py
|
\---foo
|- __init__.py
|
\---data
- example.png
还有如下配置:
Manifest.in:
recursive-include foo/data *
setup.py
import setuptools
setuptools.setup()
setup.cfg
[metadata]
name = wheel-data-files-example
url = www.example.com
maintainer = None
maintainer_email = none@example.com
[options]
packages =
foo
include_package_data = True
sdist 包和您构建的***也将包含example.png
数据文件。
(当然,也可以直接在setup.py中指定config,而不是setup.cfg。但这与示例无关。)
更新:对于 src 布局项目
这也适用于使用 src 布局的项目,如下所示:
|- MANIFEST.in
|- setup.cfg
|- setup.py
|
\---src
|
\---foo
|- __init__.py
|
\---data
- example.png
要使其正常工作,请使用package_dir
告诉 setuptools src 目录:
setup.cfg
[metadata]
name = wheel-data-files-example
url = www.example.com
maintainer = None
maintainer_email = none@example.com
[options]
packages =
foo
include_package_data = True
package_dir =
=src
并在清单中调整路径:
Manifest.in:
recursive-include src/foo/data *
注意:如果您使用 setuptools_scm
,则不需要 Manifest.in
如果您碰巧使用 setuptools 并添加了 setuptools_scm
插件 (on pypi),则无需管理 Manifest.in 文件。相反,setuptools_scm 将负责将 git 跟踪的所有文件都添加到包中。
因此,对于这种情况,是否将文件添加到 sdist/wheel 的规则是: 当且仅当
include_package_data
是真的
文件由 git(或其他 setuptools_scm 支持的工具)跟踪
数据文件在包目录下
然后将包含数据文件。
【讨论】:
我尝试了这种方法,但没有让data
进入方向盘。我怀疑这是我的基于src
的布局和它引入的额外间接层。我现在按照建议将我的data
目录移到了包目录中,但是去掉了MANIFEST.in
和include_package_data
,改用package_data='package': ['data/specific_file']
。对于sdist
和bdist_wheel
来说,一切都是金色的。祝你好运使用所有这些隐含子目录的 glob... :-)
我更新了我的答案,它现在也应该适用于具有 src 布局的项目。
太棒了!我已将您的示例包逐字复制到我的环境中,并且效果很好。这让我能够弄清楚为什么我的实际包的行为不同......我忘记了我正在使用numpy.distutils.core.setup
来构建一个 Fortran 扩展,但后来我随机不得不导入setuptools.setup
以获得bdist_wheel
命令完全可以工作。它制造了***,但坚持使用package_data
。这条通往工作 Python 包的货物*** hacky-sacky 路线让我想拔掉我剩下的几根头发:-D
我想我搞砸了我的 Manifest.in
文件,但我发现添加 [options.package_data]
* =
*.png
也可以,而且你不会用 污染你的存储库另一个文件.【参考方案6】:
我有 config/ 目录,其中包含 JSON 文件,我需要将其添加到 wheel 包中。所以,我已将这些行添加到MANIFEST.in
:
recursive-include config/ *.json
setup.py
的以下指令:
setup(
...
include_package_data=True,
)
没有任何效果。
直到我在 config/
目录中创建了一个名为 __init__.py
的空文件。
(Python 3.6.7,wheel 3.6.7,setuptools 39.0.1)
【讨论】:
以上是关于如何将其他文件添加到***?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用命令行将“其他链接器标志”添加到 xcode 项目?