如何在setuptools / distribute中包含软件包数据?


135

使用setuptools / distribute时,我无法使安装程序提取任何package_data文件。我读过的所有内容都表明,以下是正确的方法。有人可以请教吗?

setup(
   name='myapp',
   packages=find_packages(),
   package_data={
      'myapp': ['data/*.txt'],
   },
   include_package_data=True,
   zip_safe=False,
   install_requires=['distribute'],
)

myapp/data/数据文件的位置在哪里。


2
我遇到了同样的问题...手动指定data_files解决了该问题。但这容易出错,对我来说并不“正确”。有人可以验证是否确实有必要package_data和中复制配置data_files吗?
2011年

github.com/wimglenn/resources-example 显示了一个现代的setuptools项目结构,可以使用正确地将数据文件打包到wheel和sdists中pyproject.toml。无需setup.py文件。
维姆

Answers:


289

我知道这是一个老问题,但人们发现这里通过谷歌自己的方式: package_data是低了下来,肮脏的谎言。它仅在构建二进制软件包(python setup.py bdist ...)时使用,在构建源软件包(python setup.py sdist ...)时不使用。当然,这是荒谬的-人们希望构建源代码分发将导致文件集合,这些文件可以发送给其他人来构建二进制分发。

在任何情况下,使用MANIFEST.in将工作二进制和源分布。


97
在过去的一个小时中,我一直在研究此问题,并尝试了许多方法。就像您说的那样,它package_databdist而不是sdist但是MANIFEST.in适用于sdist,但适用bdist!因此,我想出的最好的办法是同时包含package_dataMANIFEST.in,以便同时容纳bdistsdist
Wesley Baugh 2013年

7
我找到了另一个支持@WesleyBaugh的人。在stackoverflow.com/a/2969087/261718中MANIFEST.in用于将不会安装的文件(例如文档)以及package_data用于非Python代码的文件(例如图像或模板)。
Drake Guan

12
我正在使用sdist,必须同时包含MANIFEST.in package_data。似乎可以MANIFEST.in控制分发中包含的内容,而package_data可以控制随后在安装过程中将其复制到site_packages目录中的内容。令人困惑的是,路径MANIFEST.in相对于setup.py的位置,并且package_data相对于各个包(例如模块)的根目录。
爱德华·纽厄尔

9
“在2.7版中进行了更改:如果没有提供模板,则所有与package_data匹配的文件都将添加到MANIFEST文件中。请参阅指定要分发的文件。” 来自distutils。因此,仅当您不存在MANIFEST.in文件时,并且仅在使用2.7+时,您才会看到文件package_data自动包含在ZIP中的行为。
约翰斯,2016年

29
认真地说,我觉得这张票是针对使用设置工具的人们进行的集体治疗课程,目的是发现他们在生活中所经历的恐怖境地。
马特·乔伊斯

32

我只是有同样的问题。解决的方法是简单地删除include_package_data=True

这里阅读之后,我意识到它include_package_data旨在包含来自版本控制的文件,而不是顾名思义仅包含“ include package data”。从文档:

[include_package_data]的数据文件必须处于CVS或Subversion控制之下

...

如果要对包含的文件进行更细粒度的控制(例如,如果您的软件包目录中有文档文件,并希望将其从安装中排除),则也可以使用package_data关键字。

把那个参数排除掉可以解决这个问题,这恰好是为什么当您切换到distutils时它也可以工作的原因,因为它不接受那个参数。


2
我的经历有所不同,我遇到了同样的问题,但没有包含include_package_data=True入题。对我来说,唯一的解决方案是按照上面的建议在清单中添加一个条目。介意您使用的是setuptools,也许您的版本适用于“ distribute”?
TimStaley

4
删除include_package_data后再解决问题的实际原因还包括在原文中如果使用setuptools特定的include_package_data参数,package_data除非指定的MANIFEST.in文件列出在文件中,否则不会自动将其指定的文件添加到清单中。
Piotr Dobrogost '16

package_data设置为非空列表并指定的用例是什么include_package_data=False?为什么还要在MANIFEST.in和中两次指定文件package_data
赫伯特

21

遵循@Joe的建议删除该include_package_data=True行也对我有用。

详细说明一下,我没有 MANIFEST.in文件。我使用Git而不是CVS。

存储库采用以下形式:

/myrepo
    - .git/
    - setup.py
    - myproject
        - __init__.py
        - some_mod
            - __init__.py
            - animals.py
            - rocks.py
        - config
            - __init__.py
            - settings.py
            - other_settings.special
            - cool.huh
            - other_settings.xml
        - words
            - __init__.py
            word_set.txt

setup.py

from setuptools import setup, find_packages
import os.path

setup (
    name='myproject',
    version = "4.19",
    packages = find_packages(),  
    # package_dir={'mypkg': 'src/mypkg'},  # didnt use this.
    package_data = {
        # If any package contains *.txt or *.rst files, include them:
        '': ['*.txt', '*.xml', '*.special', '*.huh'],
    },

#
    # Oddly enough, include_package_data=True prevented package_data from working.
    # include_package_data=True, # Commented out.
    data_files=[
#               ('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
        ('/opt/local/myproject/etc', ['myproject/config/settings.py', 'myproject/config/other_settings.special']),
        ('/opt/local/myproject/etc', [os.path.join('myproject/config', 'cool.huh')]),
#
        ('/opt/local/myproject/etc', [os.path.join('myproject/config', 'other_settings.xml')]),
        ('/opt/local/myproject/data', [os.path.join('myproject/words', 'word_set.txt')]),
    ],

    install_requires=[ 'jsonschema',
        'logging', ],

     entry_points = {
        'console_scripts': [
            # Blah...
        ], },
)

python setup.py sdist为源发行版(没有尝试过二进制)运行。

在新的虚拟环境中,我有一个myproject-4.19.tar.gz文件,并且我使用

(venv) pip install ~/myproject-4.19.tar.gz
...

除了将所有内容都安装到我的虚拟环境中之外site-packages,这些特殊数据文件也都安装到/opt/local/myproject/data和中/opt/local/myproject/etc


16

include_package_data=True 为我工作。

如果你使用git,请记住,包括setuptools-gitinstall_requires。远没有拥有Manifest或包含所有路径package_data(在我的情况下,它是具有各种静态特性的django应用程序)那么无聊

(粘贴了我的评论,就像k3-rnc所说的那样,实际上是有帮助的)


7

更新:此答案是旧的,该信息不再有效。所有setup.py配置均应使用import setuptools。我在https://stackoverflow.com/a/49501350/64313中添加了更完整的答案


我通过切换到distutils解决了这个问题。似乎已弃用和/或破坏了分发。

from distutils.core import setup

setup(
   name='myapp',
   packages=['myapp'],
   package_data={
      'myapp': ['data/*.txt'],
   },
)

2
发行版并不被弃用,它正在取代 distutils。我不知道您为什么遇到问题,但这不是原因。
2011年

1
那是我从IRC收到的回复,那么我相信谁?如果您有使用分发的可行示例,那么我将不胜感激。
cmcginty 2011年

6
澄清:distribute旨在替换setuptools,两者均基于distutils构建。distutils本身最终将被一个新包替换,该新包在python2中称为“ distutils2”,在python3中称为“ packaging”
Kevin Horn

1
切换到distutils解决了我的问题,这include_package_data=True一点并没有得到兑现。因此,使用该设置,您只需要MANIFEST.in-无需在该package_data设置中复制文件列表。
Daniel Sokolowski

4

古老的问题,然而... python的软件包管理确实有很多不足之处。因此,我有在本地使用pip安装到指定目录的用例,很惊讶package_data和data_files路径都无法解决。我不希望再向仓库添加另一个文件,所以最终我利用了data_files和setup.py选项--install-data;。像这样的东西

pip install . --install-option="--install-data=$PWD/package" -t package  


3

我在几天中遇到了同样的问题,但是即使一切都变得混乱,这个线程也无法为我提供帮助。因此,我进行了研究,发现了以下解决方案:

基本上在这种情况下,您应该执行以下操作:

from setuptools import setup

setup(
   name='myapp',
   packages=['myapp'],
   package_dir={'myapp':'myapp'}, # the one line where all the magic happens
   package_data={
      'myapp': ['data/*.txt'],
   },
)

完整的其他stackoverflow答案在这里


尝试过此操作,但仍然没有任何内容被复制。
Gerrit

3

只需删除该行:

include_package_data=True,

从您的安装脚本中,它将正常工作。(刚刚通过最新的setuptools测试。)


太疯狂了,但它可与sdist和一起使用bdist_wheel,您是否检查了原因?
Szabolcs

1
我确实可以确认设置此设置时将sdist忽略package_data
桑德·斯特凡

到现在为止已经有几个月了,但是我似乎想起了在代码中四处摸索,迷路两次,对文档进行了极细的梳齿处理并获得了满意的结果。显然,各种示例脚本都包含此标志,并且不会引起任何麻烦。
伊恩

1

使用setup.cfg(setuptools≥30.3.0)

从setuptools 30.3.0(2016年12月8日发布)开始,您可以保持setup.py很小的规模并将配置移动到setup.cfg文件中。使用这种方法,您可以将包数据放在以下[options.package_data]部分中:

[options.package_data]
* = *.txt, *.rst
hello = *.msg

在这种情况下,您setup.py可以做到:

from setuptools import setup
setup()

有关更多信息,请参阅使用setup.cfg文件配置安装程序

一些关于setup.cfgPEP 518中pyproject.toml提议的弃用赞成的说法,但从2020年2月21日起这仍然是临时的。


这个答案忽略了提及MANIFEST文件,因此我认为它实际上不适用于sdists。仅带轮子。你应该提一下。
wim

@wim我对MANIFEST,sdist和wheel没有足够的了解。这对我有用pip install
Gerrit

这是因为pip install,对于足够现代的pip版本,将首先构建一个轮子,然后再安装它。对于许多用户而言,这种方法仍然会无声地无法包含包数据。有关详细信息,请参见接受的答案及其下的评论。使用a setup.cfg实际上只是写出OP setup.py在问题中已经做的事情的另一种方式(通过package_data在call中传递关键字参数setup),因此我认为这对于回答这个问题没有特别的帮助。它根本没有解决根本的问题。
维姆
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.