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

时间:2011-09-22 22:35:24

标签: 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'],
)

其中myapp/data/是数据文件的位置。

13 个答案:

答案 0 :(得分:234)

我意识到这是一个老问题......但是对于那些通过Google找到方法的人来说:package_data是一个低调的dirty lie。它仅在构建二进制包(python setup.py bdist ...)时使用,但在构建源包(python setup.py sdist ...)时。当然,这是荒谬的 - 人们会期望构建源代码分发会导致一组文件可以发送给其他人来构建二进制分发。

在任何情况下,使用MANIFEST.in对于二进制和源代码分发都将

答案 1 :(得分:25)

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

reading here之后,我意识到include_package_data的目的是包含来自版本控制的文件,而不是像名称所暗示的那样仅包含“包数据”。来自文档:

  

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

下      

...

     

如果您希望对包含的文件进行更精细的控制(例如,如果   您在包目录中有文档文件,并希望排除   它们来自安装),然后您还可以使用package_data关键字。

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

答案 2 :(得分:16)

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

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

Repository采用这种形式:

/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

答案 3 :(得分:11)

include_package_data=True为我工作。

如果你使用git,请记得在setuptools-git中加入install_requires。比Manifest或包含package_data中的所有路径(在我的情况下它是一个带有各种静力学的django应用程序)更为无聊

(粘贴我发表的评论,正如k3-rnc提到的那样,实际上是有帮助的)

答案 4 :(得分:5)

更新:此答案已过时且信息不再有效。所有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'],
   },
)

答案 5 :(得分:4)

古老的问题然而......蟒蛇的包管理真的还有很多不足之处。所以我有一个使用pip本地安装到指定目录的用例,并且很惊讶package_data和data_files路径都没有用。我并不热衷于在repo中添加另一个文件,所以我最终利用了data_files和setup.py选项--install-data;像这样的东西

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

答案 6 :(得分:3)

只需删除行:

include_package_data=True,

从您的安装脚本,它将正常工作。 (刚刚通过最新的设置工具进行了测试。)

答案 7 :(得分:2)

使用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()

有关更多信息,请参见configuring setup using setup.cfg files

some talk of deprecating setup.cfg中有PEP 518赞成pyproject.toml,但从2020年2月21日起这仍然是临时的。

答案 8 :(得分:2)

我发现这个帖子时遇到了同样的问题。

我的经验与其他答案中的经验相反。 include_package_data=True 是否将数据包括在 bdist! setuptools中的解释 documentation 缺少上下文和故障排除技巧,但是 include_package_data如广告所宣传。

我的设置:

  • Windows / Cygwin
  • git版本2.21.0
  • Python 3.8.1 Windows发行版
  • setuptools v47.3.1
  • check-manifest v0.42

这是我的操作指南。

如何包含包裹数据

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

├── LICENSE.md
├── MANIFEST.in
├── my_package
│   ├── __init__.py
│   ├── __main__.py
│   └── _my_data          <---- folder with data
│       ├── consola.ttf   <---- data file
│       └── icon.png      <---- data file
├── README.md
└── setup.py

起点

此处是setuptools.setup()中通用的起点 setup.py

setuptools.setup(
    ...
    packages=setuptools.find_packages(),
    ...
)

setuptools.find_packages()将我所有的软件包都包含在 分配。我唯一的包裹是my_package

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

一种经常被引用但又不正确的解决方案是将一个空白 __init__.py文件夹中的_my_data文件。

使其成为一个包,因此它包含文件夹 _my_data。但是里面的数据文件 {strong>不包含_my_data

因此将_my_data打包成一个包没有帮助

解决方案是:

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

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

可以通过三个步骤来进行可重复的实验:

$ rm -fr build/ dist/ my_package.egg-info/
$ check-manifest
$ python setup.py sdist bdist_wheel

我将逐步细分这些内容:

  1. 清理旧版本:
$ rm -fr build/ dist/ my_package.egg-info/
  1. 运行check-manifest,确保MANIFEST.in 相匹配 版本控制下文件的Git索引:
$ check-manifest

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

$ check-manifest --create

以下是创建的MANIFEST.in

include *.md
recursive-include my_package *.png
recursive-include my_package *.ttf

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

只要应该受版本控制的所有内容 在版本控制下(即是Git索引的 part ), check-manifest --create做正确的事。

注意:如果文件属于以下两种情况,则它们都不属于Git索引:

  • .gitignore中被忽略
  • 排除在.git/info/exclude
  • 或只是尚未将添加到索引中的 new 文件

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

  1. 内部版本:
$ python setup.py sdist bdist_wheel

现在检查sdist(源分发)和bdist_wheel (内部版本)以查看它们是否包含数据文件。

查看sdist的内容(只有相关行是 如下所示):

$ tar --list -f dist/my_package-0.0.1a6.tar.gz
my_package-0.0.1a6/
...
my_package-0.0.1a6/my_package/__init__.py
my_package-0.0.1a6/my_package/__main__.py
my_package-0.0.1a6/my_package/_my_data/
my_package-0.0.1a6/my_package/_my_data/consola.ttf <-- yay!
my_package-0.0.1a6/my_package/_my_data/icon.png    <-- yay!
...

因此sdist已包含数据文件,因为它们是 在MANIFEST.in中列出。没有其他可做的事情了 sdist中的数据文件。

查看bdist的内容(它是一个.zip文件,已解析 与zipfile.ZipFile):

$ python check-whl.py
my_package/__init__.py
my_package/__main__.py
my_package-0.0.1a6.dist-info/LICENSE.md
my_package-0.0.1a6.dist-info/METADATA
my_package-0.0.1a6.dist-info/WHEEL
my_package-0.0.1a6.dist-info/entry_points.txt
my_package-0.0.1a6.dist-info/top_level.txt
my_package-0.0.1a6.dist-info/RECORD

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

from zipfile import ZipFile
path = "dist/my_package-0.0.1a6-py3-none-any.whl" # <-- CHANGE
print('\n'.join(ZipFile(path).namelist()))

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

_my_data文件夹完全丢失。

如果我创建_my_data/__init__.py怎么办?我重复 实验之后,我发现数据文件仍然不存在! _my_data/文件夹已包含,但其中不包含数据 文件!

解决方案

与其他人的经历相反,这是的工作:

setuptools.setup(
    ...
    packages=setuptools.find_packages(),
    include_package_data=True, # <-- adds data files to bdist
    ...
)

修复后,重做实验:

$ rm -fr build/ dist/ my_package.egg-info/
$ check-manifest
$ python.exe setup.py sdist bdist_wheel

确保sdist仍具有数据文件:

$ tar --list -f dist/my_package-0.0.1a6.tar.gz
my_package-0.0.1a6/
...
my_package-0.0.1a6/my_package/__init__.py
my_package-0.0.1a6/my_package/__main__.py
my_package-0.0.1a6/my_package/_my_data/
my_package-0.0.1a6/my_package/_my_data/consola.ttf <-- yay!
my_package-0.0.1a6/my_package/_my_data/icon.png    <-- yay!
...

查看bdist的内容:

$ python check-whl.py
my_package/__init__.py
my_package/__main__.py
my_package/_my_data/consola.ttf        <--- yay!
my_package/_my_data/icon.png           <--- yay!
my_package-0.0.1a6.dist-info/LICENSE.md
my_package-0.0.1a6.dist-info/METADATA
my_package-0.0.1a6.dist-info/WHEEL
my_package-0.0.1a6.dist-info/entry_points.txt
my_package-0.0.1a6.dist-info/top_level.txt
my_package-0.0.1a6.dist-info/RECORD

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

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

以可编辑模式安装的pip不是有效的测试

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

符号链接使安装行为类似于 包含数据文件(因为它们已经存在于本地 开发人员的计算机)。

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

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

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

答案 9 :(得分:1)

将包含数据包数据的文件夹移到模块文件夹中解决了我的问题。

请参阅此问题:MANIFEST.in ignored on "python setup.py install" - no data files installed?

答案 10 :(得分:1)

这两天我遇到了同样的问题,但是即使这个线程对我来说也不清楚。一切都令人困惑。因此,我进行了研究并找到了解决方案。基本上在这种情况下,这就是您应该做的:

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'],
   },
)

The full other stackoverflow answer here

答案 11 :(得分:0)

对于像这样的目录结构:

foo/
├── foo
│   ├── __init__.py
│   ├── a.py
│   └── data.txt
└── setup.py

setup.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from setuptools import setup


NAME = 'foo'
DESCRIPTION = 'Test library to check how setuptools works'
URL = 'https://none.com'
EMAIL = 'gzorp@bzorp.com'
AUTHOR = 'KT'
REQUIRES_PYTHON = '>=3.6.0'

setup(
    name=NAME,
    version='0.0.0',
    description=DESCRIPTION,
    author=AUTHOR,
    author_email=EMAIL,
    python_requires=REQUIRES_PYTHON,
    url=URL,
    license='MIT',
    classifiers=[
        'Programming Language :: Python',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.6',
    ],
    packages=['foo'],
    package_data={'foo': ['data.txt']},
    include_package_data=True,
    install_requires=[],
    extras_require={},
    cmdclass={},
)

python setup.py bdist_wheel有效。

答案 12 :(得分:0)

像这个帖子中的其他人一样,我对长寿和仍然缺乏清晰度的组合感到有点惊讶,但对我来说最好的答案是使用 check-manifest 作为在@mike-gazes 的回答中推荐

因此,仅使用 setup.cfg 而没有 setup.py 以及包中所需的其他文本和 python 文件,对我有用的是将其保留在 setup.cfg 中:

[options]
packages = find:
include_package_data = true

并根据 MANIFEST.in 输出更新 check-manifest

include *.in
include *.txt
include *.yml
include LICENSE
include tox.ini
recursive-include mypkg *.py
recursive-include mypkg *.txt