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

Cpp*_*ner 41 python

这就是我目前的做法:

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
      """,
      )
Run Code Online (Sandbox Code Playgroud)

这是好的方式吗?我有一些麻烦.例如,对于金字塔,我不能使用系统范围的nosetests插件来运行测试.我需要pyramid在全局python site-packages中安装!

但我不希望这样.所以我必须在这个项目的virtualenv中安装鼻子.但我不希望它成为一种依赖.我不觉得它应该属于requires.事实并非如此.然而,我也不想一直手工安装.是的我知道我有很多我不想这样做那......

但你怎么解决这个问题呢?我不想篡改全局python站点包,但我想安装nose作为virtualenv的一部分.

另外,pip安装需求文件.它稍微准确一点,因为我不需要手动指定版本,我不需要害怕手动更新setup.py.刚刚pip freeze > file.txt完成.

但是,pip可以返回垃圾,因为我们将垃圾包扔进了virtualenv.

这么多刀片.什么是最佳做法?你是如何处理这些问题的?

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

Tom*_*ann 61

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

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",
      ...
      )
Run Code Online (Sandbox Code Playgroud)

这样,当有人安装软件包时,只安装了"安装"依赖项.因此,如果有人只想使用该包(并且他们对运行测试不感兴趣),那么他们就不必安装测试依赖项.

当您想要运行测试时,可以使用:

$ python setup.py test
Run Code Online (Sandbox Code Playgroud)

根据文档:

请注意,这些必需的项目不会安装在运行测试的系统上,但只有在本地尚未安装的情况下才会下载到项目的安装目录中.

一旦"测试"依赖关系到位,它就会运行"test_suite"命令.既然你提到鼻子是你首选的测试跑步者,我展示了你如何使用"nose.collector"来配置它.

顺便说一下,Django setup.py并不是理解setuptools基础知识的最干净的例子.我认为Sentry setup.py是一个值得学习的更好的例子.

  • setuptools `tests_require` [自 41.5.0 起已弃用](https://setuptools.readthedocs.io/en/latest/setuptools.html)(2019 年 10 月)。我们现在的版本是 50.3.0。 (2认同)

Pet*_*r K 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,
      ...
      )
Run Code Online (Sandbox Code Playgroud)

我发现这种方法更加稳定并且不易出错,因为需求有时会发生变化并且人们经常忘记更新两个位置。

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

  • setuptools `tests_require` [自 41.5.0 起已弃用](https://setuptools.readthedocs.io/en/latest/setuptools.html)(2019 年 10 月)。我们现在的版本是 50.3.0。 (8认同)
  • Pytest 是最常见的选择。tox也是众所周知的。如果我看到 pytest.ini 或 tox.ini 我就会知道如何运行测试。 (2认同)