如何使用 setuptools/distutils 包含包数据?
- 2025-01-09 08:47:00
- admin 原创
- 15
问题描述:
使用 setuptools 时,我无法让安装程序提取任何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/
数据文件的位置在哪里。
解决方案 1:
我知道这是一个老问题,但对于通过 Google 找到这里的人来说: package_data
这是一个卑鄙的肮脏谎言。它只在构建二进制包时使用(python setup.py bdist ...
),但在构建源包时不适用python setup.py sdist ...
( )。这当然是荒谬的——人们会认为构建源分发版会产生一组文件,这些文件可以发送给其他人来构建二进制分发版。
无论如何,使用对二进制和源分布都MANIFEST.in
有效。
解决方案 2:
我刚刚遇到了同样的问题。解决方案就是删除include_package_data=True
。
阅读此处后,我意识到其include_package_data
目的是包含来自版本控制的文件,而不是像名称所暗示的那样仅仅“包含包数据”。摘自文档:
[include_package_data] 的数据文件必须受 CVS 或 Subversion 控制
...
如果您想要对包含的文件进行更细粒度的控制(例如,如果您的包目录中有文档文件并想要将其从安装中排除),那么您也可以使用关键字
package_data
。
删除该参数可以修复此问题,这恰好就是为什么当您切换到 distutils 时它也能起作用,因为它不接受该参数。
解决方案 3:
按照@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
。
解决方案 4:
include_package_data=True
对我有用。
如果你使用 git,记得将其包含setuptools-git
在内。这比在 中包含所有路径install_requires
要轻松得多(在我的例子中,它是一个包含各种静态数据的 Django 应用程序)Manifest
`package_data`
(粘贴我发表的评论,正如k3-rnc所提到的,它实际上很有帮助)
解决方案 5:
使用 setup.cfg(setuptools ≥ 30.3.0)
从 setuptools 30.3.0(发布于 2016-12-08)开始,您可以保持setup.py
非常小的配置并将配置移动到setup.cfg
文件中。使用这种方法,您可以将包数据放在一个[options.package_data]
部分中:
[options.package_data]
* = *.txt, *.rst
hello = *.msg
在这种情况下,您setup.py
可以简短地写成:
from setuptools import setup
setup()
有关更多信息,请参阅使用 setup.cfg 文件配置设置。
有人讨论弃用setup.cfg
PEP 518中pyproject.toml
提出的建议,但截至 2020-02-21,这仍然是临时的。
解决方案 6:
当我遇到同样的问题时,我发现了这篇文章。
我的经验与其他答案中的经验
相矛盾。include_package_data=True
确实包括 bdist 中的数据!setuptools
文档中的解释
缺乏上下文和故障排除提示,但include_package_data
可以像广告中说的那样工作。
我的设置:
Windows / Cygwin
git 版本 2.21.0
Python 3.8.1 Windows 发行版
setuptools
v47.3.1check-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
在分发中
包含了文件夹
。但其中的数据文件_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
我将逐步分解这些内容:
清除旧构建:
$ rm -fr build/ dist/ my_package.egg-info/
运行
check-manifest
以确保与版本控制下的文件的 Git 索引MANIFEST.in
相匹配:
$ check-manifest
如果MANIFEST.in
尚不存在,则从版本控制下的文件的 Git 索引中创建它:
$ check-manifest --create
这是MANIFEST.in
创建的:
include *.md
recursive-include my_package *.png
recursive-include my_package *.ttf
没有理由手动编辑此文件。
只要所有应该受到版本控制的内容都受到版本控制(即,是Git 索引的
一部分check-manifest --create
),那就做对了。
注意:如果文件属于以下情况,则它们不属于 Git 索引:
被忽略
.gitignore
排除在外
.git/info/exclude
或者只是尚未添加到索引中的新文件
如果任何文件处于不应受到版本控制的版本控制之下,check-manifest
则会发出警告并指定建议从 Git 索引中删除哪些文件。
建造:
$ 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('
'.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
如何不测试是否包含数据文件
我建议使用上面概述的方法检查sdist
和进行故障排除/测试bdist
。
pip 在可编辑模式下安装不是有效的测试
注意:如果数据文件包含在内pip install -e .
则不bdist
显示。
符号链接使安装表现得好像数据文件被包含在内(因为它们已经存在于开发人员的计算机上)。
之后pip install my_package
,数据文件位于虚拟环境的lib/site-packages/my_package/
文件夹中,使用与上面内容列表中显示的完全相同的文件结构whl
。
发布到 TestPyPI 是一种缓慢的测试方式
发布到TestPyPI然后安装并查看lib/site-packages/my_packages
是一个有效的测试,但它太耗时了。
解决方案 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'],
},
)
解决方案 8:
几天来我遇到了同样的问题,但即使是这个帖子也无法帮助我,因为一切都令人困惑。所以我做了研究并找到了以下解决方案:
基本上在这种情况下你应该这样做:
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 答案在这里
解决方案 9:
这是一个古老的问题,然而……python 的包管理确实有很多不足之处。因此,我使用 pip 在本地安装到指定目录,但令我惊讶的是,package_data 和 data_files 路径都没有起作用。我并不想再向 repo 添加另一个文件,所以我最终利用了 data_files 和 setup.py 选项 --install-data;类似这样的操作
pip install . --install-option="--install-data=$PWD/package" -t package
解决方案 10:
与本帖中的其他人一样,我对这种持续时间长但仍然缺乏清晰度的结合感到有些惊讶,但对我来说最好的答案是使用check-manifest
@mike-gazes 的答案中的建议
因此,只需使用包中所需的asetup.cfg
和 no以及附加文本和 python 文件,对我有用的就是将其保存在 setup.cfg 中:setup.py
[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
解决方案 11:
将包含包数据的文件夹移到模块文件夹中解决了我的问题。
请参阅此问题:MANIFEST.in 在“python setup.py install”上被忽略 - 没有安装数据文件?
解决方案 12:
只需删除以下行:
include_package_data=True,
从您的安装脚本,它将正常工作。(刚刚使用最新的安装工具进行了测试。)
解决方案 13:
从Setuptools 62.3.0开始,您现在可以使用递归通配符( "**"
) 以递归方式包含 (子) 目录。这样,您就可以包含整个文件夹及其中的所有文件夹和文件。
例如,当使用pyproject.toml
文件时,您可以这样递归地包含两个文件夹:
[tool.setuptools.package-data]
"ema_workbench.examples.data" = ["**"]
"ema_workbench.examples.models" = ["**"]
但你也可以只包含文件夹及其所有子文件夹中的某些文件类型。如果你想包含所有 markdown ( .md
) 文件,例如:
[tool.setuptools.package-data]
"ema_workbench.examples.data" = ["**/*.md"]
使用setup.py
或时它也应该可以工作setup.cfg
。
有关详细信息,请参阅https://github.com/pypa/setuptools/pull/3309 。
解决方案 14:
对于类似这样的目录结构:
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
作品。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理必备:盘点2024年13款好用的项目管理软件