【问题标题】:Prevent setup.py test / pytest from installing extra dependencies防止 setup.py test / pytest 安装额外的依赖项
【发布时间】:2018-03-29 11:47:44
【问题描述】:

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

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

Setuptools 和 PIP 以不同的方式解决包依赖关系,这导致 test 步骤尝试重新安装某些包。我想防止这种情况发生。有没有办法通过 Setuptools 配置(首选)或 PyTest 配置来做到这一点?

更新:

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

【问题讨论】:

  • 有什么令人信服的理由不只是运行pytest 命令目录而不是使用 setup.py?
  • @MrName 原因是python setup.py test 应该无论使用哪个特定的测试运行程序包都可以工作,无论是 vanilla unittest、pytest 还是像鼻子测试这样过时的东西。
  • 如果已经预装了pytest,setuptools会重新安装吗?我以为我有这个问题,通过将测试框架预装到virtualenv中解决了。
  • 你能提供一个我们可以使用的最小可重现示例 git repo 吗?
  • @TarunLalwani 完成

标签: python pytest setuptools


【解决方案1】:

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

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

【讨论】:

  • 这是一个有趣的解决方法。我仍然希望解决方案不那么老套,但如果没有其他办法,那可能
  • @vartec,不知道这比只做同样工作的两个班轮更好吗?我刚刚在我的答案上发布了编辑。如果你真的不关心install_requires 那么为什么要指定它们并自定义测试类然后忽略它们呢?当您在test运行的情况下可以在第一种情况下简单地忽略它们时
【解决方案2】:

所以,据我了解,问题在于 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"。您可以声明多个“附加”,并在需要时将它们安装为pip install mylib[ext1,ext2]

然后你可以用任何一种方式运行测试:

pytest
python setup.py test

仅当test 命令已配置为运行pytest 时(参见pytest integration manual)。

诀窍在于,如果setuptools 可以在当前环境(virtualenv、pyenv、system python 等)中找到测试依赖项,它不会将它们作为鸡蛋安装,而只会使用已安​​装的版本。

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

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

请注意,install_requires 始终安装,无论您添加了额外内容。因此,app/lib 本身将始终是功能齐全、可导入和可自省的。

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

【讨论】:

    【解决方案3】:

    您可以使用requirements.txt 文件指定的依赖项不在PyPI 中,而不是setup.pysetup 方法的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

    【讨论】:

      【解决方案4】:

      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',
          ]
      )
      

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

      Edit-1

      如果你真的不关心install_requirestest,那么你可以这样做

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

      【讨论】:

        猜你喜欢
        • 2015-01-10
        • 1970-01-01
        • 2022-01-15
        • 2012-03-25
        • 2019-02-07
        • 2020-09-23
        • 1970-01-01
        • 2014-11-03
        • 1970-01-01
        相关资源
        最近更新 更多