如何让setuptools忽略Subversion库存?

20

当使用setuptools的setup.py打包Python包时:

from setuptools import setup
...

由以下方式创建源代码分发:

python setup.py sdist

除了通常在MANIFEST.in中指定的文件外,还包括所有子版本控制目录下的被Subversion列为版本控制的文件。这非常烦人。这不仅使我难以对哪些文件与我的包一起分发进行明确控制,而且意味着当我使用"svn export" 而不是 "svn checkout"构建我的包时,由于缺少.svn元数据,setuptools将做出不同的选择,从而导致我的包内容可能非常不同。

我的问题是:我如何关闭这种可怕的行为,使得"setuptools"无论我使用Subversion还是没有听说过的版本控制方式,或者我在项目结束时创建的“svn export”裸树以确保它可以在工作目录之外干净地构建时,都以相同的方式处理我的项目?

到目前为止,我所做到最好的只是一个丑陋的猴子补丁:

from setuptools.command import sdist
del sdist.finders[:]

但这是Python,不是丛林,所以我当然希望有一个更好的解决方案,完全不涉及猴子。我该如何驯服setuptools,关闭其魔力,并通过查看MANIFEST.py中可见且可预测的规则使其表现得明智?


我认为我在这里遇到了完全相同的问题,只是针对.git和py2app:https://dev59.com/questions/CmHVa4cB1Zd3GeqPrOa9 - jdi
哇,看起来确实是同样的问题! - Brandon Rhodes
我在自己的问题下发布了一个猴子补丁hack作为答案。目前还没有找到更好的解决方案。 - jdi
6个回答

14

我知道你已经了解很多,Brandon,但我会尽可能给出一个完整的答案(虽然我不是setuptools方面的专家),以使其他人受益。

问题在于setuptools本身涉及相当多的黑魔法,包括使用名为setuptools.file_finders的入口点,在那里您可以添加插件以查找要包含的文件。但是,我完全不知道如何从中删除插件...

  • 快速解决方法:将您的软件包svn导出到临时目录中,并从那里运行setup.py。这意味着您没有svn,因此svn查找程序找不到要包含的文件。 :)

  • 更长的解决方法:您真的需要setuptools吗? Setuptools具有许多功能,因此答案很可能是肯定的,但主要是依赖项(因此您的依赖项会通过easy_install安装)、名称空间包(foo.bar)和入口点。名称空间包实际上也可以在没有setuptools的情况下创建。但是,如果您没有使用这些内容,您可能只需使用distutils就可以解决问题。

  • 丑陋的解决方法:您在问题中提供给sdist的猴子补丁,它只是使插件没有任何查找器并快速退出。

因此,正如您所看到的,尽管我已经尽力做到完整,但这个答案仍然非常不完整。实际上我无法回答你的问题,尽管我认为答案是“无法”。


9

这对我来说产生了一个错误。我不得不使用 recursive-exclude . * - Aryeh Leib Taurog

1

可能答案在你的 setup.py 文件中。你使用了 find_packages 吗?这个函数默认会使用版本控制系统(比如 subversion,hg,...)。如果你不喜欢它,只需编写一个不同的 Python 函数,只收集你想要的内容。


find_packages本身只使用listdir,并查找名为__init__.py的文件。 - Lennart Regebro

1

简单的解决方案是,不要使用setuptools来创建源代码分发包,而是降级到distutils命令:

from distutils.command.sdist import sdist
from setuptools import setup

setup(
    # ... all the usual setup arguments ...
    cmdclass = {'sdist': sdist},
)

我不知道类可以根据每个命令进行定制!感谢您指出这一点。 - Brandon Rhodes

0

我认为默认的sdist行为是正确的。当你构建一个源码分发时,我希望它包含所有在Subversion中检入的内容。当然,在特殊情况下,能够清晰地覆盖它会很好。

将sdist与bdist_egg进行比较;我敢打赌,只有明确指定的文件才会被包含。

我对三个文件进行了简单测试,这些文件都在svn中。空的dummy.lkj和foobar.py以及以下样子的setup.py:

import setuptools
setuptools.setup(name='foobar', version='0.1', py_modules=['foobar'])

sdist 会创建一个包含 dummy.lkj 的 tarball。而 bdist_egg 则会创建一个不包含 dummy.lkj 的 egg。


-1
你可能想要这样的东西:
from distutils.core import setup

def packages():
    import os

    packages = []

    for path, dirs, files in os.walk("yourprogram"):
        if ".svn" in dirs:
            dirs.remove(".svn")

        if "__init__.py" in files:
            packages.append(path.replace(os.sep, "."))

    return packages

setup(
    # name, version, description, etc...

    packages = packages(),

    # pacakge_data, data_files, etc...
)

1
+1:对于那些给帖子点踩的人,请解释一下为什么这个帖子无效。这种方法似乎非常有效。 - Mr Fooz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接