如何使setup.py
包含不属于代码的文件? (具体来说,它是一个许可证文件,但它可能是任何其他东西。)
我希望能够控制文件的位置。在原始源文件夹中,该文件位于包的根目录中。 (即与最顶层的__init__.py
处于同一级别。)我希望它在安装软件包时保持准确,无论操作系统如何。我该怎么做?
答案 0 :(得分:166)
执行此操作的最佳方法可能是使用setuptools
package_data
指令。这意味着使用setuptools
(或distribute
)代替distutils
,但这是一个非常无缝的“升级”。
这是一个完整的(但未经测试的)示例:
from setuptools import setup, find_packages
setup(
name='your_project_name',
version='0.1',
description='A description.',
packages=find_packages(exclude=['ez_setup', 'tests', 'tests.*']),
package_data={'': ['license.txt']},
include_package_data=True,
install_requires=[],
)
请注意这里至关重要的具体行:
package_data={'': ['license.txt']},
include_package_data=True,
package_data
是一个dict
包名称(空=所有包)到模式列表(可以包括globs)。例如,如果您只想在包中指定文件,也可以这样做:
package_data={'yourpackage': ['*.txt', 'path/to/resources/*.txt']}
此处的解决方案肯定是不重命名带有py
扩展名的非.py
文件。
有关详细信息,请参阅Ian Bicking's presentation。
如果您只想控制源代码分发(sdist
)的内容并且包含在包之外的文件(例如顶级目录),那么另一种方法可以很好地添加MANIFEST.in
文件。有关此文件的格式,请参阅the Python documentation。
自编写此响应以来,我发现使用MANIFEST.in
通常是一种不那么令人沮丧的方法,只需确保您的源代码分发(tar.gz
)包含您需要的文件。
例如,如果您想要从顶层包含requirements.txt
,则递归地包含顶级“data”目录:
include requirements.txt
recursive-include data *
尽管如此,为了将这些文件在安装时复制到site-packages中的软件包文件夹,您需要向include_package_data=True
函数提供setup()
。有关详细信息,请参阅Adding Non-Code Files。
答案 1 :(得分:41)
要完成您所描述的内容,需要采取两个步骤......
步骤1:要将文件添加到源tarball,请将其包含在MANIFEST中
在包含setup.py
的文件夹中创建MANIFEST模板MANIFEST基本上是一个文本文件,其中包含将包含在源tarball中的所有文件的列表。
以下是我的项目的MANIFEST:
注意:在sdist does add some files automatically期间,我更愿意明确指定它们,而不是预测它的作用与否。
步骤2:要将数据文件安装到源文件夹,请修改setup.py
由于您要将数据文件(LICENSE.txt)添加到源安装文件夹,因此需要修改数据安装路径以匹配源安装路径。这是必要的,因为默认情况下,数据文件安装在与源文件不同的位置。
修改数据安装目录以匹配源安装目录...
使用以下命令从distutils中提取安装目录信息:
from distutils.command.install import INSTALL_SCHEMES
修改数据安装目录以匹配源安装目录:
for scheme in INSTALL_SCHEMES.values():
scheme['data'] = scheme['purelib']
然后,将数据文件和位置添加到setup():
data_files=[('', ['LICENSE.txt'])]
注意:上述步骤应完全按标准方式完成,无需任何扩展库。
答案 2 :(得分:10)
在项目根目录中使用MANIFEST.in
创建recursive-include
到所需目录,或者include
创建文件名。
include LICENSE
include README.rst
recursive-include package/static *
recursive-include package/templates *
答案 3 :(得分:5)
在setup(:
下)的setup.py中setup(
name = 'foo library'
...
package_data={
'foolibrary.folderA': ['*'], # All files from folder A
'foolibrary.folderB': ['*.txt'] #All text files from folder B
},
答案 4 :(得分:3)
这是一个对我有用的简单答案。
首先,根据上面的Python Dev评论,不需要setuptools:
package_data is also available to pure distutils setup scripts
since 2.3. – Éric Araujo
这很好,因为在你的包上加上setuptools要求意味着你也必须安装它。简而言之:
from distutils.core import setup
setup(
# ...snip...
packages = ['pkgname'],
package_data = {'pkgname': ['license.txt']},
)
答案 5 :(得分:3)
步骤1:使用setup.py在同一文件夹中创建一个MANIFEST.in
文件
第2步:在MANIFEST.in
include README.rst
include docs/*.txt
include funniest/data.json
第3步:在include_package_data=True
函数中设置setup()
,将这些文件复制到站点包中
答案 6 :(得分:2)
这将在2020年生效!
正如其他人所说,在setup.py所在的位置创建“ MANIFEST.in”。
清单中的下一步包括/排除所有必要的内容。这里要注意语法。 例如:假设我们的源文件包中包含模板文件夹。
在清单文件中执行以下操作:
recursive-include template *
请确保在目录名和模式之间留出上述文件/目录的空间。 不要像我们在.gitignore
中那样做recursive-include template/* [this won't work]
其他选项是使用include。有很多选择。 Look up here at their docs for Manifest.in
最后一个重要步骤,就是将这个参数包含在setup.py中,您就可以开始了!
setup(
...
include_package_data=True,
......
)
希望有帮助!祝您编码愉快!
答案 7 :(得分:2)
以上都不对我有用。救了我的是this的回答。
显然,为了在安装过程中提取这些数据文件,我必须做一些事情:
MANIFEST.in
并指定要包含的文件夹/文件。就我而言:recursive-include folder_with_extra_stuff *
include_package_data=True
添加到您的 setup.py
。这很关键,因为没有它,只会带来匹配 *.py
的文件。__init__.py
。对我来说,我必须将此文件添加到我的 folder-with-extra-stuff
。site-packages
中的 .egg 文件中。所以我不得不将 zip_safe=False
添加到我的 setup.py
文件中。最终目录结构
my-app/
├─ app/
│ ├─ __init__.py
│ ├─ __main__.py
├─ folder-with-extra-stuff/
│ ├─ __init__.py
│ ├─ data_file.json
├─ setup.py
├─ MANIFEST.in
答案 8 :(得分:1)
我只想跟进我发现在Centos 6上使用Python 2.7的内容。如上所述添加package_data或data_files对我不起作用。我添加了一个带有我想要的文件的MANIFEST.IN,它将非python文件放入tarball中,但没有通过RPM将它们安装在目标机器上。
最后,我能够使用setup / setuptools中的“options”将文件放入我的解决方案中。选项文件允许您从setup.py修改spec文件的各个部分。如下。
from setuptools import setup
setup(
name='theProjectName',
version='1',
packages=['thePackage'],
url='',
license='',
author='me',
author_email='me@email.com',
description='',
options={'bdist_rpm': {'install_script': 'filewithinstallcommands'}},
)
文件 - MANIFEST.in:
include license.txt
file - filewithinstallcommands:
mkdir -p $RPM_BUILD_ROOT/pathtoinstall/
#this line installs your python files
python setup.py install -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES
#install license.txt into /pathtoinstall folder
install -m 700 license.txt $RPM_BUILD_ROOT/pathtoinstall/
echo /pathtoinstall/license.txt >> INSTALLED_FILES
答案 9 :(得分:1)
我想对其中一个问题发表评论,但我没有足够的声誉来做到这一点。>
以下是对我有用的内容(请参阅文档后再进行研究):
package_data={
'mypkg': ['../*.txt']
},
include_package_data: False
奇怪的是,最后一行对我也很关键(您也可以省略此关键字参数-效果相同)。
这是将所有文本文件复制到顶层或根目录(要分发的软件包mypkg
的上一层)。
希望这会有所帮助!
答案 10 :(得分:1)
现在是2019,这是正在起作用的-
尽管到处都有建议,但我在互联网上发现的中途记录是使用setuptools_scm
,并作为选项传递给setuptools.setup
。这将包括在VCS上版本化的所有数据文件(无论是git还是其他版本)到wheel软件包,并将从git存储库进行“ pip install”以将这些文件带到一起。
因此,我仅将这两行添加到“ setup.py”的设置调用中。无需额外安装或导入:
setup_requires=['setuptools_scm'],
include_package_data=True,
无需手动列出package_data或在MANIFEST.in文件中-如果已对其进行版本控制,则它将包含在软件包中。关于“ setuptools_scm”的文档着重于从提交位置创建版本号,而忽略了添加数据文件的真正重要部分。 (如果我的中间滚轮文件名为“ * 0.2.2.dev45 + g3495a1f”,或者使用我输入的硬编码版本号“ 0.3.0dev0”,则我不太在意-但将程序的关键文件留给了我后面的工作有些重要)
答案 11 :(得分:1)
没有一个答案对我有用,因为我的文件位于软件包之外的顶层。我改用了一个自定义构建命令。
import os
import setuptools
from setuptools.command.build_py import build_py
from shutil import copyfile
HERE = os.path.abspath(os.path.dirname(__file__))
NAME = "thepackage"
class BuildCommand(build_py):
def run(self):
build_py.run(self)
if not self.dry_run:
target_dir = os.path.join(self.build_lib, NAME)
for fn in ["VERSION", "LICENSE.txt"]:
copyfile(os.path.join(HERE, fn), os.path.join(target_dir,fn))
setuptools.setup(
name=NAME,
cmdclass={"build_py": BuildCommand},
description=DESCRIPTION,
...
)
答案 12 :(得分:-14)
找出解决方法:我将lgpl2.1_license.txt
重命名为lgpl2.1_license.txt.py
,并在文本周围加上一些三重引号。现在我不需要使用data_files
选项也不需要指定任何绝对路径。我知道,使它成为一个Python模块是丑陋的,但我认为它不如指定绝对路径那么难看。