Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tox3: Support provision of tox 4 with the min_version option #2714

Merged
merged 3 commits into from Dec 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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')"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import os part is a leftover from debugging a d should have been removed. Sorry about that.

""",
},
)
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
hroncok marked this conversation as resolved.
Show resolved Hide resolved
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 = {}
{} = {}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if adding a new fixture that evaluates to this expression is worth it or not.

""".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