Skip to content

Commit 3fa94b7

Browse files
authored
Merge pull request #2868 from stefanor/no-wheel
2 parents 26e2235 + c93d2a6 commit 3fa94b7

File tree

13 files changed

+66
-47
lines changed

13 files changed

+66
-47
lines changed

docs/changelog/2868.feature.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
No longer bundle ``wheel`` wheels, ``setuptools`` includes native ``bdist_wheel`` support.
2+
Update ``pip`` to ``25.1``.

docs/development.rst

Lines changed: 1 addition & 1 deletion
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

Lines changed: 5 additions & 5 deletions
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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from __future__ import annotations
22

33
from abc import ABC
4+
from argparse import SUPPRESS
45
from pathlib import Path
6+
from warnings import warn
57

68
from virtualenv.seed.seeder import Seeder
79
from virtualenv.seed.wheels import Version
@@ -18,14 +20,21 @@ def __init__(self, options) -> None:
1820

1921
self.pip_version = options.pip
2022
self.setuptools_version = options.setuptools
21-
self.wheel_version = options.wheel
2223

2324
self.no_pip = options.no_pip
2425
self.no_setuptools = options.no_setuptools
25-
self.no_wheel = options.no_wheel
2626
self.app_data = options.app_data
2727
self.periodic_update = not options.no_periodic_update
2828

29+
if options.no_wheel:
30+
warn(
31+
"The --no-wheel option is deprecated. "
32+
"It has no effect, wheel is no longer bundled in virtualenv. "
33+
"This option will be removed in pip 26.",
34+
DeprecationWarning,
35+
stacklevel=1,
36+
)
37+
2938
if not self.distribution_to_versions():
3039
self.enabled = False
3140

@@ -34,7 +43,6 @@ def distributions(cls) -> dict[str, Version]:
3443
return {
3544
"pip": Version.bundle,
3645
"setuptools": Version.bundle,
37-
"wheel": Version.bundle,
3846
}
3947

4048
def distribution_to_versions(self) -> dict[str, str]:
@@ -71,7 +79,7 @@ def add_parser_arguments(cls, parser, interpreter, app_data): # noqa: ARG003
7179
default=[],
7280
)
7381
for distribution, default in cls.distributions().items():
74-
if interpreter.version_info[:2] >= (3, 12) and distribution in {"wheel", "setuptools"}:
82+
if interpreter.version_info[:2] >= (3, 12) and distribution == "setuptools":
7583
default = "none" # noqa: PLW2901
7684
parser.add_argument(
7785
f"--{distribution}",
@@ -88,6 +96,13 @@ def add_parser_arguments(cls, parser, interpreter, app_data): # noqa: ARG003
8896
help=f"do not install {distribution}",
8997
default=False,
9098
)
99+
# DEPRECATED: Remove in pip 26
100+
parser.add_argument(
101+
"--no-wheel",
102+
dest="no_wheel",
103+
action="store_true",
104+
help=SUPPRESS,
105+
)
91106
parser.add_argument(
92107
"--no-periodic-update",
93108
dest="no_periodic_update",

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

Lines changed: 6 additions & 13 deletions
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": {
15-
"pip": "pip-25.0.1-py3-none-any.whl",
14+
"pip": "pip-25.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": {
20-
"pip": "pip-25.0.1-py3-none-any.whl",
18+
"pip": "pip-25.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": {
25-
"pip": "pip-25.0.1-py3-none-any.whl",
22+
"pip": "pip-25.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": {
30-
"pip": "pip-25.0.1-py3-none-any.whl",
26+
"pip": "pip-25.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": {
35-
"pip": "pip-25.0.1-py3-none-any.whl",
30+
"pip": "pip-25.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": {
40-
"pip": "pip-25.0.1-py3-none-any.whl",
34+
"pip": "pip-25.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.
Binary file not shown.

tests/unit/config/test___main__.py

Lines changed: 2 additions & 2 deletions
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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,10 @@ def test_create_long_path(tmp_path):
398398
subprocess.check_call([str(result.creator.script("pip")), "--version"])
399399

400400

401+
@pytest.mark.skipif(
402+
sys.version_info[:2] == (3, 8),
403+
reason="Disable on Python 3.8, which still uses pip 25.0.1 (without https://github.com/pypa/pip/pull/13330)",
404+
)
401405
@pytest.mark.slow
402406
@pytest.mark.parametrize("creator", sorted(set(PythonInfo.current_system().creators().key_to_class) - {"builtin"}))
403407
@pytest.mark.usefixtures("session_app_data")
@@ -411,8 +415,6 @@ def test_create_distutils_cfg(creator, tmp_path, monkeypatch):
411415
creator,
412416
"--setuptools",
413417
"bundle",
414-
"--wheel",
415-
"bundle",
416418
],
417419
)
418420

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

tests/unit/seed/embed/test_base_embed.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import sys
4+
import warnings
45
from typing import TYPE_CHECKING
56

67
import pytest
@@ -20,11 +21,21 @@ def test_download_cli_flag(args, download, tmp_path):
2021
assert session.seeder.download is download
2122

2223

24+
# DEPRECATED: Remove in pip 26
25+
def test_download_deprecated_cli_flag(tmp_path):
26+
with warnings.catch_warnings(record=True) as w:
27+
warnings.simplefilter("always")
28+
session_via_cli(["--no-wheel", str(tmp_path)])
29+
assert len(w) == 1
30+
assert issubclass(w[-1].category, DeprecationWarning)
31+
assert str(w[-1].message) == (
32+
"The --no-wheel option is deprecated. "
33+
"It has no effect, wheel is no longer bundled in virtualenv. "
34+
"This option will be removed in pip 26."
35+
)
36+
37+
2338
def test_embed_wheel_versions(tmp_path: Path) -> None:
2439
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-
)
40+
expected = {"pip": "bundle"} if sys.version_info[:2] >= (3, 12) else {"pip": "bundle", "setuptools": "bundle"}
3041
assert session.seeder.distribution_to_versions() == expected

tests/unit/seed/embed/test_bootstrap_link_via_app_data.py

Lines changed: 6 additions & 6 deletions
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

Lines changed: 3 additions & 4 deletions
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

Lines changed: 1 addition & 4 deletions
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)