Package: release.debian.org Severity: normal X-Debbugs-Cc: python-virtual...@packages.debian.org Control: affects -1 + src:python-virtualenv User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package python-virtualenv Sorry, I hadn't realized virtualenv was a key package. [ Reason ] This version includes the final upstream result of forwarding our no-wheel-whl patch. My initial approach (strong deprecation) caused some regressions in other people's CI, so it got watered down. [ Impact ] The previous version of virtualenv had a Debian patch that removed the --wheel and --no-wheel options. These are now silently ignored upstream, which will cause less downstream breakage. Being closer to upstream risks less confusion for our users. [ Tests ] Third parties have stopped complaining, so I think the current upstream versions of virtualenv are behaving as they expect. We have build time and autopkgtests. [ Risks ] (Discussion of the risks involved. E.g. code is trivial or complex, key package vs leaf package, alternatives available.) [ Checklist ] [x] all changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in testing unblock python-virtualenv/20.31.2+ds-1
diff -Nru python-virtualenv-20.30.0+ds/debian/changelog python-virtualenv-20.31.2+ds/debian/changelog --- python-virtualenv-20.30.0+ds/debian/changelog 2025-04-28 19:56:37.000000000 +0200 +++ python-virtualenv-20.31.2+ds/debian/changelog 2025-05-09 15:08:14.000000000 +0200 @@ -1,3 +1,15 @@ +python-virtualenv (20.31.2+ds-1) unstable; urgency=medium + + [ Stefano Rivera ] + * New upstream release. + * Refresh patches. + * Drop no-wheel-whl patch, superseded upstream. + + [ Alexandre Detiste ] + * Drop build-dep on python3-importlib-metadata + + -- Stefano Rivera <stefa...@debian.org> Fri, 09 May 2025 09:08:14 -0400 + python-virtualenv (20.30.0+ds-3) unstable; urgency=medium * Update no-wheel-whl patch to include a deprecated noop --no-wheel option. diff -Nru python-virtualenv-20.30.0+ds/debian/control python-virtualenv-20.31.2+ds/debian/control --- python-virtualenv-20.30.0+ds/debian/control 2025-04-28 19:56:37.000000000 +0200 +++ python-virtualenv-20.31.2+ds/debian/control 2025-05-09 15:08:14.000000000 +0200 @@ -15,7 +15,6 @@ zip <!nocheck>, Build-Depends-Indep: python3-distlib (>= 0.3.1) <!nocheck>, python3-filelock <!nocheck>, - python3-importlib-metadata (>= 3.6) <!nocheck>, python3-pip-whl <!nocheck>, python3-platformdirs <!nocheck>, python3-hatchling (>= 1.11.1), diff -Nru python-virtualenv-20.30.0+ds/debian/patches/debian_update_for_available_wheels.patch python-virtualenv-20.31.2+ds/debian/patches/debian_update_for_available_wheels.patch --- python-virtualenv-20.30.0+ds/debian/patches/debian_update_for_available_wheels.patch 2025-04-28 19:56:37.000000000 +0200 +++ python-virtualenv-20.31.2+ds/debian/patches/debian_update_for_available_wheels.patch 2025-05-09 15:08:14.000000000 +0200 @@ -13,10 +13,10 @@ 1 file changed, 21 insertions(+) diff --git a/src/virtualenv/seed/wheels/embed/__init__.py b/src/virtualenv/seed/wheels/embed/__init__.py -index 6c50bda..55362c7 100644 +index 5ca63de..6c8180d 100644 --- a/src/virtualenv/seed/wheels/embed/__init__.py +++ b/src/virtualenv/seed/wheels/embed/__init__.py -@@ -45,6 +45,27 @@ BUNDLE_SUPPORT = { +@@ -39,6 +39,27 @@ BUNDLE_SUPPORT = { MAX = "3.8" @@ -42,5 +42,5 @@ + + def get_embed_wheel(distribution, for_py_version): - path = BUNDLE_FOLDER / (BUNDLE_SUPPORT.get(for_py_version, {}) or BUNDLE_SUPPORT[MAX]).get(distribution) - return Wheel.from_path(path) + mapping = BUNDLE_SUPPORT.get(for_py_version, {}) or BUNDLE_SUPPORT[MAX] + wheel_file = mapping.get(distribution) diff -Nru python-virtualenv-20.30.0+ds/debian/patches/debian_wheel_location.patch python-virtualenv-20.31.2+ds/debian/patches/debian_wheel_location.patch --- python-virtualenv-20.30.0+ds/debian/patches/debian_wheel_location.patch 2025-04-28 19:56:37.000000000 +0200 +++ python-virtualenv-20.31.2+ds/debian/patches/debian_wheel_location.patch 2025-05-09 15:08:14.000000000 +0200 @@ -13,7 +13,7 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/virtualenv/seed/wheels/embed/__init__.py b/src/virtualenv/seed/wheels/embed/__init__.py -index 4727e61..6c50bda 100644 +index 6b3ef26..5ca63de 100644 --- a/src/virtualenv/seed/wheels/embed/__init__.py +++ b/src/virtualenv/seed/wheels/embed/__init__.py @@ -4,7 +4,7 @@ from pathlib import Path diff -Nru python-virtualenv-20.30.0+ds/debian/patches/disable-periodic-update.patch python-virtualenv-20.31.2+ds/debian/patches/disable-periodic-update.patch --- python-virtualenv-20.30.0+ds/debian/patches/disable-periodic-update.patch 2025-04-28 19:56:37.000000000 +0200 +++ python-virtualenv-20.31.2+ds/debian/patches/disable-periodic-update.patch 2025-05-09 15:08:14.000000000 +0200 @@ -11,13 +11,13 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/virtualenv/seed/embed/base_embed.py b/src/virtualenv/seed/embed/base_embed.py -index 864cc49..7d83cb6 100644 +index 72fc5a3..59f3f2c 100644 --- a/src/virtualenv/seed/embed/base_embed.py +++ b/src/virtualenv/seed/embed/base_embed.py -@@ -6,7 +6,7 @@ from pathlib import Path - from virtualenv.seed.seeder import Seeder +@@ -9,7 +9,7 @@ from virtualenv.seed.seeder import Seeder from virtualenv.seed.wheels import Version + LOGGER = logging.getLogger(__name__) -PERIODIC_UPDATE_ON_BY_DEFAULT = True +PERIODIC_UPDATE_ON_BY_DEFAULT = False diff -Nru python-virtualenv-20.30.0+ds/debian/patches/no-wheel-whl python-virtualenv-20.31.2+ds/debian/patches/no-wheel-whl --- python-virtualenv-20.30.0+ds/debian/patches/no-wheel-whl 2025-04-28 19:56:37.000000000 +0200 +++ python-virtualenv-20.31.2+ds/debian/patches/no-wheel-whl 1970-01-01 01:00:00.000000000 +0100 @@ -1,324 +0,0 @@ -From: Stefano Rivera <stef...@rivera.za.net> -Date: Thu, 10 Apr 2025 17:40:16 -0400 -Subject: Stop including 'wheel', - setuptools 70.1 has native bdist_wheel support - -Forwarded: https://github.com/pypa/virtualenv/pull/2868 -Bug-Upstream: https://github.com/pypa/virtualenv/issues/2873 ---- - src/virtualenv/seed/embed/base_embed.py | 23 ++++++++++++++++++---- - src/virtualenv/seed/wheels/embed/__init__.py | 7 ------- - tests/unit/config/test___main__.py | 4 ++-- - tests/unit/create/test_creator.py | 4 +--- - tests/unit/seed/embed/test_base_embed.py | 21 +++++++++++++++----- - .../seed/embed/test_bootstrap_link_via_app_data.py | 12 +++++------ - tests/unit/seed/embed/test_pip_invoke.py | 7 +++---- - tests/unit/seed/wheels/test_periodic_update.py | 5 +---- - 8 files changed, 48 insertions(+), 35 deletions(-) - -diff --git a/src/virtualenv/seed/embed/base_embed.py b/src/virtualenv/seed/embed/base_embed.py -index 7d83cb6..94e5ed4 100644 ---- a/src/virtualenv/seed/embed/base_embed.py -+++ b/src/virtualenv/seed/embed/base_embed.py -@@ -1,7 +1,9 @@ - from __future__ import annotations - - 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 -@@ -18,14 +20,21 @@ class BaseEmbed(Seeder, ABC): - - self.pip_version = options.pip - self.setuptools_version = options.setuptools -- self.wheel_version = options.wheel - - 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.no_wheel: -+ warn( -+ "The --no-wheel option is deprecated. " -+ "It has no effect, wheel is no longer bundled in virtualenv. " -+ "This option will be removed in pip 26.", -+ DeprecationWarning, -+ stacklevel=1, -+ ) -+ - if not self.distribution_to_versions(): - self.enabled = False - -@@ -34,7 +43,6 @@ class BaseEmbed(Seeder, ABC): - return { - "pip": Version.bundle, - "setuptools": Version.bundle, -- "wheel": Version.bundle, - } - - def distribution_to_versions(self) -> dict[str, str]: -@@ -71,7 +79,7 @@ class BaseEmbed(Seeder, ABC): - default=[], - ) - for distribution, default in cls.distributions().items(): -- if interpreter.version_info[:2] >= (3, 12) and distribution in {"wheel", "setuptools"}: -+ if interpreter.version_info[:2] >= (3, 12) and distribution == "setuptools": - default = "none" # noqa: PLW2901 - parser.add_argument( - f"--{distribution}", -@@ -88,6 +96,13 @@ class BaseEmbed(Seeder, ABC): - help=f"do not install {distribution}", - default=False, - ) -+ # DEPRECATED: Remove in pip 26 -+ parser.add_argument( -+ "--no-wheel", -+ dest="no_wheel", -+ action="store_true", -+ help=SUPPRESS, -+ ) - parser.add_argument( - "--no-periodic-update", - dest="no_periodic_update", -diff --git a/src/virtualenv/seed/wheels/embed/__init__.py b/src/virtualenv/seed/wheels/embed/__init__.py -index adc9216..2426081 100644 ---- a/src/virtualenv/seed/wheels/embed/__init__.py -+++ b/src/virtualenv/seed/wheels/embed/__init__.py -@@ -9,37 +9,30 @@ BUNDLE_SUPPORT = { - "3.8": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-75.3.2-py3-none-any.whl", -- "wheel": "wheel-0.45.1-py3-none-any.whl", - }, - "3.9": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", -- "wheel": "wheel-0.45.1-py3-none-any.whl", - }, - "3.10": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", -- "wheel": "wheel-0.45.1-py3-none-any.whl", - }, - "3.11": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", -- "wheel": "wheel-0.45.1-py3-none-any.whl", - }, - "3.12": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", -- "wheel": "wheel-0.45.1-py3-none-any.whl", - }, - "3.13": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", -- "wheel": "wheel-0.45.1-py3-none-any.whl", - }, - "3.14": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", -- "wheel": "wheel-0.45.1-py3-none-any.whl", - }, - } - MAX = "3.8" -diff --git a/tests/unit/config/test___main__.py b/tests/unit/config/test___main__.py -index fc6b3ee..b7c1850 100644 ---- a/tests/unit/config/test___main__.py -+++ b/tests/unit/config/test___main__.py -@@ -64,7 +64,7 @@ def test_fail_with_traceback(raise_on_session_done, tmp_path, capsys): - - @pytest.mark.usefixtures("session_app_data") - def test_session_report_full(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: -- run_with_catch([str(tmp_path), "--setuptools", "bundle", "--wheel", "bundle"]) -+ run_with_catch([str(tmp_path), "--setuptools", "bundle"]) - out, err = capsys.readouterr() - assert not err - lines = out.splitlines() -@@ -72,7 +72,7 @@ def test_session_report_full(tmp_path: Path, capsys: pytest.CaptureFixture[str]) - r"created virtual environment .* in \d+ms", - r" creator .*", - r" seeder .*", -- r" added seed packages: .*pip==.*, setuptools==.*, wheel==.*", -+ r" added seed packages: .*pip==.*, setuptools==.*", - r" activators .*", - ] - _match_regexes(lines, regexes) -diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py -index ed1cb11..2b4b1c0 100644 ---- a/tests/unit/create/test_creator.py -+++ b/tests/unit/create/test_creator.py -@@ -411,8 +411,6 @@ def test_create_distutils_cfg(creator, tmp_path, monkeypatch): - creator, - "--setuptools", - "bundle", -- "--wheel", -- "bundle", - ], - ) - -@@ -470,7 +468,7 @@ def list_files(path): - def test_zip_importer_can_import_setuptools(tmp_path): - """We're patching the loaders so might fail on r/o loaders, such as zipimporter on CPython<3.8""" - result = cli_run( -- [str(tmp_path / "venv"), "--activators", "", "--no-pip", "--no-wheel", "--copies", "--setuptools", "bundle"], -+ [str(tmp_path / "venv"), "--activators", "", "--no-pip", "--copies", "--setuptools", "bundle"], - ) - zip_path = tmp_path / "site-packages.zip" - with zipfile.ZipFile(str(zip_path), "w", zipfile.ZIP_DEFLATED) as zip_handler: -diff --git a/tests/unit/seed/embed/test_base_embed.py b/tests/unit/seed/embed/test_base_embed.py -index 255e031..73754a5 100644 ---- a/tests/unit/seed/embed/test_base_embed.py -+++ b/tests/unit/seed/embed/test_base_embed.py -@@ -1,6 +1,7 @@ - from __future__ import annotations - - import sys -+import warnings - from typing import TYPE_CHECKING - - import pytest -@@ -20,11 +21,21 @@ def test_download_cli_flag(args, download, tmp_path): - assert session.seeder.download is download - - -+# DEPRECATED: Remove in pip 26 -+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, wheel is no longer bundled in virtualenv. " -+ "This option will be removed in pip 26." -+ ) -+ -+ - def test_embed_wheel_versions(tmp_path: Path) -> None: - session = session_via_cli([str(tmp_path)]) -- expected = ( -- {"pip": "bundle"} -- if sys.version_info[:2] >= (3, 12) -- else {"pip": "bundle", "setuptools": "bundle", "wheel": "bundle"} -- ) -+ expected = {"pip": "bundle"} if sys.version_info[:2] >= (3, 12) else {"pip": "bundle", "setuptools": "bundle"} - assert session.seeder.distribution_to_versions() == expected -diff --git a/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py b/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py -index 2448d90..bfbb424 100644 ---- a/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py -+++ b/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py -@@ -110,7 +110,7 @@ def test_seed_link_via_app_data(tmp_path, coverage_env, current_fastest, copies) - # Windows does not allow removing a executable while running it, so when uninstalling pip we need to do it via - # python -m pip - remove_cmd = [str(result.creator.exe), "-m", "pip"] + remove_cmd[1:] -- process = Popen([*remove_cmd, "pip", "wheel"]) -+ process = Popen([*remove_cmd, "pip"]) - _, __ = process.communicate() - assert not process.returncode - # pip is greedy here, removing all packages removes the site-package too -@@ -208,13 +208,13 @@ def test_populated_read_only_cache_and_copied_app_data(tmp_path, current_fastest - - - @pytest.mark.slow --@pytest.mark.parametrize("pkg", ["pip", "setuptools", "wheel"]) -+@pytest.mark.parametrize("pkg", ["pip", "setuptools"]) - @pytest.mark.usefixtures("session_app_data", "current_fastest", "coverage_env") - def test_base_bootstrap_link_via_app_data_no(tmp_path, pkg): -- create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}", "--wheel", "bundle", "--setuptools", "bundle"] -+ create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}", "--setuptools", "bundle"] - result = cli_run(create_cmd) - assert not (result.creator.purelib / pkg).exists() -- for key in {"pip", "setuptools", "wheel"} - {pkg}: -+ for key in {"pip", "setuptools"} - {pkg}: - assert (result.creator.purelib / key).exists() - - -@@ -230,7 +230,7 @@ def test_app_data_parallel_fail(tmp_path: Path, mocker: MockerFixture) -> None: - exceptions = _run_parallel_threads(tmp_path) - assert len(exceptions) == 2 - for exception in exceptions: -- assert exception.startswith("failed to build image wheel because:\nTraceback") -+ assert exception.startswith("failed to build image pip because:\nTraceback") - assert "RuntimeError" in exception, exception - - -@@ -239,7 +239,7 @@ def _run_parallel_threads(tmp_path): - - def _run(name): - try: -- cli_run(["--seeder", "app-data", str(tmp_path / name), "--no-pip", "--no-setuptools", "--wheel", "bundle"]) -+ cli_run(["--seeder", "app-data", str(tmp_path / name), "--no-setuptools"]) - except Exception as exception: # noqa: BLE001 - as_str = str(exception) - exceptions.append(as_str) -diff --git a/tests/unit/seed/embed/test_pip_invoke.py b/tests/unit/seed/embed/test_pip_invoke.py -index d8c243e..97d4d33 100644 ---- a/tests/unit/seed/embed/test_pip_invoke.py -+++ b/tests/unit/seed/embed/test_pip_invoke.py -@@ -13,7 +13,7 @@ from virtualenv.seed.wheels.embed import BUNDLE_FOLDER, BUNDLE_SUPPORT - - - @pytest.mark.slow --@pytest.mark.parametrize("no", ["pip", "setuptools", "wheel", ""]) -+@pytest.mark.parametrize("no", ["pip", "setuptools", ""]) - def test_base_bootstrap_via_pip_invoke(tmp_path, coverage_env, mocker, current_fastest, no): # noqa: C901 - extra_search_dir = tmp_path / "extra" - extra_search_dir.mkdir() -@@ -49,7 +49,7 @@ def test_base_bootstrap_via_pip_invoke(tmp_path, coverage_env, mocker, current_f - - original = PipInvoke._execute # noqa: SLF001 - run = mocker.patch.object(PipInvoke, "_execute", side_effect=_execute) -- versions = {"pip": "embed", "setuptools": "bundle", "wheel": new["wheel"].split("-")[1]} -+ versions = {"pip": "embed", "setuptools": "bundle"} - - create_cmd = [ - "--seeder", -@@ -76,14 +76,13 @@ def test_base_bootstrap_via_pip_invoke(tmp_path, coverage_env, mocker, current_f - site_package = result.creator.purelib - pip = site_package / "pip" - setuptools = site_package / "setuptools" -- wheel = site_package / "wheel" - files_post_first_create = list(site_package.iterdir()) - - if no: - no_file = locals()[no] - assert no not in files_post_first_create - -- for key in ("pip", "setuptools", "wheel"): -+ for key in ("pip", "setuptools"): - if key == no: - continue - assert locals()[key] in files_post_first_create -diff --git a/tests/unit/seed/wheels/test_periodic_update.py b/tests/unit/seed/wheels/test_periodic_update.py -index 3b0529a..731252f 100644 ---- a/tests/unit/seed/wheels/test_periodic_update.py -+++ b/tests/unit/seed/wheels/test_periodic_update.py -@@ -74,7 +74,7 @@ def test_manual_upgrade(session_app_data, caplog, mocker, for_py_version): - packages[args[1]["distribution"]].append(args[1]["for_py_version"]) - packages = {key: sorted(value) for key, value in packages.items()} - versions = sorted(BUNDLE_SUPPORT.keys()) -- expected = {"setuptools": versions, "wheel": versions, "pip": versions} -+ expected = {"setuptools": versions, "pip": versions} - assert packages == expected - - -@@ -97,12 +97,9 @@ def test_pick_periodic_update(tmp_path, mocker, for_py_version): - "--activators", - "", - "--no-periodic-update", -- "--no-wheel", - "--no-pip", - "--setuptools", - "bundle", -- "--wheel", -- "bundle", - ], - ) - diff -Nru python-virtualenv-20.30.0+ds/debian/patches/series python-virtualenv-20.31.2+ds/debian/patches/series --- python-virtualenv-20.30.0+ds/debian/patches/series 2025-04-28 19:56:37.000000000 +0200 +++ python-virtualenv-20.31.2+ds/debian/patches/series 2025-05-09 15:08:14.000000000 +0200 @@ -2,4 +2,3 @@ debian_update_for_available_wheels.patch disable-periodic-update.patch wheel-package-error -no-wheel-whl diff -Nru python-virtualenv-20.30.0+ds/debian/patches/wheel-package-error python-virtualenv-20.31.2+ds/debian/patches/wheel-package-error --- python-virtualenv-20.30.0+ds/debian/patches/wheel-package-error 2025-04-28 19:56:37.000000000 +0200 +++ python-virtualenv-20.31.2+ds/debian/patches/wheel-package-error 2025-05-09 15:08:14.000000000 +0200 @@ -4,14 +4,14 @@ Forwarded: not-needed --- - src/virtualenv/seed/wheels/embed/__init__.py | 13 +++++++++++++ - 1 file changed, 13 insertions(+) + src/virtualenv/seed/wheels/embed/__init__.py | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) diff --git a/src/virtualenv/seed/wheels/embed/__init__.py b/src/virtualenv/seed/wheels/embed/__init__.py -index 55362c7..adc9216 100644 +index 6c8180d..6ed9727 100644 --- a/src/virtualenv/seed/wheels/embed/__init__.py +++ b/src/virtualenv/seed/wheels/embed/__init__.py -@@ -67,6 +67,19 @@ BUNDLE_SUPPORT = list_available_wheels(BUNDLE_SUPPORT.keys()) +@@ -61,6 +61,20 @@ BUNDLE_SUPPORT = list_available_wheels(BUNDLE_SUPPORT.keys()) def get_embed_wheel(distribution, for_py_version): @@ -27,7 +27,8 @@ + '2' if for_py_version == '2.7' else '3', + distribution, + )) ++ # End Debian specific + - path = BUNDLE_FOLDER / (BUNDLE_SUPPORT.get(for_py_version, {}) or BUNDLE_SUPPORT[MAX]).get(distribution) - return Wheel.from_path(path) - + mapping = BUNDLE_SUPPORT.get(for_py_version, {}) or BUNDLE_SUPPORT[MAX] + wheel_file = mapping.get(distribution) + if wheel_file is None: diff -Nru python-virtualenv-20.30.0+ds/PKG-INFO python-virtualenv-20.31.2+ds/PKG-INFO --- python-virtualenv-20.30.0+ds/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: virtualenv -Version: 20.30.0 +Version: 20.31.2 Summary: Virtual Python Environment builder Project-URL: Documentation, https://virtualenv.pypa.io Project-URL: Homepage, https://github.com/pypa/virtualenv diff -Nru python-virtualenv-20.30.0+ds/src/virtualenv/config/cli/parser.py python-virtualenv-20.31.2+ds/src/virtualenv/config/cli/parser.py --- python-virtualenv-20.30.0+ds/src/virtualenv/config/cli/parser.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/src/virtualenv/config/cli/parser.py 2020-02-02 01:00:00.000000000 +0100 @@ -107,8 +107,8 @@ class HelpFormatter(ArgumentDefaultsHelpFormatter): - def __init__(self, prog) -> None: - super().__init__(prog, max_help_position=32, width=240) + def __init__(self, prog, **kwargs) -> None: + super().__init__(prog, max_help_position=32, width=240, **kwargs) def _get_help_string(self, action): text = super()._get_help_string(action) diff -Nru python-virtualenv-20.30.0+ds/src/virtualenv/run/__init__.py python-virtualenv-20.31.2+ds/src/virtualenv/run/__init__.py --- python-virtualenv-20.30.0+ds/src/virtualenv/run/__init__.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/src/virtualenv/run/__init__.py 2020-02-02 01:00:00.000000000 +0100 @@ -48,6 +48,7 @@ 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 -Nru python-virtualenv-20.30.0+ds/src/virtualenv/seed/embed/base_embed.py python-virtualenv-20.31.2+ds/src/virtualenv/seed/embed/base_embed.py --- python-virtualenv-20.30.0+ds/src/virtualenv/seed/embed/base_embed.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/src/virtualenv/seed/embed/base_embed.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,11 +1,14 @@ from __future__ import annotations +import logging from abc import ABC +from argparse import SUPPRESS from pathlib import Path from virtualenv.seed.seeder import Seeder from virtualenv.seed.wheels import Version +LOGGER = logging.getLogger(__name__) PERIODIC_UPDATE_ON_BY_DEFAULT = True @@ -18,7 +21,11 @@ self.pip_version = options.pip self.setuptools_version = options.setuptools - self.wheel_version = options.wheel + + # 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 @@ -26,6 +33,15 @@ 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 @@ -41,7 +57,7 @@ return { distribution: getattr(self, f"{distribution}_version") for distribution in self.distributions() - if getattr(self, f"no_{distribution}") is False and getattr(self, f"{distribution}_version") != "none" + if getattr(self, f"no_{distribution}", None) is False and getattr(self, f"{distribution}_version") != "none" } @classmethod @@ -71,21 +87,28 @@ default=[], ) for distribution, default in cls.distributions().items(): + 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": + 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(): + help_ = f"do not install {distribution}" + if interpreter.version_info[:2] >= (3, 9) and distribution == "wheel": + help_ = SUPPRESS parser.add_argument( f"--no-{distribution}", dest=f"no_{distribution}", action="store_true", - help=f"do not install {distribution}", + help=help_, default=False, ) parser.add_argument( @@ -103,7 +126,7 @@ result += f"extra_search_dir={', '.join(str(i) for i in self.extra_search_dir)}," result += f"download={self.download}," for distribution in self.distributions(): - if getattr(self, f"no_{distribution}"): + if getattr(self, f"no_{distribution}", None): continue version = getattr(self, f"{distribution}_version", None) if version == "none": diff -Nru python-virtualenv-20.30.0+ds/src/virtualenv/seed/wheels/embed/__init__.py python-virtualenv-20.31.2+ds/src/virtualenv/seed/wheels/embed/__init__.py --- python-virtualenv-20.30.0+ds/src/virtualenv/seed/wheels/embed/__init__.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/src/virtualenv/seed/wheels/embed/__init__.py 2020-02-02 01:00:00.000000000 +0100 @@ -12,41 +12,39 @@ "wheel": "wheel-0.45.1-py3-none-any.whl", }, "3.9": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", - "wheel": "wheel-0.45.1-py3-none-any.whl", + "pip": "pip-25.1.1-py3-none-any.whl", + "setuptools": "setuptools-80.3.1-py3-none-any.whl", }, "3.10": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", - "wheel": "wheel-0.45.1-py3-none-any.whl", + "pip": "pip-25.1.1-py3-none-any.whl", + "setuptools": "setuptools-80.3.1-py3-none-any.whl", }, "3.11": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", - "wheel": "wheel-0.45.1-py3-none-any.whl", + "pip": "pip-25.1.1-py3-none-any.whl", + "setuptools": "setuptools-80.3.1-py3-none-any.whl", }, "3.12": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", - "wheel": "wheel-0.45.1-py3-none-any.whl", + "pip": "pip-25.1.1-py3-none-any.whl", + "setuptools": "setuptools-80.3.1-py3-none-any.whl", }, "3.13": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", - "wheel": "wheel-0.45.1-py3-none-any.whl", + "pip": "pip-25.1.1-py3-none-any.whl", + "setuptools": "setuptools-80.3.1-py3-none-any.whl", }, "3.14": { - "pip": "pip-25.0.1-py3-none-any.whl", - "setuptools": "setuptools-78.1.0-py3-none-any.whl", - "wheel": "wheel-0.45.1-py3-none-any.whl", + "pip": "pip-25.1.1-py3-none-any.whl", + "setuptools": "setuptools-80.3.1-py3-none-any.whl", }, } MAX = "3.8" def get_embed_wheel(distribution, for_py_version): - path = BUNDLE_FOLDER / (BUNDLE_SUPPORT.get(for_py_version, {}) or BUNDLE_SUPPORT[MAX]).get(distribution) + mapping = BUNDLE_SUPPORT.get(for_py_version, {}) or BUNDLE_SUPPORT[MAX] + wheel_file = mapping.get(distribution) + if wheel_file is None: + return None + path = BUNDLE_FOLDER / wheel_file return Wheel.from_path(path) diff -Nru python-virtualenv-20.30.0+ds/src/virtualenv/version.py python-virtualenv-20.31.2+ds/src/virtualenv/version.py --- python-virtualenv-20.30.0+ds/src/virtualenv/version.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/src/virtualenv/version.py 2020-02-02 01:00:00.000000000 +0100 @@ -17,5 +17,5 @@ __version_tuple__: VERSION_TUPLE version_tuple: VERSION_TUPLE -__version__ = version = '20.30.0' -__version_tuple__ = version_tuple = (20, 30, 0) +__version__ = version = '20.31.2' +__version_tuple__ = version_tuple = (20, 31, 2) diff -Nru python-virtualenv-20.30.0+ds/tasks/upgrade_wheels.py python-virtualenv-20.31.2+ds/tasks/upgrade_wheels.py --- python-virtualenv-20.30.0+ds/tasks/upgrade_wheels.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/tasks/upgrade_wheels.py 2020-02-02 01:00:00.000000000 +0100 @@ -38,7 +38,7 @@ ) -def run(): # noqa: C901 +def run(): # noqa: C901, PLR0912 old_batch = {i.name for i in DEST.iterdir() if i.suffix == ".whl"} with TemporaryDirectory() as temp: temp_path = Path(temp) @@ -50,6 +50,8 @@ into.mkdir() folders[into] = support_ver for package in BUNDLED: + if package == "wheel" and support >= (3, 9): + continue thread = Thread(target=download, args=(support_ver, str(into), package)) targets.append(thread) thread.start() @@ -90,8 +92,10 @@ if (folder / package).exists(): support_table[version].append(package) support_table = {k: OrderedDict((i.split("-")[0], i) for i in v) for k, v in support_table.items()} - bundle = ",".join( - f"{v!r}: {{ {','.join(f'{p!r}: {f!r}' for p, f in line.items())} }}" for v, line in support_table.items() + nl = "\n" + bundle = "".join( + f"\n {v!r}: {{{nl}{''.join(f' {p!r}: {f!r},{nl}' for p, f in line.items())} }}," + for v, line in support_table.items() ) msg = dedent( f""" diff -Nru python-virtualenv-20.30.0+ds/tests/unit/config/test___main__.py python-virtualenv-20.31.2+ds/tests/unit/config/test___main__.py --- python-virtualenv-20.30.0+ds/tests/unit/config/test___main__.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/tests/unit/config/test___main__.py 2020-02-02 01:00:00.000000000 +0100 @@ -64,7 +64,7 @@ @pytest.mark.usefixtures("session_app_data") def test_session_report_full(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: - run_with_catch([str(tmp_path), "--setuptools", "bundle", "--wheel", "bundle"]) + run_with_catch([str(tmp_path), "--setuptools", "bundle"]) out, err = capsys.readouterr() assert not err lines = out.splitlines() @@ -72,7 +72,7 @@ r"created virtual environment .* in \d+ms", r" creator .*", r" seeder .*", - r" added seed packages: .*pip==.*, setuptools==.*, wheel==.*", + r" added seed packages: .*pip==.*, setuptools==.*", r" activators .*", ] _match_regexes(lines, regexes) diff -Nru python-virtualenv-20.30.0+ds/tests/unit/create/test_creator.py python-virtualenv-20.31.2+ds/tests/unit/create/test_creator.py --- python-virtualenv-20.30.0+ds/tests/unit/create/test_creator.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/tests/unit/create/test_creator.py 2020-02-02 01:00:00.000000000 +0100 @@ -411,8 +411,6 @@ creator, "--setuptools", "bundle", - "--wheel", - "bundle", ], ) diff -Nru python-virtualenv-20.30.0+ds/tests/unit/seed/embed/test_base_embed.py python-virtualenv-20.31.2+ds/tests/unit/seed/embed/test_base_embed.py --- python-virtualenv-20.30.0+ds/tests/unit/seed/embed/test_base_embed.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/tests/unit/seed/embed/test_base_embed.py 2020-02-02 01:00:00.000000000 +0100 @@ -20,11 +20,46 @@ assert session.seeder.download is download +@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: session = session_via_cli([str(tmp_path)]) - expected = ( - {"pip": "bundle"} - if sys.version_info[:2] >= (3, 12) - else {"pip": "bundle", "setuptools": "bundle", "wheel": "bundle"} - ) + if sys.version_info[:2] >= (3, 12): + expected = {"pip": "bundle"} + elif sys.version_info[:2] >= (3, 9): + expected = {"pip": "bundle", "setuptools": "bundle"} + else: + expected = {"pip": "bundle", "setuptools": "bundle", "wheel": "bundle"} assert session.seeder.distribution_to_versions() == expected diff -Nru python-virtualenv-20.30.0+ds/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py python-virtualenv-20.31.2+ds/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py --- python-virtualenv-20.30.0+ds/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py 2020-02-02 01:00:00.000000000 +0100 @@ -25,7 +25,7 @@ @pytest.mark.slow @pytest.mark.parametrize("copies", [False, True] if fs_supports_symlink() else [True]) -def test_seed_link_via_app_data(tmp_path, coverage_env, current_fastest, copies): +def test_seed_link_via_app_data(tmp_path, coverage_env, current_fastest, copies, for_py_version): # noqa: PLR0915 current = PythonInfo.current_system() bundle_ver = BUNDLE_SUPPORT[current.version_release_str] create_cmd = [ @@ -45,6 +45,8 @@ current_fastest, "-vv", ] + if for_py_version == "3.8": + create_cmd += ["--wheel", bundle_ver["wheel"].split("-")[1]] if not copies: create_cmd.append("--symlink-app-data") result = cli_run(create_cmd) @@ -109,7 +111,7 @@ # Windows does not allow removing a executable while running it, so when uninstalling pip we need to do it via # python -m pip - remove_cmd = [str(result.creator.exe), "-m", "pip"] + remove_cmd[1:] + remove_cmd = [str(result.creator.exe), "-m", "pip", *remove_cmd[1:]] process = Popen([*remove_cmd, "pip", "wheel"]) _, __ = process.communicate() assert not process.returncode @@ -210,11 +212,18 @@ @pytest.mark.slow @pytest.mark.parametrize("pkg", ["pip", "setuptools", "wheel"]) @pytest.mark.usefixtures("session_app_data", "current_fastest", "coverage_env") -def test_base_bootstrap_link_via_app_data_no(tmp_path, pkg): - create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}", "--wheel", "bundle", "--setuptools", "bundle"] +def test_base_bootstrap_link_via_app_data_no(tmp_path, pkg, for_py_version): + if for_py_version != "3.8" and pkg == "wheel": + msg = "wheel isn't installed on Python > 3.8" + raise pytest.skip(msg) + create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}", "--setuptools", "bundle"] + if for_py_version == "3.8": + create_cmd += ["--wheel", "bundle"] result = cli_run(create_cmd) assert not (result.creator.purelib / pkg).exists() for key in {"pip", "setuptools", "wheel"} - {pkg}: + if for_py_version != "3.8" and key == "wheel": + continue assert (result.creator.purelib / key).exists() @@ -230,7 +239,7 @@ exceptions = _run_parallel_threads(tmp_path) assert len(exceptions) == 2 for exception in exceptions: - assert exception.startswith("failed to build image wheel because:\nTraceback") + assert exception.startswith("failed to build image pip because:\nTraceback") assert "RuntimeError" in exception, exception @@ -239,7 +248,10 @@ def _run(name): try: - cli_run(["--seeder", "app-data", str(tmp_path / name), "--no-pip", "--no-setuptools", "--wheel", "bundle"]) + cmd = ["--seeder", "app-data", str(tmp_path / name), "--no-setuptools"] + if sys.version_info[:2] == (3, 8): + cmd.append("--no-wheel") + cli_run(cmd) except Exception as exception: # noqa: BLE001 as_str = str(exception) exceptions.append(as_str) diff -Nru python-virtualenv-20.30.0+ds/tests/unit/seed/embed/test_pip_invoke.py python-virtualenv-20.31.2+ds/tests/unit/seed/embed/test_pip_invoke.py --- python-virtualenv-20.30.0+ds/tests/unit/seed/embed/test_pip_invoke.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/tests/unit/seed/embed/test_pip_invoke.py 2020-02-02 01:00:00.000000000 +0100 @@ -49,7 +49,9 @@ original = PipInvoke._execute # noqa: SLF001 run = mocker.patch.object(PipInvoke, "_execute", side_effect=_execute) - versions = {"pip": "embed", "setuptools": "bundle", "wheel": new["wheel"].split("-")[1]} + versions = {"pip": "embed", "setuptools": "bundle"} + if sys.version_info[:2] == (3, 8): + versions["wheel"] = new["wheel"].split("-")[1] create_cmd = [ "--seeder", @@ -86,4 +88,6 @@ for key in ("pip", "setuptools", "wheel"): if key == no: continue + if sys.version_info[:2] >= (3, 9) and key == "wheel": + continue assert locals()[key] in files_post_first_create diff -Nru python-virtualenv-20.30.0+ds/tests/unit/seed/wheels/test_periodic_update.py python-virtualenv-20.31.2+ds/tests/unit/seed/wheels/test_periodic_update.py --- python-virtualenv-20.30.0+ds/tests/unit/seed/wheels/test_periodic_update.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/tests/unit/seed/wheels/test_periodic_update.py 2020-02-02 01:00:00.000000000 +0100 @@ -74,7 +74,7 @@ packages[args[1]["distribution"]].append(args[1]["for_py_version"]) packages = {key: sorted(value) for key, value in packages.items()} versions = sorted(BUNDLE_SUPPORT.keys()) - expected = {"setuptools": versions, "wheel": versions, "pip": versions} + expected = {"setuptools": versions, "wheel": ["3.8"], "pip": versions} assert packages == expected @@ -101,8 +101,6 @@ "--no-pip", "--setuptools", "bundle", - "--wheel", - "bundle", ], ) diff -Nru python-virtualenv-20.30.0+ds/tests/unit/seed/wheels/test_wheels_util.py python-virtualenv-20.31.2+ds/tests/unit/seed/wheels/test_wheels_util.py --- python-virtualenv-20.30.0+ds/tests/unit/seed/wheels/test_wheels_util.py 2020-02-02 01:00:00.000000000 +0100 +++ python-virtualenv-20.31.2+ds/tests/unit/seed/wheels/test_wheels_util.py 2020-02-02 01:00:00.000000000 +0100 @@ -29,3 +29,8 @@ def test_wheel_repr(): wheel = get_embed_wheel("setuptools", MAX) assert str(wheel.path) in repr(wheel) + + +def test_unknown_distribution(): + wheel = get_embed_wheel("unknown", MAX) + assert wheel is None