From: Stefano Rivera <stefano@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                   |  5 +----
 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                  |  6 +-----
 tests/unit/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, 15 insertions(+), 35 deletions(-)

diff --git a/src/virtualenv/seed/embed/base_embed.py b/src/virtualenv/seed/embed/base_embed.py
index 7d83cb6..d370e5b 100644
--- a/src/virtualenv/seed/embed/base_embed.py
+++ b/src/virtualenv/seed/embed/base_embed.py
@@ -18,11 +18,9 @@ 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
 
@@ -34,7 +32,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 +68,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}",
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..e34266d 100644
--- a/tests/unit/seed/embed/test_base_embed.py
+++ b/tests/unit/seed/embed/test_base_embed.py
@@ -22,9 +22,5 @@ def test_download_cli_flag(args, download, tmp_path):
 
 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",
         ],
     )
 
