如何将其他文件添加到转盘?


76

如何控制车轮中包含哪些文件?似乎MANIFEST.in没有被使用python setup.py bdist_wheel

更新

我错了从源tarball安装与安装轮子之间的区别。源代码发行版包含中指定的文件MANIFEST.in,但已安装的软件包仅包含python文件。无论是通过源分发版,egg还是wheel安装,都需要采取步骤来确定应安装的其他文件。即,附加软件包文件需要package_data,而软件包外部文件(例如命令行脚本或系统配置文件)需要data_files

原始问题

我有一个项目,我一直在使用python setup.py sdist来构建我的包,MANIFEST.in以控制包括和排除的文件,并pyroma退房清单,以确认我的设置。

我最近将其转换为双重Python 2/3代码,并添加了setup.cfg

[bdist_wheel]
universal = 1

我可以用构建轮子python setup.py bdist_wheel,并且根据需要它似乎是通用轮子。但是,它不包括中指定的所有文件MANIFEST.in

安装了什么?

我更深入地研究了,现在对包装和车轮有了更多的了解。这是我学到的:

我将两个包文件上传到PyPi上multigtfs项目

  • 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文件(以及自述文件)安装到该文件夹​​中,并且测试现在可以正确运行。感谢您的建议!


到底缺少哪些文件?
rje 2014年

任何非Python文件,例如文档或测试装置。我的应用程序包含一些用于测试的.zip文件,有些人可能会认为二进制分发版中不需要这些文件。其他人可能具有运行时所需的非Python文件。
jwhitlock

我很难理解你的问题。setup.py应该如何在文件中包含文件(标签描述为空,所以我不知道您指的是什么)?
llrs 2014年

wheel是Python的内置软件包格式,如果两者都可用,通常比.egg格式更受欢迎。要制造轮子,请运行python setup.py bdist_wheel。请参阅wheel.readthedocs.org(无法回答我的问题)上的文档,以及pythonwheels.com
jwhitlock

2
魔术组合是使用来指定文件MANIFEST.in,然后将其添加include_package_data=True到setup.py。
rspeed

Answers:


44

你有没有尝试使用package_data在你的setup.pyMANIFEST.in似乎是针对python版本<= 2.6的,我不确定是否还会使用更高版本。

在浏览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.
    package_data={
        'sample': ['package_data.dat'],
    },
    ...
)

(我不确定他们为什么选择其中的通配符MANIFEST.in和中的文件名setup.py。它们引用相同的文件)

再简单一点,这似乎又暗示该package_data路线优于该MANIFEST.in方法。好吧,除非您必须支持2.6,在这种情况下,我的祈祷会向您发出。


1
谢谢!这使我步入正轨。我为自己的问题添加了详细信息。
jwhitlock

很好的答案,那确实是元凶。这也是有关此问题不错的文章
令人惊讶的2015年

32

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

rm -rf build *.egg-info

如果您不这样做,则指望没有任何东西能正常工作。

现在,这已不复存在。

  1. 如果您要构建源代码发布sdist),则可以使用以下任何方法。

  2. 如果要构建转盘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让我们将数据文件放入包中。它是相同的,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

1
不直接支持@piRSquared通配符,但是您可以在此处使用其他答案的示例:glob('conf/*.json')
cmcginty

data_files格式不正确,应该是,:作为: data_files=[('my_data', ['data/data_file'])], 参考文档 我会编辑,但编辑必须是6个字符...
安德鲁·弗雷泽

@AndrewFraser ..现在已修复。
cmcginty

“ INCLUDE_PACKAGE_DATA是一个不错的选择,但是bdist_wheel不支持它”?include pkg/test/*.pyMANIFEST.in工作正常(在setuptools 45.2.0中)。
丹尼斯

23

您可以使用package_data,并data_filessetup.py指定的其他文件,但他们是可笑很难得到正确(和越野车)

另一种方法是使用MANIFEST.in和添加include_package_data=Truesetup()setup.py这里表示

使用此指令,MANIFEST.in将使用来指定文件,这些文件不仅包括在源tarball / zip中,而且包括在wheel和win32安装程序中。这也适用于任何python版本(我在py2.6到py3.6的项目中进行了测试)。

2020年更新:尽管MANIFEST.in仍然位于tar.gz中(即使您进行了设置),但MANIFEST.in在Python 3中似乎再也没有受到认可include_package_data=True

解决方法如下:您需要同时指定include_package_datapackages

如果您的Python模块位于“ pymod”文件夹中,则可以使用以下适当的设置:

setup( ...
    include_package_data = True,
    packages = ['pymod'],
)

如果您的python脚本位于根目录,请使用:

setup( ...
    include_package_data = True,
    packages = ['.'],
)

然后,您可以使用zip归档软件(例如7-zip)打开.whl文件,以检查所需的所有文件确实在其中。


4
这应该是当前接受的答案!package_data=...在另一个答案中使用as充满了危险(请阅读链接以及链接后面的链接)
马特·威尔基

随着NumPy的公司采取上setupnumpy.distutils.core,我不能让车轮与工作include_package_data=True。它只听package_data
llude

1
(1)轮子确实(尽管文档)尊重MANIFEST.in和include_package_data = True的组合,但是(2)这仅适用于“软件包数据”,也就是位于软件包目录中的内容,而不是例如项目根目录
布拉德·所罗门

10

您可以使用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')),
    ],
)

5
这看起来非常有前途,但是两个小时后我无法使data_files或package_files工作。您是否知道使用这些功能的任何项目都可以用于正常工作的代码?
jwhitlock

1

include_package_data是要走的路,它适用于sdist和wheel

但是,您必须正确地进行操作,这花了我几个月的时间才弄清楚,所以这就是我学到的东西。

技巧实际上是在选项名称中给出的include_PACKAGE_data数据文件必须位于package子文件夹中

当且仅当

  • include_package_data 是真的
  • 数据文件列在MANIFEST.in(*另请参阅结尾处的我的说明setuptools_scm
  • 并且数据文件在包目录下

然后将包含数据文件。

工作示例:

给定的项目具有以下结构和文件:

|- MANIFEST.in
|- setup.cfg
|- setup.py
|
\---foo
    |- __init__.py
    |
    \---data
         - example.png

并进行以下配置:

清单:

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.cfg之外,还可以在setup.py中直接指定配置。但这与示例无关。)

更新:对于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

并在清单中调整路径:

清单:

recursive-include src/foo/data *

注意:如果使用,则无需清单 setuptools_scm

如果您碰巧使用setuptools并添加setuptools_scm插件(在pypi上),则无需管理Manifest.in文件。相反,setuptools_scm将注意将git跟踪的所有文件添加到软件包中。

因此,在这种情况下,是否将文件添加到sdist / wheel的规则是:仅当且仅当

  • include_package_data 是真的
  • 该文件由git跟踪(或其他受setuptools_scm支持的工具)
  • 并且数据文件在包目录下

然后将包含数据文件。


我尝试过这种方法,但是运气不好data。我怀疑这是src基于我的布局以及它引入的额外的间接层。现在,我已data按照建议将目录移至package目录中,但使用代替了MANIFEST.in和。对于和双方来说都是黄金。通过使用包含所有这些隐式子目录的include_package_datapackage_data={'package': ['data/specific_file']}sdistbdist_wheel
glob

我更新了答案,它现在也适用于具有src布局的项目。
StefanD。20年

太棒了!我已将您的示例软件包逐字复制到我的环境中,并且效果很好。这让我弄清楚了为什么我的实际程序包表现出不同的原因...我忘了我一直numpy.distutils.core.setup在构建Fortran扩展,但是后来我随机地也必须导入setuptools.setup才能使bdist_wheel命令完全起作用。它制造轮子,但坚持使用package_data。这种通俗易懂的方法,可以使用有效的Python程序包,这使我想拔出剩下的几根毛发:-D
凌晨

-1

我的config /目录中包含JSON文件,需要将其添加到wheel包中。因此,我将这些行添加到MANIFEST.in

recursive-include config/ *.json

以下指令可用于setup.py

setup(
 ...
 include_package_data=True,
)

没有任何效果。直到我创建了一个称为__init__.pyinsideconfig/目录的空文件。

(Python 3.6.7,wheel 3.6.7,setuptools 39.0.1)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.