setuptools的麻烦——不包括包,包括数据文件

Posted

技术标签:

【中文标题】setuptools的麻烦——不包括包,包括数据文件【英文标题】:setuptools troubles -- excluding packages, including data files 【发布时间】:2012-01-23 07:51:27 【问题描述】:

我对 setuptools 还很陌生。我已经看到了一些类似的问题,这让我有点发疯了,我似乎遵循了我看到的建议,但 setuptools 仍然做了一些与我想要的不同的事情。

这是我的项目的结构:

.
..
package1/
    __init__.py
    abc.py
    ...
tests/
    __init__.py
    test_package1.py
LICENSE
README.md
RELEASE
setup.py

这是我的 setup.py 的内容:

#!/usr/bin/env python
import os
#from distutils.core import setup
from setuptools import setup, find_packages

setup(
    name='package1',
    version='1.1',
    test_suite="tests",
    packages=find_packages(exclude=['tests']),    
    include_package_data=True,
    package_data = 
        '': ['LICENSE', 'README.md5', 'RELEASE']
    ,   
)

另外,在我的清单文件中,我有:

include LICENSE
include RELEASE
include README.md

我使用以下方法构建 tar:

python setup.py sdist

我想:

    从源分发中排除 tests 目录; 在 site-packages 目录中拥有 LICENSE、README.md、RELEASE 文件,无论是在顶层还是在 package1 目录中(此时我都同意)。

相反,会发生以下情况:

    tests 目录仍保留在创建的 tar 存档中并安装到站点包中; 文件被复制到存档中,但不会安装到包的站点打包目录中。

我没有想法,谁能向我解释我做错了什么以及如何解决它?

【问题讨论】:

为什么python不爱我们...这是一个非常简单和常见的任务:忽略几个文件,并包含几个不常见的文件来打包。为什么这么难做? 【参考方案1】:

find_packages 使用fnmatchcase 进行排除过滤。您可以测试您的排除模式是否与包名称匹配,如下所示:

>>> from fnmatch import fnmatchcase
>>> fnmatchcase('my.package.name.tests', 'tests')
False

假设您项目中的所有测试都存在于以 tests 结尾的包名称或这些包的子包中,以下内容应该足以排除所有测试代码:

setup(
    name='package1',
    version='1.1',
    packages=find_packages(exclude=['tests', '*.tests', '*.tests.*']),    
)

要同时从源分发中排除 tests 文件夹,请将以下内容添加到 MANIFEST.in:

recursive-exclude tests *

【讨论】:

这是问题的最佳答案 我在find_packages() 的语法方面遇到了很多困难,我发现一个有用的技巧是在您的setup.py 所在文件夹的python 控制台中import setuptools;然后执行以下操作以查看它将列出哪些包以响应您选择的文件匹配模式:print(setuptools.find_packages(where='YourSourceFolder', exclude=['tests', 'tests.*'])) 如果所有测试都在一个子包中,即在主包目录下的子目录中,那么指定 packages=find_packages(exclude=['*.tests', '*.tests.*']), 显然就足够了,并且不需要 MANIFEST.in 文件条目。至少这是我在 Python 3.7 下的实验告诉我的。【参考方案2】:

您应该在包的根目录中创建一个名为 MANIFEST.in 的新文件,然后按照以下说明操作:

    要控制哪些文件最终出现在您的 tar 文件中,请在包的根级别创建一个名为 MANIFEST.in 的新文件。例如,您可以使用 MANIFEST.in 文件中的 recursive-exclude 从分发中排除整个目录。在您的情况下,您需要您的 MANIFEST.in 文件包含:

    recursive-exclude tests *
    

    在 site-packages 目录中包含 README 和其他文件并不常见,但如果您真的想要,请进入 package1 并创建指向您想要包含的文件的符号链接:

    cd package1
    ln -s ../LICENSE
    ln -s ../README.md
    ln -s ../RELEASE
    

    然后在 setup.py 中更改以下行:

    package_data = 
        '': ['LICENSE', 'README.md', 'RELEASE']
    

    到:

    package_data = 
        'package1': ['LICENSE', 'README.md', 'RELEASE']
    

【讨论】:

【参考方案3】:

我尝试了一切,但似乎没有任何效果,直到我删除了 build 目录(在看到 another answer mentioning *.egg-info/ directory 之后),它终于奏效了。 python setup.py clean --all 也应该能胜任。

【讨论】:

谢谢,这是我遇到问题的原因。 setup.py clean --all 没有为我工作并清理所有内容。【参考方案4】:

如果你的结构是真的:

    tests 文件夹不是包(它没有 init.py 文件),所以 find_package 不要排除它。 include_package_data=True 表示如果没有明确排除,所有版本控制的文件都将被包括在内。

所以:尝试在您的 MANIFEST.in 中排除测试/*

希望对你有所帮助

【讨论】:

我确实有 init.py 在测试中,实际上,只是没有在源代码中显示它。事实上,如果我打印 find_packages() 结果,它只返回 package1。但测试文件夹仍然包含在内。【参考方案5】:

MANIFEST.in 会处理它。

prune tests/
include LICENSE  README.md RELEASE

如果您有要添加的静态文件,请使用

添加它们
...
recursive-include package1/static *

【讨论】:

以上是关于setuptools的麻烦——不包括包,包括数据文件的主要内容,如果未能解决你的问题,请参考以下文章

virtualenv 不包括 pip

Python setuptools:包目录不存在

Javaitext根据模板生成pdf(包括图片和表格)

jQuery:如何找到第一个可见的输入/选择/文本区域,不包括按钮?

解决安装模块报错“ModuleNotFoundError: No module named 'setuptools'”

急!!IP数据报必须考虑最大传送单元MTU,这是指哪一层的最大传送单元?包括不包括首部或尾部等开销在内?