如何使用setuptools/distribute包含包数据?

cmc*_*nty 115 python setuptools distribute

使用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'],
)
Run Code Online (Sandbox Code Playgroud)

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

lar*_*sks 249

我意识到这是一个老问题......但对于那些通过谷歌找到方法的人来说:这 package_data是一个低沉,肮脏的谎言.它构建时才使用二进制包(python setup.py bdist ...),但建立源代码包时(python setup.py sdist ...).当然,这是荒谬的 - 人们会期望构建源代码分发会导致可以发送给其他人构建二进制分发的文件集合.

在任何情况下,using MANIFEST.in可以用于二进制和源代码分发.

  • 过去一小时我一直在研究这个问题,并且一直在尝试很多方法.正如你所说,`package_data`适用于`bdist`而不适用于`sdist`.**但是**,`MANIFEST.in`适用于`sdist`,但*不适用于`bdist`!因此,我能够提出的最好的方法是包括`package_data`和`MANIFEST.in`以便同时容纳`bdist`和`sdist`. (89认同)
  • 说真的,我觉得这张票是一个团体治疗会议,供人们使用setuptools,发现他们在生活中发现了一个可怕的地方. (15认同)
  • 我正在使用sdist,并且必须包含`MANIFEST.in`*和*`package_data`.似乎`MANIFEST.in`控制分发中包含的内容,package_data控制随后在安装期间将哪些内容复制到site_packages目录中.令人困惑的是,`MANIFEST.in`中的路径相对于setup.py的位置,而`package_data`相对于各个包(例如模块)root. (11认同)
  • "在版本2.7中更改:如果未提供模板,则所有与package_data匹配的文件将添加到MANIFEST文件中.请参阅指定要分发的文件." [来自distutils](https://docs.python.org/2/distutils/setupscript.html#installing-package-data).因此,如果您没有现有的MANIFEST.in文件*,并且只有在使用2.7+时,您才会看到`package_data`中的文件行为自动包含在ZIP*中. (8认同)
  • 我发现了另一个支持@WesleyBaugh.在http://stackoverflow.com/a/2969087/261718中,对于您不会安装的文件(例如文档)使用`MANIFEST.in`,对于您使用的非Python代码的文件使用`package_data`(如图像)或模板). (7认同)
  • 今天进入这个.我知道他们可能不想改变行为,但它应该*至少*在文档中提到. (3认同)
  • 将`package_data`与`setuptools`一起使用是安全的:http://setuptools.readthedocs.io/en/latest/setuptools.html#including-data-files.文件有效地包含在二进制和源代码分发中,并且可以使用同一页面上描述的ResourceManager API方便地访问.另请参见/sf/answers/994812031/. (3认同)
  • 使用Python 3.6,如果我只运行“python setup.py install”,“package_data”仍然对我不起作用。添加“MANIFEST.in”解决了我的问题...... (2认同)
  • 我发现有时对 `MANIFEST.in` 的更改不会生效,除非我删除了 egg-info 文件夹。这些太该死的令人困惑! (2认同)

Joe*_*Joe 29

我刚才有同样的问题.解决方案,只是删除include_package_data=True.

这里阅读之后,我意识到include_package_data目的是包含来自版本控制的文件,而不是仅仅像名称所暗示的那样"包括数据包".来自文档:

[include_package_data]数据文件必须在CVS或Subversion控件下

...

如果您希望对包含的文件进行更精细的控制(例如,如果您的包目录中有文档文件并希望将它们从安装中排除),那么您也可以使用该package_data关键字.

把这个论点修正了,这恰巧是为什么当你切换到distutils时它也起作用,因为它没有采取这个论点.

  • 删除`include_package_data`可以解决问题的实际原因进一步在[原始文本](https://pythonhosted.org/setuptools/setuptools.html#include-data-files)中– *如果使用特定于setuptools的`include_package_data`参数,除非package_data`指定的文件在MANIFEST.in文件中列出,否则不会自动添加到清单中。* (4认同)
  • 我的经验不同,我有同样的问题,没有包括`include_package_data = True`条目.对我来说,唯一的解决方案是在Manifest中添加一个条目,如上所述.请注意,我使用的是setuptools,也许你的版本适用于'发布'? (2认同)

Hey*_*his 19

以下@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
Run Code Online (Sandbox Code Playgroud)

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...
        ], },
)
Run Code Online (Sandbox Code Playgroud)

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

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

(venv) pip install ~/myproject-4.19.tar.gz
...
Run Code Online (Sandbox Code Playgroud)

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


vin*_*ent 13

include_package_data=True 为我工作.

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

(粘贴我发表的评论,因为k3-rnc提到它实际上是有帮助的)


ger*_*rit 9

使用 setup.cfg (setuptools \xe2\x89\xa5 30.3.0)

\n\n

从 setuptools 30.3.0(2016-12-08 发布)开始,您可以保持setup.py非常小的配置并将配置移动到setup.cfg文件中。通过这种方法,您可以将包数据放在一个[options.package_data]部分中:

\n\n
[options.package_data]\n* = *.txt, *.rst\nhello = *.msg\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这种情况下,您的setup.py长度可以短至:

\n\n
[options.package_data]\n* = *.txt, *.rst\nhello = *.msg\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

有人讨论要setup.cfg弃用PEP 518pyproject.toml中的提议,但这截至 2020 年 2 月 21 日仍然是临时的。

\n


cmc*_*nty 7

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


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

from distutils.core import setup

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

  • 澄清:distribute旨在替换setuptools,两者均基于distutils构建。distutils本身最终将被一个新包替换,该新包在python2中称为“ distutils2”,在python3中称为“ packaging” (6认同)
  • 发行版不被弃用,它是_replacing_ distutils。我不知道您为什么遇到问题,但这不是原因。 (2认同)

小智 7

我在遇到同样的问题时发现了这篇文章。

\n

我的经验与其他答案中的经验相矛盾。\ninclude_package_data=True 确实包含\nbdist中的数据!setuptools\n文档中的解释\n缺乏上下文和疑难解答提示,但是\ninclude_package_data按宣传的那样工作。

\n

我的设置:

\n
    \n
  • 视窗/Cygwin
  • \n
  • git 版本 2.21.0
  • \n
  • Python 3.8.1 Windows 发行版
  • \n
  • setuptoolsv47.3.1
  • \n
  • check-manifestv0.42
  • \n
\n

这是我的操作指南。

\n

如何包含包数据

\n

以下是我在 PyPI 上发布的项目的文件结构。\n(它将应用程序安装在 中__main__.py)。

\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 LICENSE.md\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 MANIFEST.in\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 my_package\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __main__.py\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 _my_data          <---- folder with data\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 consola.ttf   <---- data file\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 icon.png      <---- data file\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 README.md\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 setup.py\n
Run Code Online (Sandbox Code Playgroud)\n

初始点

\n

setuptools.setup()这是in\n的通用起点setup.py

\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 LICENSE.md\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 MANIFEST.in\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 my_package\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __main__.py\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 _my_data          <---- folder with data\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 consola.ttf   <---- data file\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 icon.png      <---- data file\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 README.md\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 setup.py\n
Run Code Online (Sandbox Code Playgroud)\n

setuptools.find_packages()包括我在发行版中的所有软件包。我唯一的包裹是my_package.

\n

包含我的数据的子文件夹_my_data, 不被 Python 视为\n包,因为它不包含__init__.py,\n因此find_packages()找不到它。

\n

经常引用但不正确的解决方案是在文件夹中放置一个空__init__.py文件_my_data

\n

确实使其成为一个包,因此它确实_my_data在发行版中包含该文件夹。但里面的数据文件_my_data包括在内。

\n

所以做成_my_data一个包并没有什么帮助

\n

解决办法是:

\n
    \n
  • 已经sdist包含数据文件
  • \n
  • 添加include_package_data=True以将数据文件bdist也包含在
  • \n
\n

实验(如何测试解决方案)

\n

使其成为可重复的实验需要三个步骤:

\n
setuptools.setup(\n    ...\n    packages=setuptools.find_packages(),\n    ...\n)\n
Run Code Online (Sandbox Code Playgroud)\n

我将逐步分解这些:

\n
    \n
  1. 清理旧版本:
  2. \n
\n
$ rm -fr build/ dist/ my_package.egg-info/\n$ check-manifest\n$ python setup.py sdist bdist_wheel\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 运行check-manifest以确保MANIFEST.in 匹配\n版本控制下文件的 Git 索引:
  2. \n
\n
$ rm -fr build/ dist/ my_package.egg-info/\n
Run Code Online (Sandbox Code Playgroud)\n

如果MANIFEST.in尚不存在,请从版本控制下文件的 Git\n索引创建它:

\n
$ check-manifest\n
Run Code Online (Sandbox Code Playgroud)\n

这是MANIFEST.in创建的:

\n
include *.md\nrecursive-include my_package *.png\nrecursive-include my_package *.ttf\n
Run Code Online (Sandbox Code Playgroud)\n

没有理由手动编辑此文件。

\n

只要所有应该在版本控制之下的东西都在版本控制之下(即,是Git 索引的一部分check-manifest --create),\n就会做正确的事情。

\n

注意:文件不是Git 索引的一部分:

\n
    \n
  • 被忽略在.gitignore
  • \n
  • 排除在一个.git/info/exclude
  • \n
  • 或者只是尚未添加的新文件到索引的
  • \n
\n

如果有任何文件受版本控制\n但不应该受版本控制,check-manifest则会发出警告并\n指定建议从 Git 索引中删除哪些文件。

\n
    \n
  1. 建造:
  2. \n
\n
$ check-manifest --create\n
Run Code Online (Sandbox Code Playgroud)\n

现在检查sdist(源分布)和bdist_wheel\n(构建发行版)以查看它们是否包含数据文件。

\n

看看里面的内容sdist(下面仅显示相关行):

\n
$ tar --list -f dist/my_package-0.0.1a6.tar.gz\nmy_package-0.0.1a6/\n...\nmy_package-0.0.1a6/my_package/__init__.py\nmy_package-0.0.1a6/my_package/__main__.py\nmy_package-0.0.1a6/my_package/_my_data/\nmy_package-0.0.1a6/my_package/_my_data/consola.ttf <-- yay!\nmy_package-0.0.1a6/my_package/_my_data/icon.png    <-- yay!\n...\n
Run Code Online (Sandbox Code Playgroud)\n

因此sdist已经包含了数据文件,因为它们\n列在MANIFEST.in. 无需执行任何额外操作即可将\n数据文件包含在sdist.

\n

查看内容bdist(它是一个 .zip 文件,用 解析\n zipfile.ZipFile):

\n
include *.md\nrecursive-include my_package *.png\nrecursive-include my_package *.ttf\n
Run Code Online (Sandbox Code Playgroud)\n

注意:您需要创建自己的check-whl.py脚本来生成\n上面的输出。它只有三行:

\n
$ python setup.py sdist bdist_wheel\n
Run Code Online (Sandbox Code Playgroud)\n

正如预期的那样,bdist缺少数据文件。

\n

_my_data文件夹完全丢失。

\n

如果我创建一个怎么办_my_data/__init__.py?我重复实验,发现数据文件仍然不存在!包含\n_my_data/文件夹,但不包含\n数据文件!

\n

解决方案

\n

与其他人的经验相反,这确实有效:

\n
$ tar --list -f dist/my_package-0.0.1a6.tar.gz\nmy_package-0.0.1a6/\n...\nmy_package-0.0.1a6/my_package/__init__.py\nmy_package-0.0.1a6/my_package/__main__.py\nmy_package-0.0.1a6/my_package/_my_data/\nmy_package-0.0.1a6/my_package/_my_data/consola.ttf <-- yay!\nmy_package-0.0.1a6/my_package/_my_data/icon.png    <-- yay!\n...\n
Run Code Online (Sandbox Code Playgroud)\n

修复到位后,重做实验:

\n
$ python check-whl.py\nmy_package/__init__.py\nmy_package/__main__.py\nmy_package-0.0.1a6.dist-info/LICENSE.md\nmy_package-0.0.1a6.dist-info/METADATA\nmy_package-0.0.1a6.dist-info/WHEEL\nmy_package-0.0.1a6.dist-info/entry_points.txt\nmy_package-0.0.1a6.dist-info/top_level.txt\nmy_package-0.0.1a6.dist-info/RECORD\n
Run Code Online (Sandbox Code Playgroud)\n

确保sdist仍然有数据文件:

\n
from zipfile import ZipFile\npath = "dist/my_package-0.0.1a6-py3-none-any.whl" # <-- CHANGE\nprint(\'\\n\'.join(ZipFile(path).namelist()))\n
Run Code Online (Sandbox Code Playgroud)\n

看看下面的内容bdist

\n
setuptools.setup(\n    ...\n    packages=setuptools.find_packages(),\n    include_package_data=True, # <-- adds data files to bdist\n    ...\n)\n
Run Code Online (Sandbox Code Playgroud)\n

如何测试是否包含数据文件

\n

我建议使用上面概述的方法进行故障排除/测试来检查sdistbdist.

\n

可编辑模式下的 pip install 不是有效的测试

\n

注意:pip install -e . 显示数据文件是否包含在bdist.

\n

符号链接导致安装的行为就像包含数据文件一样(因为它们已经存在于开发人员的计算机本地)。

\n

之后pip install my_package,数据文件位于虚拟环境的lib/site-packages/my_package/文件夹中,\n使用与上面内容列表中显示的\n完全相同的文件结构whl

\n

发布到 TestPyPI 是一种缓慢的测试方法

\n

发布到 TestPyPI 然后安装并查看lib/site-packages/my_packages是一个有效的测试,但太耗时。

\n


moc*_*llo 6

几天来我遇到了同样的问题,但即使是这个线程也无法帮助我,因为一切都令人困惑。所以我做了我的研究并找到了以下解决方案:

基本上在这种情况下,你应该这样做:

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'],
   },
)
Run Code Online (Sandbox Code Playgroud)

完整的其他stackoverflow答案在这里