包含setup.py的非Python文件

Ram*_*hum 172 python distutils

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

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

Han*_*s L 187

可能最好的方法是使用该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=[],
)
Run Code Online (Sandbox Code Playgroud)

请注意这里至关重要的具体行:

package_data={'': ['license.txt']},
include_package_data=True,
Run Code Online (Sandbox Code Playgroud)

package_data是一个dict包名称(空=所有包)到模式列表(可以包括globs).例如,如果您只想在包中指定文件,也可以这样做:

package_data={'yourpackage': ['*.txt', 'path/to/resources/*.txt']}
Run Code Online (Sandbox Code Playgroud)

这里的解决方案绝对不是py.py扩展名重命名您的非文件.

有关详细信息,请参阅Ian Bicking的演示文稿.

更新:另一个[更好]方法

如果您只想控制源分发(sdist)的内容并且包含在包之外的文件(例如顶级目录)的另一种方法是添加MANIFEST.in文件.有关此文件的格式,请参阅Python文档.

自编写此响应以来,我发现使用MANIFEST.in通常是一种不那么令人沮丧的方法来确保源分发(tar.gz)具有您需要的文件.

例如,如果要包含requirements.txt顶级,则递归地包含顶级"data"目录:

include requirements.txt
recursive-include data *
Run Code Online (Sandbox Code Playgroud)

但是,为了将这些文件在安装时复制到site-packages中的软件包文件夹,您需要提供include_package_data=True给该setup()函数.有关更多信息,请参阅添加非代码文件.

  • 这个答案看起来很合理,但对我不起作用.由于package_data是众所周知的不可靠(需要协调MANIFEST.in和setup.py以将文件添加到sdist并安装它们,作为单独的步骤)并且这个答案的作者注意到它"未经过测试",任何人都可以否则确认它是否适合他们?我的LICENSE文件包含在sdist中,但在运行"python setup.py install"或"pip install Package"时未安装 (9认同)
  • Ian Bicking的演示文稿仅显示如何为包中的文件安装包数据.我的LICENSE文件位于我的项目的顶层,即不在任何包中.我还可以使用package_data吗?使用data_files是一个非启动器,因为它将文件放在系统范围的位置.与我的项目无关,更糟糕的是,位置会根据我是否从同一个sdist运行"setup.py install"或"pip install"而改变. (8认同)
  • 我猜它不适合我的原因是文件不在任何包中 - 它是存储库顶层的LICENSE文件,因此不能使用'package_data'安装 (7认同)
  • 自Python 2.3以来,package_data也可用于纯distutils安装脚本. (5认同)
  • 这个答案对我不起作用.其他文件没有被放入tarball中...... (4认同)
  • 我已经看到,阅读并尝试了 package_data 并且它没有工作,直到我注意到这里的 include_package_data=True 。要求该设置似乎很愚蠢 - 如果不包含在内,为什么还有人指定 package_data ? (2认同)
  • 请注意,您的包含非Python文件的文件夹仍应带有`__init __。py`包标记。如果缺少该消息,则不会生成警告,也不会复制任何情报 (2认同)

Eva*_*ice 43

要完成你所描述的将采取两个步骤......

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

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

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

MANIFEST基本上是一个文本文件,其中包含将包含在源tarball中的所有文件的列表.

以下是我的项目的MANIFEST:

  • 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
Run Code Online (Sandbox Code Playgroud)

修改数据安装目录以匹配源安装目录:

for scheme in INSTALL_SCHEMES.values():
    scheme['data'] = scheme['purelib']
Run Code Online (Sandbox Code Playgroud)

并且,将数据文件和位置添加到setup():

data_files=[('', ['LICENSE.txt'])]
Run Code Online (Sandbox Code Playgroud)

注意:上述步骤应完全按标准方式完成,无需任何扩展库.

  • MANIFEST仅控制源tarball中包含的文件(由sdist生成).其中列出的文件将不会安装. (6认同)
  • 正如在其他线程中提到的那样,如果文件不在包中,则package_data`不起作用. (6认同)
  • @Éric有什么特别的理由吗?并且,你有一个可行的安装程序替代品,不需要第三方包(如setup_tools)工作.我在setuptools中选择了distutils,因为它包含在python的vanilla中,我正在为PYPI构建模块.现在使用distutils2应该有一个更好的方法来做到这一点,但是我已经有一段时间没有触及python,所以我不知道怎么做.既然你似乎对distutils2有所了解,我认为这将有利于我们其他人有一个适当的distutils2替代品. (3认同)
  • @ÉricAraujo:使用此解决方案不是一个坏主意,因为没有其他方法。这是一个糟糕的distutils设计-是的。但是事实上的公共API永远不会改变,因为它将破坏很多事情。我们希望distutils2将提供更好的推荐方法。 (2认同)

jsb*_*eno 22

现在是 2019 年,这是有效的 - 尽管到处都有建议,但我在互联网上发现的中途记录正在使用setuptools_scm,作为选项传递给setuptools.setup. 这将包括在您的 VCS 上进行版本控制的任何数据文件,无论是 git 还是任何其他文件,到轮包中,并将从 git 存储库进行“pip install”以带来这些文件。

所以,我只是将这两行添加到“setup.py”的设置调用中。无需额外安装或导入:

    setup_requires=['setuptools_scm'],
    include_package_data=True,
Run Code Online (Sandbox Code Playgroud)

无需手动列出 package_data,或在 MANIFEST.in 文件中 - 如果它是版本化的,则它包含在包中。“setuptools_scm”上的文档强调从提交位置创建版本号,而忽略了添加数据文件的真正重要部分。(如果我的中间轮文件被命名为“*0.2.2.dev45+g3495a1f”或者将使用我输入的硬编码版本号“0.3.0dev0”,我不在乎 - 但为程序留下关键文件后面的工作有点重要)


All*_*ітy 13

MANIFEST.in在项目根目录中创建recursive-include所需目录或include文件名.

include LICENSE
include README.rst
recursive-include package/static *
recursive-include package/templates *
Run Code Online (Sandbox Code Playgroud)

文档可以在这里找到


小智 11

步骤1:MANIFEST.in在与setup.py相同的文件夹中创建一个文件

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

include README.rst
include docs/*.txt
include funniest/data.json
Run Code Online (Sandbox Code Playgroud)

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

参考在这里。


Ale*_*itz 9

以上这些都不适合我。拯救我的是这个答案。
\n显然,为了在安装过程中提取这些数据文件,我必须做几件事:

\n
    \n
  1. 就像已经提到的 - 将 a 添加MANIFEST.in到项目并指定要包含的文件夹/文件。就我而言:recursive-include folder_with_extra_stuff *
  2. \n
  3. 再次,就像已经提到的 - 添加include_package_data=True到您的setup.py. *.py这很重要,因为没有它,只会带来匹配的文件。
  4. \n
  5. 这就是所缺少的!- 添加一个空的__init__.py数据文件夹。对我来说,我必须将此文件添加到我的folder-with-extra-stuff.
  6. \n
  7. 额外 - 不确定这是否是一个要求,但通过我自己的 python 模块,我看到它们被压缩在 .egg 文件中site-packages。所以我必须添加zip_safe=False到我的setup.py文件中。
  8. \n
\n

最终目录结构

\n
my-app/\n\xe2\x94\x9c\xe2\x94\x80 app/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 __init__.py\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 __main__.py\n\xe2\x94\x9c\xe2\x94\x80 folder-with-extra-stuff/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 __init__.py\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 data_file.json\n\xe2\x94\x9c\xe2\x94\x80 setup.py\n\xe2\x94\x9c\xe2\x94\x80 MANIFEST.in\n
Run Code Online (Sandbox Code Playgroud)\n

  • 你能用目录结构更新这个吗?这是一个很好的网站 https://ascii-tree-generator.com/ (2认同)

rv.*_*tch 8

我想对其中一个问题发表评论,但我没有足够的声誉来做到这一点 >.>

这是对我有用的(在参考文档后提出的):

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

include_package_data: False
Run Code Online (Sandbox Code Playgroud)

奇怪的是,最后一行对我来说也很重要(你也可以省略这个关键字参数——它的工作原理是一样的)。

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

希望这可以帮助!


Das*_*hes 5

在setup.py下设置(:

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


Dee*_*and 5

这在 2020 年有效!

正如其他人所说,在您的 setup.py 所在的位置创建“MANIFEST.in”。

清单中的下一步包括/排除所有必要的东西。这里要注意语法。例如:假设我们有模板文件夹要包含在源包中。

在清单文件中这样做:

recursive-include template *
Run Code Online (Sandbox Code Playgroud)

确保在 dir-name 和 pattern 之间为文件/目录留有空格,如上述。不要像我们在 .gitignore 中那样做

recursive-include template/* [this won't work]
Run Code Online (Sandbox Code Playgroud)

其他选项是使用包括。有很多选择。在此处查看他们的 Manifest.in 文档

最后一个重要的步骤,在你的 setup.py 中包含这个参数,你就可以开始了!

   setup(
    ...
    include_package_data=True,
    ......
)
Run Code Online (Sandbox Code Playgroud)

希望有帮助!快乐编码!