阻止 setup.py test / pytest 安装额外的依赖项

Prevent setup.py test / pytest from installing extra dependencies

在我的 CI 中,我有一个 build 步骤,它使用 pip 并使用私有索引等正确设置

然后我有 test 步骤,它执行 python setup.py test。 在这种特殊情况下 testpytest.

的别名

Setuptools 和 PIP 以不同方式解析包依赖性,这导致 test 步骤尝试重新安装某些包。我想阻止这种情况。有没有办法通过 Setuptools 配置(最好)或 PyTest 配置来做到这一点?

更新:

通过热门需求回购来举例说明我遇到的问题 https://github.com/vartec/example_repo_setuptools_issue

为什么不覆盖这样的测试命令:

from setuptools import setup
from setuptools.command.test import test


class CustomTest(test):
    def run(self):
        self.distribution.install_requires = []
        super().run()


setup(
    name = "test",
    version = "0.0.1",
    install_requires=['non-existing-package'],
    cmdclass={
        "test": CustomTest,
    },
)

因此,据我了解,问题是 setuptools 将内部依赖项安装到本地文件夹(.eggs 如果我没记错的话),而不是安装到您使用的普通 virtualenv 中。

而且您不喜欢 setuptools 的工作方式。我也不会,尤其是当我需要使用本地 DevPI 服务器时(setuptools 会忽略它)。所以我这样做:

setup(
    ...
    install_requires=['monotonic'],  # just for example
    extras_require={
        'test': ['pytest', 'pytest-timeout'],
        'docs': ['sphinx', 'alabaster'],
    },
)

当您需要测试时,假设您以某种方式创建并安装了 virtualenv:

pip install -e .[test]

这里,.是当前目录。 -e表示可编辑模式(但可以省略)。 [test] 是一个 setuptools "extra"。您可以声明多个 "extras",并在需要时将它们安装为 pip install mylib[ext1,ext2]

然后您可以 运行 两种方式进行测试:

pytest
python setup.py test

后一个仅在 test 命令已经配置为 运行 pytest(参见 pytest integration manual)时才会出现。

诀窍是,如果setuptools可以在当前环境中找到测试依赖(virtualenv,pyenv,系统python,等等),它不会像鸡蛋一样安装它们,并且只会使用已安​​装的版本。

实际上,在这种情况下您甚至不需要声明 tests_require=,因为假定库已安装到 virtualenv 中。如果不是,测试命令将失败。

同样,您可以 pip install .[docs],并使用当前 virtualenv 中的 sphinx-build ... 命令构建您的文档。

请注意 install_requires 始终会安装,无论您是否添加了附加功能。因此 app/lib 本身将始终具有完整的功能、可导入和自省。

希望这就是问题所在(如果我理解正确的话)。

您可以使用 requirements.txt 文件指定的依赖项不在 PyPI 中,而不是 setup.py.

setup 方法的 dependency_links 参数

requirements.txt:

-e git+ssh://git@github.com/gentcys/example_repo_setuptools_issue_submodule.git#egg=example_submodule-0.1.0

-e .[testing]

setup.py:

from setuptools import setup, find_packages

install_requires = [
    'redis~=2.10.0',
    'example_submodule',
]

tests_require = [
    'pytest',
]


setup(
    name='example_module',
    version='0.1.0',
    packages=find_packages(),
    install_requires=install_requires,
    tests_require=tests_require,
    setup_requires=['pytest-runner'],
    extras_require={
        'testing': tests_require,
    },
)

我分叉了你的示例回购并做了一些更改 https://github.com/gentcys/example_repo_setuptools_issue.git
我创建了一个子模块回购 https://github.com/gentcys/example_repo_setuptools_issue_submodule.git

setup.py 中的一个小修改专门适用于测试应该可以完成工作

import sys

import pkg_resources
from setuptools import setup, find_packages
from setuptools.dist import Distribution

install_requires = [
    'redis~=2.8.0',
    'example_submodule',
]

tests_require = [
    'pytest',
]

original_function = None

if sys.argv[1] == "test":
    working_set = pkg_resources.WorkingSet()
    new_reqs = set()
    for req in install_requires:
        try:
            sets = working_set.resolve(pkg_resources.parse_requirements(req))
        except Exception as ex:
            new_reqs.add(req)
    install_requires = new_reqs


setup(
    name='example_module',
    version='0.1.0',
    packages=find_packages(),
    install_requires=install_requires,
    tests_require=tests_require,
    setup_requires=['pytest-runner'],
    extras_require={
        'testing': tests_require,
    },
    dependency_links=[
        'git+ssh://git@github.com/vartec/example_repo_setuptools_issue_submodule.git#egg=example_submodule-0.1.0',
    ]
)

看看这是否确实是您要找的,如果不是,请提供您的反馈。

编辑-1

如果你真的不关心 test 情况下的 install_requires 那么你可以只做

if sys.argv[1] == "test":
   install_requires = []