如何将其他文件添加到***?

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_dataMANIFEST.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.0 谢谢!这个答案太有用了。我对MANIFEST.in 没有做任何事情感到非常困惑。这立即解决了我的问题。【参考方案2】:

在您对MANIFEST.insetup.py 进行任何更改之前,您必须删除旧的输出目录。 Setuptools 正在缓存一些数据,这可能会导致意外结果。

rm -rf build *.egg-info

如果您不这样做,则预计不会正常工作。

现在不碍事了。

    如果您正在构建源分发版 (sdist),那么您可以使用以下任何方法。

    如果您正在构建*** (bdist_wheel),则include_package_dataMANIFEST.in 将被忽略,您必须使用package_datadata_files

INCLUDE_PACKAGE_DATA

这是一个不错的选择,但bdist_wheel 不接受它。

setup(
    ...
    include_package_data=True
)

# MANIFEST.in
include package/data.json

DATA_FILES 用于非包数据

这是最灵活的选项,因为您可以将存储库中的任何文件添加到 sdistbdist_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,让我们将数据文件放入包中。 sdistsdist 相同,但比 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_datadata_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_datapackages

如果您的 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.9pip 21.01。我在setup() 中使用packages=find_packages() 并将其更改为packages=find_packages() + ['.'],以及include_package_data=True @BradSolomon :您能否更好地解释第二点,例如如果我使用src/layout,如何在根目录中包含文件?另外,我注意到诸如 jupyter-notebookblack 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.ininclude_package_data,改用package_data='package': ['data/specific_file']。对于sdistbdist_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)

【讨论】:

以上是关于如何将其他文件添加到***?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 css 添加到我的其他本地网页? [关闭]

IOS将app添加到其他app的“其他方式”打开列表中

如何使用命令行将“其他链接器标志”添加到 xcode 项目?

将 QWidget 或其他 QWidget 派生控件添加到 QWindow

如何向 Visual Studio 项目添加其他库?

如何将二进制数拆分为 6 位二进制数并在 C 中添加其他位?