最佳实践:如何在setup.py中列出所需的依赖项?

60

这是我当前的做法:

import os
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))

requires = [
    'pyramid',
    'pyramid_debugtoolbar',
    'waitress',
    'requests',
    'mock',
    'gunicorn',
    'mongoengine',
    ]

setup(name='repoapi',
      version='0.0',
      description='repoapi',
      packages=find_packages(),
      include_package_data=True,
      zip_safe=False,
      install_requires=requires,
      tests_require=requires,
      test_suite="repoapi",
      entry_points="""\
      [paste.app_factory]
      main = repoapi:main
      """,
      )

这样可以吗?我遇到了一些问题。例如,对于金字塔(pyramid)框架,我无法使用系统范围内的nosetests插件运行测试。我需要在全局Python site-packages中安装pyramid

但我不想这样做。所以我必须在此项目的虚拟环境中安装nose。但我不希望它成为依赖项。我觉得它不应该属于requires。然而,我也不想每次都手动安装。是的,我知道我有很多不想这样做和那样做的想法......

但是,你怎么解决这个问题呢?我不想篡改全局Python site-packages,但我想将nose安装为虚拟环境的一部分。

另外,使用pip安装要求文件。这稍微更准确一些,因为我不需要手动指定版本,并且我不需要担心手动更新setup.py。只需输入pip freeze > file.txt即可完成。

然而,pip可能会返回垃圾,因为我们将垃圾包放入虚拟环境中。

这么多刀口向着你。什么是最佳实践?你如何处理这些问题?

也许我错过了,但是Django是如何做到的?https://github.com/django/django/blob/master/setup.py


3
自2019年10月起,setuptools中的tests_require已被弃用(41.5.0版本)。目前最新版本为50.3.0。 - Martin Thoma
2个回答

87
你可以将需求分为“安装”依赖项和“测试”依赖项,如下所示:

您可以将需求分为“安装”依赖项和“测试”依赖项,如下所示:

import os
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))

install_requires = [
    'pyramid',
    'pyramid_debugtoolbar',
    'waitress',
    'requests',
    'gunicorn',
    'mongoengine',
    ]

tests_require = [
    'mock',
    'nose',
    ]

setup(name='repoapi',
      ...
      install_requires=install_requires,
      tests_require=tests_require,
      test_suite="nose.collector",
      ...
      )

这种方式可以确保只安装“安装”依赖项,当有人安装包时。所以,如果有人只想使用包(并且不想运行测试),那么他们不必安装测试依赖。

当你想要运行测试时,可以使用以下命令:

$ python setup.py test
根据文档,这些必需的项目将不会安装在运行测试的系统上,但如果它们尚未在本地安装,则只会下载到项目的设置目录。
一旦“test”依赖关系就位,它将运行“test_suite”命令。由于您提到nose作为首选的测试运行器,因此我展示了如何使用“nose.collector”进行配置。
顺便说一下,Django的setup.py并不是理解setuptools基础知识的最佳示例。我认为Sentry setup.py是更好的学习示例。

谢谢分享。但是nose不是应该安装到virtualenv中吗?所以说,归根结底,最佳实践还是文档、错误票据来保持setup.py同步吗?谢谢。 - CppLearner
感谢您链接到“tests_require”的文档。在Python中管理依赖关系非常困难。我最初参考的文档中找不到该属性:https://packaging.python.org/guides/distributing-packages-using-setuptools - Dennis
如果我想安装测试依赖项,但现在不想运行测试怎么办?是否有python setup.py install --all选项? - Jake Stevens-Haas
3
自2019年10月起,setuptools tests_require 已经被废弃(deprecated),我们现在的版本是50.3.0。请注意更新。 - Martin Thoma

5
如果你正在使用需求文件,那么另一种选择是读取它们的内容而不是复制它们:
import pathlib
from setuptools import setup, find_packages

HERE = pathlib.Path(__file__).parent
INSTALL_REQUIRES = (HERE / "requirements.txt").read_text().splitlines()
TESTS_REQUIRE = (HERE / "test-requirements.txt").read_text().splitlines()[1:]

setup(...,
      install_requires=INSTALL_REQUIRES,
      tests_require=TESTS_REQUIRE,
      ...
      )

我认为这种方法更稳定,更不容易出错,因为有时需求会发生变化,而我们经常忘记更新两个地方。

注意:请注意TESTS_REQUIRE从第二行开始,这是因为test-requirements.txt的第一行通常是-r requirements.txt。如果你的情况不同,请随意更改它。


8
自2019年10月起,setuptools tests_require已被弃用(41.5.0版本)。目前我们使用的是50.3.0版本。 - Martin Thoma
1
@MartinThoma那我们应该使用什么替代方案呢?文档似乎没有提到。 - Alex Harvey
1
只需记录如何运行您的测试,例如在自述文件中。 - Martin Thoma
2
Pytest是最常见的选择。tox也相当知名。如果我看到pytest.ini或tox.ini,我就会知道如何运行测试。 - Martin Thoma

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