Skip to content

Commit

Permalink
Support provision of tox 4 with the min_version option
Browse files Browse the repository at this point in the history
Fixes #2661
  • Loading branch information
hroncok committed Dec 14, 2022
1 parent 3b83cd4 commit 34b2d4b
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 21 deletions.
1 change: 1 addition & 0 deletions docs/changelog/2661.feature.rst
@@ -0,0 +1 @@
Support provision of tox 4 with the ``min_version`` option - by :user:`hroncok`
6 changes: 6 additions & 0 deletions docs/config.rst
Expand Up @@ -43,6 +43,12 @@ Global settings are defined under the ``tox`` section as:
When tox is invoked with the ``--no-provision`` flag,
the provision won't be attempted, tox will fail instead.

.. versionchanged:: 3.27.2

``min_version`` has the same meaning and usage as ``minversion``
to support a best effort provision of tox 4.


.. conf:: requires ^ LIST of PEP-508

.. versionadded:: 3.2.0
Expand Down
4 changes: 4 additions & 0 deletions src/tox/config/__init__.py
Expand Up @@ -1344,6 +1344,10 @@ def run(name, section, subs, config):
def handle_provision(self, config, reader):
config.requires = reader.getlist("requires")
config.minversion = reader.getstring("minversion", None)
# tox 4 prefers the min_version name of this option.
# We check is as well in case the config is intended for tox 4.
# This allows to make a *best effort* attempt to provision tox 4 from tox 3.
config.minversion = config.minversion or reader.getstring("min_version", None)
config.provision_tox_env = name = reader.getstring("provision_tox_env", ".tox")
min_version = "tox >= {}".format(config.minversion or Version(tox.__version__).public)
deps = self.ensure_requires_satisfied(config, config.requires, min_version)
Expand Down
33 changes: 29 additions & 4 deletions tests/integration/test_provision_int.py
Expand Up @@ -25,7 +25,7 @@ def test_provision_missing(initproj, cmd):
"tox.ini": """\
[tox]
skipsdist=True
minversion = 3.7.0
minversion = 3.7.0,<4
requires =
setuptools == 40.6.3
[testenv]
Expand Down Expand Up @@ -54,7 +54,7 @@ def test_provision_from_pyvenv(initproj, cmd, monkeypatch):
"tox.ini": """\
[tox]
skipsdist=True
minversion = 3.7.0
minversion = 3.7.0,<4
requires =
setuptools == 40.6.3
[testenv]
Expand All @@ -68,6 +68,31 @@ def test_provision_from_pyvenv(initproj, cmd, monkeypatch):
assert ".tox/.tox/bin/python -m virtualenv" in result.out


@pytest.mark.skipif(
"sys.version_info < (3, 7)",
reason="tox 4 only supports Python >= 3.7",
)
def test_provision_tox_4(initproj, cmd, monkeypatch):
initproj(
"pkg123-0.7",
filedefs={
"tox.ini": """\
[tox]
no_package=True
min_version = 4
[testenv]
commands=python -c "import os; print('assert this')"
""",
},
)
result = cmd("-e", "py", "-vvv")
# result.assert_success() has some assumptions about output that tox 4 doesn't follow
assert result.ret == 0, result.output()
assert "assert this" in result.out
# this exact line is only in tox 3:
assert " congratulations :)" not in result.out.splitlines()


@pytest.mark.skipif(INFO.IS_PYPY, reason="TODO: process numbers work differently on pypy")
@pytest.mark.skipif(
"sys.platform == 'win32'",
Expand All @@ -83,7 +108,7 @@ def test_provision_interrupt_child(initproj, monkeypatch, capfd, signal_type):
"tox.ini": """
[tox]
skipsdist=True
minversion = 3.7.0
minversion = 3.7.0,<4
requires = setuptools == 40.6.3
tox == 3.7.0
[testenv:b]
Expand Down Expand Up @@ -144,7 +169,7 @@ def test_provision_race(initproj, cmd, monkeypatch):
"tox.ini": """\
[tox]
skipsdist=True
minversion = 3.7.0
minversion = 3.7.0,<4
requires =
setuptools == 40.6.3
[testenv]
Expand Down
57 changes: 40 additions & 17 deletions tests/unit/session/test_provision.py
Expand Up @@ -27,14 +27,21 @@ def next_tox_major():
return "10.0.0"


def test_provision_min_version_is_requires(newconfig, next_tox_major):
@pytest.fixture(scope="session", params=["minversion", "min_version"])
def minversion_option(request):
"""both possible names for the minversion config option"""
return request.param


def test_provision_min_version_is_requires(newconfig, minversion_option, next_tox_major):
with pytest.raises(MissingRequirement) as context:
newconfig(
[],
"""\
[tox]
minversion = {}
{} = {}
""".format(
minversion_option,
next_tox_major,
),
)
Expand All @@ -49,17 +56,20 @@ def test_provision_min_version_is_requires(newconfig, next_tox_major):
assert config.ignore_basepython_conflict is False


def test_provision_config_has_minversion_and_requires(newconfig, next_tox_major):
def test_provision_config_has_minversion_and_requires(
newconfig, minversion_option, next_tox_major
):
with pytest.raises(MissingRequirement) as context:
newconfig(
[],
"""\
[tox]
minversion = {}
{} = {}
requires =
setuptools > 2
pip > 3
""".format(
minversion_option,
next_tox_major,
),
)
Expand Down Expand Up @@ -89,17 +99,18 @@ def test_provision_tox_change_name(newconfig):
assert config.provision_tox_env == "magic"


def test_provision_basepython_global_only(newconfig, next_tox_major):
def test_provision_basepython_global_only(newconfig, minversion_option, next_tox_major):
"""we don't want to inherit basepython from global"""
with pytest.raises(MissingRequirement) as context:
newconfig(
[],
"""\
[tox]
minversion = {}
{} = {}
[testenv]
basepython = what
""".format(
minversion_option,
next_tox_major,
),
)
Expand All @@ -108,17 +119,18 @@ def test_provision_basepython_global_only(newconfig, next_tox_major):
assert base_python == sys.executable


def test_provision_basepython_local(newconfig, next_tox_major):
def test_provision_basepython_local(newconfig, minversion_option, next_tox_major):
"""however adhere to basepython when explicitly set"""
with pytest.raises(MissingRequirement) as context:
newconfig(
[],
"""\
[tox]
minversion = {}
{} = {}
[testenv:.tox]
basepython = what
""".format(
minversion_option,
next_tox_major,
),
)
Expand Down Expand Up @@ -199,14 +211,17 @@ def test_provision_does_not_fail_with_no_provision_no_reason(cmd, initproj, json


@parametrize_json_path
def test_provision_fails_with_no_provision_next_tox(cmd, initproj, next_tox_major, json_path):
def test_provision_fails_with_no_provision_next_tox(
cmd, initproj, minversion_option, next_tox_major, json_path
):
p = initproj(
"test-0.1",
{
"tox.ini": """\
[tox]
minversion = {}
{} = {}
""".format(
minversion_option,
next_tox_major,
)
},
Expand Down Expand Up @@ -238,17 +253,21 @@ def test_provision_fails_with_no_provision_missing_requires(cmd, initproj, json_


@parametrize_json_path
def test_provision_does_not_fail_with_satisfied_requires(cmd, initproj, next_tox_major, json_path):
def test_provision_does_not_fail_with_satisfied_requires(
cmd, initproj, minversion_option, json_path
):
p = initproj(
"test-0.1",
{
"tox.ini": """\
[tox]
minversion = 0
{} = 0
requires =
setuptools > 2
pip > 3
"""
""".format(
minversion_option
)
},
)
result = cmd("--no-provision", *([json_path] if json_path else []))
Expand All @@ -257,17 +276,20 @@ def test_provision_does_not_fail_with_satisfied_requires(cmd, initproj, next_tox


@parametrize_json_path
def test_provision_fails_with_no_provision_combined(cmd, initproj, next_tox_major, json_path):
def test_provision_fails_with_no_provision_combined(
cmd, initproj, minversion_option, next_tox_major, json_path
):
p = initproj(
"test-0.1",
{
"tox.ini": """\
[tox]
minversion = {}
{} = {}
requires =
setuptools > 2
pip > 3
""".format(
minversion_option,
next_tox_major,
)
},
Expand Down Expand Up @@ -389,15 +411,16 @@ def space_path2url(path):
return urljoin("file:", pathname2url(os.path.abspath(at_path)))


def test_provision_does_not_occur_in_devenv(newconfig, next_tox_major):
def test_provision_does_not_occur_in_devenv(newconfig, minversion_option, next_tox_major):
"""Adding --devenv should not change the directory where provisioning occurs"""
with pytest.raises(MissingRequirement) as context:
newconfig(
["--devenv", "my_devenv"],
"""\
[tox]
minversion = {}
{} = {}
""".format(
minversion_option,
next_tox_major,
),
)
Expand Down

0 comments on commit 34b2d4b

Please sign in to comment.