5

我最近开始使用 SetupTools 打包我的第一个项目,并且大部分都取得了成功。

不幸的是,我遇到了一个令人困惑的情况——我的项目依赖于一个在 PyPI 上不可用的单文件模块。我已经能够使用 dependency_links 选项轻松地将 setup.py 配置为依赖于该模块,并且一切正常……只要我使用 setup.py 安装它。如果我尝试使用 pip 安装项目 egg,尝试安装模块时会失败,假设它必须是预制的 egg 存档。相比之下,setup.py 检测到它是一个简单的源文件并从中生成一个鸡蛋。

我的目标是让我的项目在 PyPI 上可用,因此仅使用 pip 即可安装它很重要;所以我的问题是......我做错了什么吗?

我的理解是 setuptools 本质上是达到目的的一种手段,即 pip 和 PyPI,所以我觉得这两个工具的行为如此不同对我来说很奇怪。

setup.py 的相关部分和每个工具的输出如下:

setup(
    name='particle-fish',
    version='0.1.0',
    description='Python Boilerplate contains all the boilerplate you need to create a Python package.',
    long_description=readme + '\n\n' + history,
    author='Lachlan Pease',
    author_email='predatory.kangaroo@gmail.com',
    url='https://github.com/predakanga/particle-fish',
    packages=[
        'particle.plugins'
    ],
    include_package_data=True,
    install_requires=['particle', 'irccrypt', 'pycrypto'],
    dependency_links=['http://www.bjrn.se/code/irccrypt/irccrypt.py#egg=irccrypt-1.0'],
    license="BSD",
    zip_safe=False,
    keywords='particle-fish',
    classifiers=[
        'Development Status :: 2 - Pre-Alpha',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: BSD License',
        'Natural Language :: English',
        "Programming Language :: Python :: 2",
        'Programming Language :: Python :: 2.6',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
    ],
    test_suite='tests',
    tests_require=['pytest', 'mock', 'coverage', 'pytest-cov'],
    cmdclass = {'test': PyTest},
)

setup.py 安装的输出:

Installed /Users/lachlan/.virtualenvs/particle-fish/lib/python2.7/site-packages/particle_fish-0.1.0-py2.7.egg
Processing dependencies for particle-fish==0.1.0
Searching for irccrypt
Best match: irccrypt 1.0
Downloading http://www.bjrn.se/code/irccrypt/irccrypt.py#egg=irccrypt-1.0
Processing irccrypt.py
Writing /var/tmp/easy_install-svPfHF/setup.cfg
Running setup.py -q bdist_egg --dist-dir /var/tmp/easy_install-svPfHF/egg-dist-tmp-Xq3OCt
zip_safe flag not set; analyzing archive contents...
Adding irccrypt 1.0 to easy-install.pth file

pip 安装的输出:

Downloading/unpacking irccrypt (from particle-fish==0.1.0)
  Downloading irccrypt.py
  Cannot unpack file /private/var/tmp/pip-mCc6La-unpack/irccrypt.py (downloaded from /Users/lachlan/.virtualenvs/particle-staging/build/irccrypt, content-type: text/plain); cannot detect archive format
Cleaning up...
Cannot determine archive format of /Users/lachlan/.virtualenvs/particle-staging/build/irccrypt
4

1 回答 1

4

你的问题有两个部分:

  1. dependency_links处理指定的正确方法是什么setup
  2. 为什么没有得到一致的处理?

dependency_links处理指定的正确方法是什么setup

setuptools 文档对 menthod的dependency_links参数说明了这setup一点:

dependency_links
满足依赖项时要搜索的命名 URL 的字符串列表。setup_requires如果需要安装由或指定的软件包,将使用这些链接tests_require。它们还将被写入 egg 的元数据,以供 EasyInstall 等工具在安装.egg文件时使用。

现在,这很模糊。他们确实提到EasyInstall了,所以我们可以深入研究那里的源代码以确定它是如何处理dependency_links的。Setuptools 还记录了 egg 的内部结构,其中包括dependency-links.txt对应于dependency_links参数的文件setup。它让我们更深入地了解链接实际上应该是什么:

dependency_links使用关键字 to指定的依赖 URL 列表,每行一个 setup()这些可能是直接下载 URL,或包含直接下载链接的网页 URL, EasyInstall 将使用它们来查找依赖项,就像用户通过--find-links命令 行选项手动提供它们一样。请参阅 setuptools 手册和 EasyInstall 手册以获取有关指定此选项的更多信息,以及有关 EasyInstall 如何处理--find-linksURL 的信息。

(粗体强调我的)

这很有用,因为它指出了它们应该如何处理,以及它实际期望什么。这个描述比那个更有用dependency_links,因为它指定了“要搜索的 URL”的实际含义:直接下载链接或包含它们的索引。源代码证实了这一点,--find-links并且dependency_links 在构建 egg 时实际上是合并的,所以我们现在可以查看--find-linksEasyInstall 的参数以了解它的预期。

--find-links=URLS_OR_FILENAMES, -f URLS_OR_FILENAMES
扫描指定的“下载页面”或目录以获取指向 egg 或其他发行版的直接链接。

那里有更详细的信息,但总体思路是--find-links寻找包含未找到的包的鸡蛋或档案。因此,您的谜团的答案的第一部分是:dependency_links指向完整的包,而不是单独的未打包的模块。

这听起来像是 pip 如何处理您包含的链接,当您通读所有内容时,这很有意义。您可以通过查看 pip 的测试来确认这一点。pip 有两个使用dependency_links( 1 , 2 ) 的测试,这两个测试都假设它dependency_links指向一个 indexing page。这似乎符合 setuptools 的描述,其中dependency_links是“命名要搜索的 URL 的字符串列表”。


所以,既然我们知道 pip 正在根据规范处理这个问题,那就留下第二个问题:

为什么这与 setuptools 一起工作?

为了了解为什么这与 setuptools 一起工作,您需要了解 setuptools 如何确定依赖项并尝试下载/安装它们。该PackageIndex.download方法在任何外部 url 上调用,并且需要在本地下载包才能安装。此函数的文档字符串包含我们问题的答案:

如果它是带有明确#egg=name-version标记的 .py 文件的 URL(即,始终转义-的),则会在下载的文件旁边自动创建_一个琐碎的文件。setup.py

这就解释了为什么 setuptools 忽略了它不是一个发行版的事实,但是 pip 失败了。


TL;DR: dependency_links应该指向包含一个包或存档,而不是未打包的模块。Setuptools 意识到您的痛苦并帮助您解决问题,但这大多没有记录。如果许可证允许,请考虑重新打包模块并将其包含在您的包中。

于 2015-01-29T04:28:31.817 回答