From 34b2d4be0ac101b6ad5b855c7e65c86a6c080ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 14 Dec 2022 17:28:29 +0100 Subject: [PATCH] Support provision of tox 4 with the min_version option Fixes https://github.com/tox-dev/tox/issues/2661 --- docs/changelog/2661.feature.rst | 1 + docs/config.rst | 6 +++ src/tox/config/__init__.py | 4 ++ tests/integration/test_provision_int.py | 33 ++++++++++++-- tests/unit/session/test_provision.py | 57 +++++++++++++++++-------- 5 files changed, 80 insertions(+), 21 deletions(-) create mode 100644 docs/changelog/2661.feature.rst diff --git a/docs/changelog/2661.feature.rst b/docs/changelog/2661.feature.rst new file mode 100644 index 000000000..15e287204 --- /dev/null +++ b/docs/changelog/2661.feature.rst @@ -0,0 +1 @@ +Support provision of tox 4 with the ``min_version`` option - by :user:`hroncok` diff --git a/docs/config.rst b/docs/config.rst index d3b28ff72..d71048cbb 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -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 diff --git a/src/tox/config/__init__.py b/src/tox/config/__init__.py index 75b9ab92f..fdf6e62c1 100644 --- a/src/tox/config/__init__.py +++ b/src/tox/config/__init__.py @@ -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) diff --git a/tests/integration/test_provision_int.py b/tests/integration/test_provision_int.py index f1763e494..ec6829785 100644 --- a/tests/integration/test_provision_int.py +++ b/tests/integration/test_provision_int.py @@ -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] @@ -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] @@ -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'", @@ -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] @@ -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] diff --git a/tests/unit/session/test_provision.py b/tests/unit/session/test_provision.py index 24f7b3d80..0ebaf8af9 100644 --- a/tests/unit/session/test_provision.py +++ b/tests/unit/session/test_provision.py @@ -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, ), ) @@ -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, ), ) @@ -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, ), ) @@ -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, ), ) @@ -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, ) }, @@ -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 [])) @@ -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, ) }, @@ -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, ), )