Skip to content

Don't seed setuptools/wheel in tests virtual environments. #2329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions cibuildwheel/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from pathlib import Path, PurePath, PurePosixPath
from typing import assert_never

from packaging.version import Version

from . import errors
from .architecture import Architecture
from .frontend import BuildFrontendConfig, get_build_frontend_extra_flags
Expand Down Expand Up @@ -351,10 +349,7 @@ def build_in_container(
container.call(["uv", "venv", venv_dir, "--python", python_bin / "python"], env=env)
else:
# Use embedded dependencies from virtualenv to ensure determinism
venv_args = ["--no-periodic-update", "--pip=embed"]
# In Python<3.12, setuptools & wheel are installed as well
if Version(config.version) < Version("3.12"):
venv_args.extend(("--setuptools=embed", "--wheel=embed"))
venv_args = ["--no-periodic-update", "--pip=embed", "--no-setuptools", "--no-wheel"]
container.call(["python", "-m", "virtualenv", *venv_args, venv_dir], env=env)

virtualenv_env = env.copy()
Expand Down
10 changes: 6 additions & 4 deletions cibuildwheel/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,10 +643,12 @@ def build(options: Options, tmp_path: Path) -> None:
else:
pip_install = functools.partial(call_with_arch, *pip, "install")
# Use pip version from the initial env to ensure determinism
venv_args = ["--no-periodic-update", f"--pip={pip_version}"]
# In Python<3.12, setuptools & wheel are installed as well, use virtualenv embedded ones
if Version(config.version) < Version("3.12"):
venv_args.extend(("--setuptools=embed", "--wheel=embed"))
venv_args = [
"--no-periodic-update",
f"--pip={pip_version}",
"--no-setuptools",
"--no-wheel",
]
call_with_arch("python", "-m", "virtualenv", *venv_args, venv_dir, env=env)

virtualenv_env = env.copy()
Expand Down
39 changes: 0 additions & 39 deletions cibuildwheel/resources/constraints-python37.txt

This file was deleted.

33 changes: 9 additions & 24 deletions cibuildwheel/venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ def _ensure_virtualenv(version: str) -> Path:
return path


def _parse_constraints_for_virtualenv(
seed_packages: list[str],
def _parse_pip_constraint_for_virtualenv(
dependency_constraint_flags: Sequence[PathOrStr],
) -> dict[str, str]:
) -> str:
"""
Parses the constraints file referenced by `dependency_constraint_flags` and returns a dict where
the key is the package name, and the value is the constraint version.
Expand All @@ -50,8 +49,6 @@ def _parse_constraints_for_virtualenv(
{macos|windows}.setup_python function.
"""
assert len(dependency_constraint_flags) in {0, 2}
# only seed pip if other seed packages do not appear in a constraint file
constraints_dict = {"pip": "embed"}
if len(dependency_constraint_flags) == 2:
assert dependency_constraint_flags[0] == "-c"
constraint_path = Path(dependency_constraint_flags[1])
Expand All @@ -67,7 +64,7 @@ def _parse_constraints_for_virtualenv(
requirement = Requirement(line)
package = requirement.name
if (
package not in seed_packages
package != "pip"
or requirement.url is not None
or requirement.marker is not None
or len(requirement.extras) != 0
Expand All @@ -77,10 +74,10 @@ def _parse_constraints_for_virtualenv(
specifier = next(iter(requirement.specifier))
if specifier.operator != "==":
continue
constraints_dict[package] = specifier.version
return specifier.version
except InvalidRequirement:
continue
return constraints_dict
return "embed"


def virtualenv(
Expand All @@ -94,7 +91,7 @@ def virtualenv(
"""
Create a virtual environment. If `use_uv` is True,
dependency_constraint_flags are ignored since nothing is installed in the
venv. Otherwise, pip is installed, and setuptools + wheel if Python < 3.12.
venv. Otherwise, pip is installed.
"""

# virtualenv may fail if this is a symlink.
Expand All @@ -106,28 +103,16 @@ def virtualenv(
call("uv", "venv", venv_path, "--python", python)
else:
virtualenv_app = _ensure_virtualenv(version)
allowed_seed_packages = ["pip", "setuptools", "wheel"]
constraints = _parse_constraints_for_virtualenv(
allowed_seed_packages, dependency_constraint_flags
)
additional_flags: list[str] = []
for package in allowed_seed_packages:
if package in constraints:
additional_flags.append(f"--{package}={constraints[package]}")
else:
additional_flags.append(f"--no-{package}")
pip_constraint = _parse_pip_constraint_for_virtualenv(dependency_constraint_flags)
additional_flags = [f"--pip={pip_constraint}", "--no-setuptools", "--no-wheel"]

# Using symlinks to pre-installed seed packages is really the fastest way to get a virtual
# environment. The initial cost is a bit higher but reusing is much faster.
# Windows does not always allow symlinks so just disabling for now.
# Requires pip>=19.3 so disabling for "embed" because this means we don't know what's the
# version of pip that will end-up installed.
# c.f. https://virtualenv.pypa.io/en/latest/cli_interface.html#section-seeder
if (
not _IS_WIN
and constraints["pip"] != "embed"
and Version(constraints["pip"]) >= Version("19.3")
):
if not _IS_WIN and pip_constraint != "embed" and Version(pip_constraint) >= Version("19.3"):
additional_flags.append("--symlink-app-data")

call(
Expand Down
11 changes: 6 additions & 5 deletions cibuildwheel/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from typing import assert_never

from filelock import FileLock
from packaging.version import Version

from . import errors
from .architecture import Architecture
Expand Down Expand Up @@ -497,10 +496,12 @@ def build(options: Options, tmp_path: Path) -> None:
call("uv", "venv", venv_dir, f"--python={base_python}", env=env)
else:
# Use pip version from the initial env to ensure determinism
venv_args = ["--no-periodic-update", f"--pip={pip_version}"]
# In Python<3.12, setuptools & wheel are installed as well, use virtualenv embedded ones
if Version(config.version) < Version("3.12"):
venv_args.extend(("--setuptools=embed", "--wheel=embed"))
venv_args = [
"--no-periodic-update",
f"--pip={pip_version}",
"--no-setuptools",
"--no-wheel",
]
call("python", "-m", "virtualenv", *venv_args, venv_dir, env=env)

virtualenv_env = env.copy()
Expand Down
Loading