如何通过考虑 Python 版本来替代 tox 环境依赖项?

how to substitute tox environment dependencies with considering the Python version?

假设我们有两个 tox 环境集合 {py37,py38}-develop{py37,py38}-testdevelop 环境依赖包括相应的 test 环境依赖(为简单起见,未显示每个环境集合的额外依赖和配置):

[tox]
envlist = {py37,py38}-{test,develop}

[testenv:{py37,py38}-test]
deps = pytest
commands = pytest tests

[testenv:{py37,py38}-develop]
deps = {[testenv:py?-test]deps}  # How to describe python version here?

目前的解决方案是:

[tox]
envlist = {py37,py38}-{test,develop}

[testenv:{py37,py38}-test]
deps = pytest
commands = pytest tests

[testenv:{py37,py38}-develop]
deps = 
    py37: {[testenv:py37-test]deps}
    py38: {[testenv:py38-test]deps}

此外,我知道通过使用 {envname} 变量我们可以使用整个环境名称,但我无法提取 py* 部分以使用内部依赖变量替换。

如何在develop环境依赖部分中不重复地描述这个依赖?我也更喜欢 tox 配置本身是完整的,而不是强制用户在 运行 tox.

时传递额外的参数

也许是这样的:

[tox]
envlist = {py37,py38}-{test,develop}

[common]
deps =
  py37: CommonLib<2
  py38: CommonLib>=2

[testenv:{py37,py38}-test]
deps =
  {[common]deps}
  TestOnlyLib

[testenv:{py37,py38}-develop]
deps =
  {[common]deps}
  DevOnlyLib

借助@sinoroc 的回答,我发现因子条件是在实际执行环境(而不是包含它的环境)上评估的。

例如:

[tox]
envlist = {py37,py38}-{test,develop}

[testenv:{py37,py38}-test]
deps = 
    py37: dep1
    py38: dep2

[testenv:{py37,py38}-develop]
deps = {[testenv:py37-test]deps}  # The py37 here is not important.

独立于替换行中指定的 py* 因素成功运行。实际上,替换机制复制了整个 deps 变量,包括因子。因此,这些因素是根据实际 运行ning 环境(不是包含的环境)进行评估的。

最后,为了澄清develop环境中使用的py37因子的歧义,我在test环境中添加了pyauto因子(这不包含在envlist中,所以,用户不能运行它):

[tox]
envlist = {py37,py38}-{test,develop}

[testenv:{py37,py38,pyauto}-test]
deps = 
    py37: dep1
    py38: dep2

[testenv:{py37,py38}-develop]
deps = {[testenv:pyauto-test]deps}

解决方案与@sinoroc解决方案类似,但是:

  1. 它没有追加附加部分。
  2. 在很多依赖包含的情况下,它更简单,不需要很多使用common*命名模式的部分。

作为旁注,您还可以在 envlist 中包含 pyauto 因素,以允许用户直接 运行 pyauto-... 环境,这意味着它会自动选择 Python 版本。但是如果有任何因素条件如py38: ...,即使自动选择的Python版本是3.8,tox也会将其条件评估为false(实际上,tox考虑条件中的因素,不是 python 版本)。在这种情况下,您可以使用 PEP-508 dependency specification instead of factor conditions (that tox supports it).