在setup.py中包含非Python文件


200

如何setup.py包含不属于代码的文件?(具体来说,这是一个许可证文件,但也可以是其他任何东西。)

我希望能够控制文件的位置。在原始源文件夹中,该文件位于包的根目录中。(即与最上层处于同一级别__init__.py。)我希望它在安装软件包时准确地保持在该位置,而与操作系统无关。我怎么做?


您目前如何处理?您先前的问题表明您熟悉如何添加许可证文件,那么“不起作用”的代码是什么?
SilentGhost

2
data_files = [('', ['lgpl2.1_license.txt',]),]将其放在Python26文件夹中。
Ram Rachum 09年

经过一些负面的反馈后,我再次阅读了您的问题,并意识到我所缺少的。我已更新我的答案,以为您的问题提供一种非骇客的解决方案,该解决方案不需要任何其他模块(例如setuptools或distribution)。
Evan Plaice 2010年

谢谢埃文。但是,我非常喜欢使用setuptools,因为它是如此普遍。
Ram Rachum 2010年

Answers:


224

可能最好的方法是使用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_datadict包名称(空=所有包)中的一组模式(可以包含glob)。例如,如果只想指定包中的文件,也可以这样做:

package_data={'yourpackage': ['*.txt', 'path/to/resources/*.txt']}

此处的解决方案绝对是py使用.py扩展名重命名非文件。

有关更多信息,请参见Ian Bicking的演示文稿

更新:另一种[更好]的方法

如果您只想控制源代码分发(sdist)的内容并使文件位于软件包外部(例如,顶级目录),则另一种有效的方法是添加MANIFEST.in文件。有关此文件的格式,请参见Python文档

自编写此回复以来,我发现使用MANIFEST.in通常是一种较为轻松的方法,只需确保您的源分发(tar.gz)具有所需的文件即可。

例如,如果您要包括requirements.txt来自顶层的目录,则递归包括顶层“数据”目录:

include requirements.txt
recursive-include data *

不过,为了在安装时将这些文件复制到site-packages内软件包的文件夹中,您需要提供include_package_data=Truesetup()功能。有关更多信息,请参见添加非代码文件


5
从Python 2.3开始,package_data也可用于纯distutils安装脚本。
埃里克·阿劳霍

15
这个答案看起来很明智,但对我不起作用。众所周知,package_data不可靠(需要MANIFEST.in和setup.py的配合才能将文件添加到sdist并安装它们,作为单独的步骤),并且此答案的作者指出它“未经测试”,任何人都可以否则确认它是否对他们有用?我的许可文件包括在sdist,但没有安装,当我运行“蟒蛇的setup.py安装”,也不是“PIP安装包”
乔纳森·哈特利

11
Ian Bicking的演示仅显示了如何为程序包中的文件安装程序包数据。我的许可文件位于我项目的顶层,即没有任何软件包。我仍然可以使用package_data吗?无需使用data_files,因为它将文件放置在系统范围内。与我的项目无关,更糟糕的是,位置会根据我从同一sdist运行“ setup.py install”还是“ pip install”而改变。
乔纳森·哈特利

8
我猜想它对我不起作用的原因是该文件不在任何软件包中-它是存储库顶层的LICENSE文件,因此无法使用'package_data'安装
Jonathan Hartley 2012年

7
这个答案对我不起作用。额外的文件不会放到压缩包中……
lpapp 2013年

44

要完成您要描述的内容,将需要两个步骤...

  • 该文件需要添加到源tarball中
  • 需要修改setup.py才能将数据文件安装到源路径

步骤1:要将文件添加到源tarball,请将其包括在MANIFEST中

在包含setup.py的文件夹中创建一个MANIFEST模板

清单基本上是一个文本文件,其中包含要在源tarball中包含的所有文件的列表。

这是我的项目清单如下所示:

  • CHANGELOG.txt
  • INSTALL.txt
  • LICENSE.txt
  • pypreprocessor.py
  • README.txt
  • setup.py
  • test.py
  • TODO.txt

注意:尽管sdist 确实会自动添加一些文件,但我更愿意明确指定它们以确保确定,而不是预测它会做什么和不做什么。

步骤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'])]

注意:上面的步骤应该完全按照您所描述的标准方式完成,而无需任何扩展库。


10
清单仅控制源tarball中包含的控制文件(由sdist生成)。此处列出的文件将不会安装。
David Cournapeau

@David我没有意识到我的第一种方法有多远。我已经更新了答案,使之正确无误,无需任何其他第三方库即可完成问题。
Evan Plaice 2010年

3
@Éric为什么有特定原因?并且,您是否有可行的安装程序替代方案,不需要第三方软件包(如setup_tools)即可工作。我选择distutils而不是setuptools,因为它包含在python的原始安装中,并且我正在为PYPI构建模块。现在应该有更好的方法使用distutils2来执行此操作,但是我已经有一段时间没有接触python了,所以我不知道如何操作。既然您似乎对distutils2有所了解,所以我认为拥有适当的distutils2替代方法会对我们其他人有益。
伊万·普赖斯

6
如前所述,package_data如果文件不在软件包中,其他线程将无法正常工作。
Gringo Suave

2
@ÉricAraujo:使用此解决方案不是一个坏主意,因为没有其他方法。这是一个糟糕的distutils设计-是的。但是事实上的公共API永远不会改变,因为它将破坏很多事情。我们希望distutils2将提供更好的推荐方法。
anatoly techtonik


7

我想对其中一个问题发表评论,但我的声誉不足以做到这一点>。>

这是对我有用的东西(在参考文档后进行介绍):

package_data={
    'mypkg': ['../*.txt']
},

include_package_data: False

奇怪的是,最后一行对我也很关键(您也可以忽略此关键字参数-原理相同)。

它的作用是将所有文本文件复制到顶级或根目录中(比mypkg您要分发的包高一级)。

希望这可以帮助!


我一直在寻找不必创建的方法MANIFEST.in,这对我来说很有用。最后一行对我来说也很关键。我的台词是include_package_data=False, package_data={ "": ["../CHANGELOG.md"] },
Mendhak

7

步骤1:MANIFEST.in使用setup.py在同一文件夹中创建文件

步骤2:包含要添加的文件的相对路径MANIFEST.in

include README.rst
include docs/*.txt
include funniest/data.json

第3步:设置include_package_data=Truesetup()功能将这些文件复制到站点包

参考在这里。


6

现在是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”,我就不会在意,但是将程序的关键文件留给后面的工作有些重要)


5

在setup.py下的setup(:

setup(
   name = 'foo library'
   ...
  package_data={
   'foolibrary.folderA': ['*'],     # All files from folder A
   'foolibrary.folderB': ['*.txt']  #All text files from folder B
   },

1
实际上,这对实现OP的目标没有任何帮助。除非您修改install命令本身,否则无论您写入package_data什么内容都不会对其产生影响setup.py install。除非这些文件位于程序包目录下,否则通常要避免这种情况。
wvxvw 18/12/6

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

1
它将抱怨目录pkgame不存在
Anthony Kong

1

我只是想跟进我发现在Centos 6上使用Python 2.7的工作。如上所述,添加package_data或data_files对我不起作用。我添加了MANIFEST.IN以及我想要的文件,该文件将非python文件放到了tarball中,但没有通过RPM将它们安装在目标计算机上。

最后,我可以使用setup / setuptools中的“选项”将文件放入解决方案中。选项文件使您可以从setup.py修改规范文件的各个部分。如下。

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

文件-filewithinstall命令:

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

-12

找出解决方法:将我重命名lgpl2.1_license.txtlgpl2.1_license.txt.py,并在文本周围加上了三引号。现在,我不需要使用该data_files选项,也无需指定任何绝对路径。我知道将其制作为Python模块很丑陋,但我认为它比指定绝对路径丑陋得多。


7
看我的帖子。它不必丑陋。在网上很难找到一个好的例子,因为很难找到安装程序包的良好文档。
Evan Plaice 2010年
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.