20

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

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 中可见的、可预测的规则来让它表现得明智?

4

6 回答 6

14

Brandon,我知道您对此了解很多,但为了他人的利益,我会尽力给出完整的答案(尽管我不是 setuptools 专家)。

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

  • 快速解决方法:svn 将你的包导出到一个临时目录并从那里运行 setup.py。这意味着你没有 svn,所以 svn finder 找不到要包含的文件。:)

  • 更长的解决方法:您真的需要 setuptools 吗?Setuptools 有很多特性,所以答案可能是肯定的,但主要是这些特性是依赖项(因此您的依赖项由 easy_install 安装)、命名空间包 (foo.bar) 和入口点。命名空间包实际上也可以在没有 setuptools 的情况下创建。但是如果你不使用这些,你实际上可能只使用 distutils。

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

如您所见,这个答案虽然尽我所能完成,但仍然令人尴尬地不完整。我实际上无法回答您的问题,尽管我认为答案是“您不能”。

于 2009-07-15T10:27:16.323 回答
9

创建一个 MANIFEST.in 文件:

recursive-exclude .
# other MANIFEST.in commands go here
# to explicitly include whatever files you want

有关 MANIFEST.in 语法,请参阅http://docs.python.org/distutils/commandref.html#sdist-cmd

于 2009-12-24T22:24:50.377 回答
1

答案可能在您的 setup.py 中。你使用 find_packages 吗?此函数默认使用 VCS(例如 subversion、hg、...)。如果你不喜欢它,只需编写一个不同的 Python 函数,它只收集你想要的东西。

于 2009-07-15T07:07:32.717 回答
1

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

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

setup(
    # ... all the usual setup arguments ...
    cmdclass = {'sdist': sdist},
)
于 2020-04-11T14:12:16.537 回答
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 的压缩包。bdist_egg 创建一个不包含 dummy.lkj 的鸡蛋。

于 2009-07-15T17:53:08.310 回答
-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...
)
于 2009-07-15T07:15:15.307 回答