Skip to content

Commit db1d9fc

Browse files
committed
Stop including 'wheel', setuptools 70.1 has native bdist_wheel support
1 parent 26e2235 commit db1d9fc

12 files changed

+23
-41
lines changed

docs/changelog/2868.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No longer bundle ``wheel`` wheels, ``setuptools`` includes native ``bdist_wheel`` support.

docs/development.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ that folder.
106106
Release
107107
~~~~~~~
108108

109-
virtualenv's release schedule is tied to ``pip``, ``setuptools`` and ``wheel``. We bundle the latest version of these
109+
virtualenv's release schedule is tied to ``pip`` and ``setuptools``. We bundle the latest version of these
110110
libraries so each time there's a new version of any of these, there will be a new virtualenv release shortly afterwards
111111
(we usually wait just a few days to avoid pulling in any broken releases).
112112

docs/user_guide.rst

+5-5
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ The tool works in two phases:
4242
four further sub-steps:
4343

4444
- create a python that matches the target python interpreter from phase 1,
45-
- install (bootstrap) seed packages (one or more of :pypi:`pip`, :pypi:`setuptools`, :pypi:`wheel`) in the created
45+
- install (bootstrap) seed packages (one or more of :pypi:`pip`, :pypi:`setuptools`) in the created
4646
virtual environment,
4747
- install activation scripts into the binary directory of the virtual environment (these will allow end users to
4848
*activate* the virtual environment from various shells).
@@ -138,9 +138,9 @@ at the moment has two types of virtual environments:
138138

139139
Seeders
140140
-------
141-
These will install for you some seed packages (one or more of: :pypi:`pip`, :pypi:`setuptools`, :pypi:`wheel`) that
141+
These will install for you some seed packages (one or more of: :pypi:`pip`, :pypi:`setuptools`) that
142142
enables you to install additional python packages into the created virtual environment (by invoking pip). Installing
143-
:pypi:`setuptools` and :pypi:`wheel` is disabled by default on Python 3.12+ environments. There are two
143+
:pypi:`setuptools` is disabled by default on Python 3.12+ environments. There are two
144144
main seed mechanisms available:
145145

146146
- ``pip`` - this method uses the bundled pip with virtualenv to install the seed packages (note, a new child process
@@ -163,8 +163,8 @@ Wheels
163163
To install a seed package via either ``pip`` or ``app-data`` method virtualenv needs to acquire a wheel of the target
164164
package. These wheels may be acquired from multiple locations as follows:
165165

166-
- ``virtualenv`` ships out of box with a set of embed ``wheels`` for all three seed packages (:pypi:`pip`,
167-
:pypi:`setuptools`, :pypi:`wheel`). These are packaged together with the virtualenv source files, and only change upon
166+
- ``virtualenv`` ships out of box with a set of embed ``wheels`` for both seed packages (:pypi:`pip`,
167+
:pypi:`setuptools`). These are packaged together with the virtualenv source files, and only change upon
168168
upgrading virtualenv. Different Python versions require different versions of these, and because virtualenv supports a
169169
wide range of Python versions, the number of embedded wheels out of box is greater than 3. Whenever newer versions of
170170
these embedded packages are released upstream ``virtualenv`` project upgrades them, and does a new release. Therefore,

src/virtualenv/seed/embed/base_embed.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@ def __init__(self, options) -> None:
1818

1919
self.pip_version = options.pip
2020
self.setuptools_version = options.setuptools
21-
self.wheel_version = options.wheel
2221

2322
self.no_pip = options.no_pip
2423
self.no_setuptools = options.no_setuptools
25-
self.no_wheel = options.no_wheel
2624
self.app_data = options.app_data
2725
self.periodic_update = not options.no_periodic_update
2826

@@ -34,7 +32,6 @@ def distributions(cls) -> dict[str, Version]:
3432
return {
3533
"pip": Version.bundle,
3634
"setuptools": Version.bundle,
37-
"wheel": Version.bundle,
3835
}
3936

4037
def distribution_to_versions(self) -> dict[str, str]:
@@ -71,7 +68,7 @@ def add_parser_arguments(cls, parser, interpreter, app_data): # noqa: ARG003
7168
default=[],
7269
)
7370
for distribution, default in cls.distributions().items():
74-
if interpreter.version_info[:2] >= (3, 12) and distribution in {"wheel", "setuptools"}:
71+
if interpreter.version_info[:2] >= (3, 12) and distribution == "setuptools":
7572
default = "none" # noqa: PLW2901
7673
parser.add_argument(
7774
f"--{distribution}",

src/virtualenv/seed/wheels/embed/__init__.py

-7
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,30 @@
99
"3.8": {
1010
"pip": "pip-25.0.1-py3-none-any.whl",
1111
"setuptools": "setuptools-75.3.2-py3-none-any.whl",
12-
"wheel": "wheel-0.45.1-py3-none-any.whl",
1312
},
1413
"3.9": {
1514
"pip": "pip-25.0.1-py3-none-any.whl",
1615
"setuptools": "setuptools-78.1.0-py3-none-any.whl",
17-
"wheel": "wheel-0.45.1-py3-none-any.whl",
1816
},
1917
"3.10": {
2018
"pip": "pip-25.0.1-py3-none-any.whl",
2119
"setuptools": "setuptools-78.1.0-py3-none-any.whl",
22-
"wheel": "wheel-0.45.1-py3-none-any.whl",
2320
},
2421
"3.11": {
2522
"pip": "pip-25.0.1-py3-none-any.whl",
2623
"setuptools": "setuptools-78.1.0-py3-none-any.whl",
27-
"wheel": "wheel-0.45.1-py3-none-any.whl",
2824
},
2925
"3.12": {
3026
"pip": "pip-25.0.1-py3-none-any.whl",
3127
"setuptools": "setuptools-78.1.0-py3-none-any.whl",
32-
"wheel": "wheel-0.45.1-py3-none-any.whl",
3328
},
3429
"3.13": {
3530
"pip": "pip-25.0.1-py3-none-any.whl",
3631
"setuptools": "setuptools-78.1.0-py3-none-any.whl",
37-
"wheel": "wheel-0.45.1-py3-none-any.whl",
3832
},
3933
"3.14": {
4034
"pip": "pip-25.0.1-py3-none-any.whl",
4135
"setuptools": "setuptools-78.1.0-py3-none-any.whl",
42-
"wheel": "wheel-0.45.1-py3-none-any.whl",
4336
},
4437
}
4538
MAX = "3.8"
Binary file not shown.

tests/unit/config/test___main__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ def test_fail_with_traceback(raise_on_session_done, tmp_path, capsys):
6464

6565
@pytest.mark.usefixtures("session_app_data")
6666
def test_session_report_full(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
67-
run_with_catch([str(tmp_path), "--setuptools", "bundle", "--wheel", "bundle"])
67+
run_with_catch([str(tmp_path), "--setuptools", "bundle"])
6868
out, err = capsys.readouterr()
6969
assert not err
7070
lines = out.splitlines()
7171
regexes = [
7272
r"created virtual environment .* in \d+ms",
7373
r" creator .*",
7474
r" seeder .*",
75-
r" added seed packages: .*pip==.*, setuptools==.*, wheel==.*",
75+
r" added seed packages: .*pip==.*, setuptools==.*",
7676
r" activators .*",
7777
]
7878
_match_regexes(lines, regexes)

tests/unit/create/test_creator.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ def test_create_long_path(tmp_path):
398398
subprocess.check_call([str(result.creator.script("pip")), "--version"])
399399

400400

401+
@pytest.mark.skip("Depends on https://github.com/pypa/pip/pull/13330")
401402
@pytest.mark.slow
402403
@pytest.mark.parametrize("creator", sorted(set(PythonInfo.current_system().creators().key_to_class) - {"builtin"}))
403404
@pytest.mark.usefixtures("session_app_data")
@@ -411,8 +412,6 @@ def test_create_distutils_cfg(creator, tmp_path, monkeypatch):
411412
creator,
412413
"--setuptools",
413414
"bundle",
414-
"--wheel",
415-
"bundle",
416415
],
417416
)
418417

@@ -470,7 +469,7 @@ def list_files(path):
470469
def test_zip_importer_can_import_setuptools(tmp_path):
471470
"""We're patching the loaders so might fail on r/o loaders, such as zipimporter on CPython<3.8"""
472471
result = cli_run(
473-
[str(tmp_path / "venv"), "--activators", "", "--no-pip", "--no-wheel", "--copies", "--setuptools", "bundle"],
472+
[str(tmp_path / "venv"), "--activators", "", "--no-pip", "--copies", "--setuptools", "bundle"],
474473
)
475474
zip_path = tmp_path / "site-packages.zip"
476475
with zipfile.ZipFile(str(zip_path), "w", zipfile.ZIP_DEFLATED) as zip_handler:

tests/unit/seed/embed/test_base_embed.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,5 @@ def test_download_cli_flag(args, download, tmp_path):
2222

2323
def test_embed_wheel_versions(tmp_path: Path) -> None:
2424
session = session_via_cli([str(tmp_path)])
25-
expected = (
26-
{"pip": "bundle"}
27-
if sys.version_info[:2] >= (3, 12)
28-
else {"pip": "bundle", "setuptools": "bundle", "wheel": "bundle"}
29-
)
25+
expected = {"pip": "bundle"} if sys.version_info[:2] >= (3, 12) else {"pip": "bundle", "setuptools": "bundle"}
3026
assert session.seeder.distribution_to_versions() == expected

tests/unit/seed/embed/test_bootstrap_link_via_app_data.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def test_seed_link_via_app_data(tmp_path, coverage_env, current_fastest, copies)
110110
# Windows does not allow removing a executable while running it, so when uninstalling pip we need to do it via
111111
# python -m pip
112112
remove_cmd = [str(result.creator.exe), "-m", "pip", *remove_cmd[1:]]
113-
process = Popen([*remove_cmd, "pip", "wheel"])
113+
process = Popen([*remove_cmd, "pip"])
114114
_, __ = process.communicate()
115115
assert not process.returncode
116116
# 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
208208

209209

210210
@pytest.mark.slow
211-
@pytest.mark.parametrize("pkg", ["pip", "setuptools", "wheel"])
211+
@pytest.mark.parametrize("pkg", ["pip", "setuptools"])
212212
@pytest.mark.usefixtures("session_app_data", "current_fastest", "coverage_env")
213213
def test_base_bootstrap_link_via_app_data_no(tmp_path, pkg):
214-
create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}", "--wheel", "bundle", "--setuptools", "bundle"]
214+
create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}", "--setuptools", "bundle"]
215215
result = cli_run(create_cmd)
216216
assert not (result.creator.purelib / pkg).exists()
217-
for key in {"pip", "setuptools", "wheel"} - {pkg}:
217+
for key in {"pip", "setuptools"} - {pkg}:
218218
assert (result.creator.purelib / key).exists()
219219

220220

@@ -230,7 +230,7 @@ def test_app_data_parallel_fail(tmp_path: Path, mocker: MockerFixture) -> None:
230230
exceptions = _run_parallel_threads(tmp_path)
231231
assert len(exceptions) == 2
232232
for exception in exceptions:
233-
assert exception.startswith("failed to build image wheel because:\nTraceback")
233+
assert exception.startswith("failed to build image pip because:\nTraceback")
234234
assert "RuntimeError" in exception, exception
235235

236236

@@ -239,7 +239,7 @@ def _run_parallel_threads(tmp_path):
239239

240240
def _run(name):
241241
try:
242-
cli_run(["--seeder", "app-data", str(tmp_path / name), "--no-pip", "--no-setuptools", "--wheel", "bundle"])
242+
cli_run(["--seeder", "app-data", str(tmp_path / name), "--no-setuptools"])
243243
except Exception as exception: # noqa: BLE001
244244
as_str = str(exception)
245245
exceptions.append(as_str)

tests/unit/seed/embed/test_pip_invoke.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414

1515
@pytest.mark.slow
16-
@pytest.mark.parametrize("no", ["pip", "setuptools", "wheel", ""])
16+
@pytest.mark.parametrize("no", ["pip", "setuptools", ""])
1717
def test_base_bootstrap_via_pip_invoke(tmp_path, coverage_env, mocker, current_fastest, no): # noqa: C901
1818
extra_search_dir = tmp_path / "extra"
1919
extra_search_dir.mkdir()
@@ -49,7 +49,7 @@ def _execute(cmd, env):
4949

5050
original = PipInvoke._execute # noqa: SLF001
5151
run = mocker.patch.object(PipInvoke, "_execute", side_effect=_execute)
52-
versions = {"pip": "embed", "setuptools": "bundle", "wheel": new["wheel"].split("-")[1]}
52+
versions = {"pip": "embed", "setuptools": "bundle"}
5353

5454
create_cmd = [
5555
"--seeder",
@@ -76,14 +76,13 @@ def _execute(cmd, env):
7676
site_package = result.creator.purelib
7777
pip = site_package / "pip"
7878
setuptools = site_package / "setuptools"
79-
wheel = site_package / "wheel"
8079
files_post_first_create = list(site_package.iterdir())
8180

8281
if no:
8382
no_file = locals()[no]
8483
assert no not in files_post_first_create
8584

86-
for key in ("pip", "setuptools", "wheel"):
85+
for key in ("pip", "setuptools"):
8786
if key == no:
8887
continue
8988
assert locals()[key] in files_post_first_create

tests/unit/seed/wheels/test_periodic_update.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def _do_update( # noqa: PLR0913
7474
packages[args[1]["distribution"]].append(args[1]["for_py_version"])
7575
packages = {key: sorted(value) for key, value in packages.items()}
7676
versions = sorted(BUNDLE_SUPPORT.keys())
77-
expected = {"setuptools": versions, "wheel": versions, "pip": versions}
77+
expected = {"setuptools": versions, "pip": versions}
7878
assert packages == expected
7979

8080

@@ -97,12 +97,9 @@ def test_pick_periodic_update(tmp_path, mocker, for_py_version):
9797
"--activators",
9898
"",
9999
"--no-periodic-update",
100-
"--no-wheel",
101100
"--no-pip",
102101
"--setuptools",
103102
"bundle",
104-
"--wheel",
105-
"bundle",
106103
],
107104
)
108105

0 commit comments

Comments
 (0)