diff --git a/src/virtualenv/run/__init__.py b/src/virtualenv/run/__init__.py index 48647ec7c..6d54eb1e7 100644 --- a/src/virtualenv/run/__init__.py +++ b/src/virtualenv/run/__init__.py @@ -48,6 +48,7 @@ def session_via_cli(args, options=None, setup_logging=True, env=None): # noqa: env = os.environ if env is None else env parser, elements = build_parser(args, options, setup_logging, env) options = parser.parse_args(args) + options.py_version = parser._interpreter.version_info # noqa: SLF001 creator, seeder, activators = tuple(e.create(options) for e in elements) # create types return Session( options.verbosity, diff --git a/src/virtualenv/seed/embed/base_embed.py b/src/virtualenv/seed/embed/base_embed.py index 6a02aef5b..72fc5a34a 100644 --- a/src/virtualenv/seed/embed/base_embed.py +++ b/src/virtualenv/seed/embed/base_embed.py @@ -1,13 +1,14 @@ from __future__ import annotations +import logging from abc import ABC from argparse import SUPPRESS from pathlib import Path -from warnings import warn from virtualenv.seed.seeder import Seeder from virtualenv.seed.wheels import Version +LOGGER = logging.getLogger(__name__) PERIODIC_UPDATE_ON_BY_DEFAULT = True @@ -20,24 +21,27 @@ def __init__(self, options) -> None: self.pip_version = options.pip self.setuptools_version = options.setuptools - if hasattr(options, "wheel"): - # Python 3.8 - self.wheel_version = options.wheel - self.no_wheel = options.no_wheel - elif options.no_wheel: - warn( - "The --no-wheel option is deprecated. " - "It has no effect for Python >= 3.8 as wheel is no longer " - "bundled in virtualenv.", - DeprecationWarning, - stacklevel=1, - ) + + # wheel version needs special handling + # on Python > 3.8, the default is None (as in not used) + # so we can differentiate between explicit and implicit none + self.wheel_version = options.wheel or "none" self.no_pip = options.no_pip self.no_setuptools = options.no_setuptools + self.no_wheel = options.no_wheel self.app_data = options.app_data self.periodic_update = not options.no_periodic_update + if options.py_version[:2] >= (3, 9): + if options.wheel is not None or options.no_wheel: + LOGGER.warning( + "The --no-wheel and --wheel options are deprecated. " + "They have no effect for Python > 3.8 as wheel is no longer " + "bundled in virtualenv.", + ) + self.no_wheel = True + if not self.distribution_to_versions(): self.enabled = False @@ -83,15 +87,17 @@ def add_parser_arguments(cls, parser, interpreter, app_data): # noqa: ARG003 default=[], ) for distribution, default in cls.distributions().items(): - if interpreter.version_info[:2] >= (3, 12) and distribution == "setuptools": + help_ = f"version of {distribution} to install as seed: embed, bundle, none or exact version" + if interpreter.version_info[:2] >= (3, 12) and distribution in {"wheel", "setuptools"}: default = "none" # noqa: PLW2901 if interpreter.version_info[:2] >= (3, 9) and distribution == "wheel": - continue + default = None # noqa: PLW2901 + help_ = SUPPRESS parser.add_argument( f"--{distribution}", dest=distribution, metavar="version", - help=f"version of {distribution} to install as seed: embed, bundle, none or exact version", + help=help_, default=default, ) for distribution in cls.distributions(): diff --git a/tests/unit/seed/embed/test_base_embed.py b/tests/unit/seed/embed/test_base_embed.py index 14a82165b..4f4fadac9 100644 --- a/tests/unit/seed/embed/test_base_embed.py +++ b/tests/unit/seed/embed/test_base_embed.py @@ -1,7 +1,6 @@ from __future__ import annotations import sys -import warnings from typing import TYPE_CHECKING import pytest @@ -21,17 +20,38 @@ def test_download_cli_flag(args, download, tmp_path): assert session.seeder.download is download -@pytest.mark.skipif(sys.version_info[:2] == (3, 8), reason="We still bundle wheels for Python 3.8") -def test_download_deprecated_cli_flag(tmp_path): - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - session_via_cli(["--no-wheel", str(tmp_path)]) - assert len(w) == 1 - assert issubclass(w[-1].category, DeprecationWarning) - assert str(w[-1].message) == ( - "The --no-wheel option is deprecated. It has no effect for Python >= " - "3.8 as wheel is no longer bundled in virtualenv." - ) +@pytest.mark.skipif(sys.version_info[:2] == (3, 8), reason="We still bundle wheel for Python 3.8") +@pytest.mark.parametrize("flag", ["--no-wheel", "--wheel=none", "--wheel=embed", "--wheel=bundle"]) +def test_wheel_cli_flags_do_nothing(tmp_path, flag): + session = session_via_cli([flag, str(tmp_path)]) + if sys.version_info[:2] >= (3, 12): + expected = {"pip": "bundle"} + else: + expected = {"pip": "bundle", "setuptools": "bundle"} + assert session.seeder.distribution_to_versions() == expected + + +@pytest.mark.skipif(sys.version_info[:2] == (3, 8), reason="We still bundle wheel for Python 3.8") +@pytest.mark.parametrize("flag", ["--no-wheel", "--wheel=none", "--wheel=embed", "--wheel=bundle"]) +def test_wheel_cli_flags_warn(tmp_path, flag, capsys): + session_via_cli([flag, str(tmp_path)]) + out, err = capsys.readouterr() + assert "The --no-wheel and --wheel options are deprecated." in out + err + + +@pytest.mark.skipif(sys.version_info[:2] == (3, 8), reason="We still bundle wheel for Python 3.8") +def test_unused_wheel_cli_flags_dont_warn(tmp_path, capsys): + session_via_cli([str(tmp_path)]) + out, err = capsys.readouterr() + assert "The --no-wheel and --wheel options are deprecated." not in out + err + + +@pytest.mark.skipif(sys.version_info[:2] != (3, 8), reason="We only bundle wheel for Python 3.8") +@pytest.mark.parametrize("flag", ["--no-wheel", "--wheel=none", "--wheel=embed", "--wheel=bundle"]) +def test_wheel_cli_flags_dont_warn_on_38(tmp_path, flag, capsys): + session_via_cli([flag, str(tmp_path)]) + out, err = capsys.readouterr() + assert "The --no-wheel and --wheel options are deprecated." not in out + err def test_embed_wheel_versions(tmp_path: Path) -> None: