56

这就是我目前的做法:

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
      """,
      )

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

但我不想那样。所以我必须在这个项目的virtualenv中安装nose。但我不希望它成为依赖项。我觉得它不应该属于requires. 它不是。然而,我也不想一直手动安装。是的,我知道我有很多我不想做这个和那个...

但是你会怎么解决呢?我不想篡改全局 python 站点包,但我想将鼻子安装为 virtualenv 的一部分。

此外,pip install 要求文件。它稍微准确一点,因为我不需要手动指定版本,也不需要害怕手动更新 setup.py。扔就pip freeze > file.txt完成了。

但是,pip 可以返回垃圾,因为我们将垃圾包扔到 virtualenv 中。

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

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

4

2 回答 2

82

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

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.collector”来配置它。

顺便说一句,Django setup.py 并不是了解 setuptools 基础知识的最简洁示例。我认为Sentry setup.py是一个更好的学习示例。

于 2013-03-15T00:31:57.997 回答
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. 如果您的情况不同,请随时更改它。

于 2020-04-16T11:09:16.363 回答