chore: rework virtual environments creation for tests (#2356)
As mentioned in https://github.com/pypa/cibuildwheel/pull/2347#discussion_r2029821701 Rework the way test venvs are created to reuse the same mechanisms as build venvs.
This commit is contained in:
@@ -241,25 +241,6 @@ def setup_python(
|
|||||||
# we version pip ourselves, so we don't care about pip version checking
|
# we version pip ourselves, so we don't care about pip version checking
|
||||||
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
||||||
|
|
||||||
# upgrade pip to the version matching our constraints
|
|
||||||
# if necessary, reinstall it to ensure that it's available on PATH as 'pip'
|
|
||||||
if build_frontend == "build[uv]":
|
|
||||||
assert uv_path is not None
|
|
||||||
pip = [str(uv_path), "pip"]
|
|
||||||
else:
|
|
||||||
pip = ["python", "-m", "pip"]
|
|
||||||
|
|
||||||
if not use_uv:
|
|
||||||
call(
|
|
||||||
*pip,
|
|
||||||
"install",
|
|
||||||
"--upgrade",
|
|
||||||
"pip",
|
|
||||||
*constraint_flags(dependency_constraint),
|
|
||||||
env=env,
|
|
||||||
cwd=venv_path,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Apply our environment after pip is ready
|
# Apply our environment after pip is ready
|
||||||
env = environment.as_dictionary(prev_environment=env)
|
env = environment.as_dictionary(prev_environment=env)
|
||||||
|
|
||||||
@@ -434,8 +415,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
build_options.environment,
|
build_options.environment,
|
||||||
build_frontend.name,
|
build_frontend.name,
|
||||||
)
|
)
|
||||||
if not use_uv:
|
pip_version = None if use_uv else get_pip_version(env)
|
||||||
pip_version = get_pip_version(env)
|
|
||||||
|
|
||||||
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
||||||
if compatible_wheel:
|
if compatible_wheel:
|
||||||
@@ -460,7 +440,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
build_env = env.copy()
|
build_env = env.copy()
|
||||||
if not use_uv:
|
if pip_version is not None:
|
||||||
build_env["VIRTUALENV_PIP"] = pip_version
|
build_env["VIRTUALENV_PIP"] = pip_version
|
||||||
if constraints_path:
|
if constraints_path:
|
||||||
combine_constraints(
|
combine_constraints(
|
||||||
@@ -614,19 +594,6 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
else f"Testing wheel on {testing_arch}..."
|
else f"Testing wheel on {testing_arch}..."
|
||||||
)
|
)
|
||||||
|
|
||||||
# set up a virtual environment to install and test from, to make sure
|
|
||||||
# there are no dependencies that were pulled in at build time.
|
|
||||||
if not use_uv:
|
|
||||||
call(
|
|
||||||
"pip",
|
|
||||||
"install",
|
|
||||||
"virtualenv",
|
|
||||||
*constraint_flags(constraints_path),
|
|
||||||
env=env,
|
|
||||||
)
|
|
||||||
|
|
||||||
venv_dir = identifier_tmp_dir / f"venv-test-{testing_arch}"
|
|
||||||
|
|
||||||
arch_prefix = []
|
arch_prefix = []
|
||||||
uv_arch_args = []
|
uv_arch_args = []
|
||||||
if testing_arch != machine_arch:
|
if testing_arch != machine_arch:
|
||||||
@@ -642,29 +609,24 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
call_with_arch = functools.partial(call, *arch_prefix)
|
call_with_arch = functools.partial(call, *arch_prefix)
|
||||||
shell_with_arch = functools.partial(call, *arch_prefix, "/bin/sh", "-c")
|
shell_with_arch = functools.partial(call, *arch_prefix, "/bin/sh", "-c")
|
||||||
|
|
||||||
|
# set up a virtual environment to install and test from, to make sure
|
||||||
|
# there are no dependencies that were pulled in at build time.
|
||||||
|
venv_dir = identifier_tmp_dir / f"venv-test-{testing_arch}"
|
||||||
|
virtualenv_env = virtualenv(
|
||||||
|
config.version,
|
||||||
|
base_python,
|
||||||
|
venv_dir,
|
||||||
|
None,
|
||||||
|
use_uv=use_uv,
|
||||||
|
env=env,
|
||||||
|
pip_version=pip_version,
|
||||||
|
)
|
||||||
if use_uv:
|
if use_uv:
|
||||||
pip_install = functools.partial(call, *pip, "install", *uv_arch_args)
|
pip_install = functools.partial(call, *pip, "install", *uv_arch_args)
|
||||||
call("uv", "venv", venv_dir, f"--python={base_python}", env=env)
|
|
||||||
else:
|
else:
|
||||||
pip_install = functools.partial(call_with_arch, *pip, "install")
|
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}",
|
|
||||||
"--no-setuptools",
|
|
||||||
"--no-wheel",
|
|
||||||
]
|
|
||||||
call_with_arch("python", "-m", "virtualenv", *venv_args, venv_dir, env=env)
|
|
||||||
|
|
||||||
virtualenv_env = env.copy()
|
|
||||||
virtualenv_env["MACOSX_DEPLOYMENT_TARGET"] = get_test_macosx_deployment_target()
|
virtualenv_env["MACOSX_DEPLOYMENT_TARGET"] = get_test_macosx_deployment_target()
|
||||||
virtualenv_env["PATH"] = os.pathsep.join(
|
|
||||||
[
|
|
||||||
str(venv_dir / "bin"),
|
|
||||||
virtualenv_env["PATH"],
|
|
||||||
]
|
|
||||||
)
|
|
||||||
virtualenv_env["VIRTUAL_ENV"] = str(venv_dir)
|
|
||||||
|
|
||||||
# check that we are using the Python from the virtual environment
|
# check that we are using the Python from the virtual environment
|
||||||
call_with_arch("which", "python", env=virtualenv_env)
|
call_with_arch("which", "python", env=virtualenv_env)
|
||||||
|
|||||||
@@ -265,21 +265,6 @@ def setup_python(
|
|||||||
env["PYTHON_ARCH"] = python_configuration.arch
|
env["PYTHON_ARCH"] = python_configuration.arch
|
||||||
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
||||||
|
|
||||||
# upgrade pip to the version matching our constraints
|
|
||||||
# if necessary, reinstall it to ensure that it's available on PATH as 'pip.exe'
|
|
||||||
if not use_uv:
|
|
||||||
call(
|
|
||||||
"python",
|
|
||||||
"-m",
|
|
||||||
"pip",
|
|
||||||
"install",
|
|
||||||
"--upgrade",
|
|
||||||
"pip",
|
|
||||||
*constraint_flags(dependency_constraint),
|
|
||||||
env=env,
|
|
||||||
cwd=venv_path,
|
|
||||||
)
|
|
||||||
|
|
||||||
# update env with results from CIBW_ENVIRONMENT
|
# update env with results from CIBW_ENVIRONMENT
|
||||||
env = environment.as_dictionary(prev_environment=env)
|
env = environment.as_dictionary(prev_environment=env)
|
||||||
|
|
||||||
@@ -378,8 +363,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
build_options.environment,
|
build_options.environment,
|
||||||
build_frontend.name,
|
build_frontend.name,
|
||||||
)
|
)
|
||||||
if not use_uv:
|
pip_version = None if use_uv else get_pip_version(env)
|
||||||
pip_version = get_pip_version(env)
|
|
||||||
|
|
||||||
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
||||||
if compatible_wheel:
|
if compatible_wheel:
|
||||||
@@ -407,7 +391,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
build_env = env.copy()
|
build_env = env.copy()
|
||||||
if not use_uv:
|
if pip_version is not None:
|
||||||
build_env["VIRTUALENV_PIP"] = pip_version
|
build_env["VIRTUALENV_PIP"] = pip_version
|
||||||
|
|
||||||
if constraints_path:
|
if constraints_path:
|
||||||
@@ -486,33 +470,16 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
log.step("Testing wheel...")
|
log.step("Testing wheel...")
|
||||||
# set up a virtual environment to install and test from, to make sure
|
# set up a virtual environment to install and test from, to make sure
|
||||||
# there are no dependencies that were pulled in at build time.
|
# there are no dependencies that were pulled in at build time.
|
||||||
if not use_uv:
|
|
||||||
call(
|
|
||||||
"pip", "install", "virtualenv", *constraint_flags(constraints_path), env=env
|
|
||||||
)
|
|
||||||
|
|
||||||
venv_dir = identifier_tmp_dir / "venv-test"
|
venv_dir = identifier_tmp_dir / "venv-test"
|
||||||
|
virtualenv_env = virtualenv(
|
||||||
if use_uv:
|
config.version,
|
||||||
call("uv", "venv", venv_dir, f"--python={base_python}", env=env)
|
base_python,
|
||||||
else:
|
venv_dir,
|
||||||
# Use pip version from the initial env to ensure determinism
|
None,
|
||||||
venv_args = [
|
use_uv=use_uv,
|
||||||
"--no-periodic-update",
|
env=env,
|
||||||
f"--pip={pip_version}",
|
pip_version=pip_version,
|
||||||
"--no-setuptools",
|
|
||||||
"--no-wheel",
|
|
||||||
]
|
|
||||||
call("python", "-m", "virtualenv", *venv_args, venv_dir, env=env)
|
|
||||||
|
|
||||||
virtualenv_env = env.copy()
|
|
||||||
virtualenv_env["PATH"] = os.pathsep.join(
|
|
||||||
[
|
|
||||||
str(venv_dir / "Scripts"),
|
|
||||||
virtualenv_env["PATH"],
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
virtualenv_env["VIRTUAL_ENV"] = str(venv_dir)
|
|
||||||
|
|
||||||
# check that we are using the Python from the virtual environment
|
# check that we are using the Python from the virtual environment
|
||||||
call("where", "python", env=virtualenv_env)
|
call("where", "python", env=virtualenv_env)
|
||||||
|
|||||||
+20
-8
@@ -93,6 +93,8 @@ def virtualenv(
|
|||||||
dependency_constraint: Path | None,
|
dependency_constraint: Path | None,
|
||||||
*,
|
*,
|
||||||
use_uv: bool,
|
use_uv: bool,
|
||||||
|
env: dict[str, str] | None = None,
|
||||||
|
pip_version: str | None = None,
|
||||||
) -> dict[str, str]:
|
) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Create a virtual environment. If `use_uv` is True,
|
Create a virtual environment. If `use_uv` is True,
|
||||||
@@ -109,8 +111,9 @@ def virtualenv(
|
|||||||
call("uv", "venv", venv_path, "--python", python)
|
call("uv", "venv", venv_path, "--python", python)
|
||||||
else:
|
else:
|
||||||
virtualenv_app = _ensure_virtualenv(version)
|
virtualenv_app = _ensure_virtualenv(version)
|
||||||
pip_constraint = _parse_pip_constraint_for_virtualenv(dependency_constraint)
|
if pip_version is None:
|
||||||
additional_flags = [f"--pip={pip_constraint}", "--no-setuptools", "--no-wheel"]
|
pip_version = _parse_pip_constraint_for_virtualenv(dependency_constraint)
|
||||||
|
additional_flags = [f"--pip={pip_version}", "--no-setuptools", "--no-wheel"]
|
||||||
|
|
||||||
# Using symlinks to pre-installed seed packages is really the fastest way to get a virtual
|
# 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.
|
# environment. The initial cost is a bit higher but reusing is much faster.
|
||||||
@@ -118,7 +121,7 @@ def virtualenv(
|
|||||||
# Requires pip>=19.3 so disabling for "embed" because this means we don't know what's the
|
# 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.
|
# version of pip that will end-up installed.
|
||||||
# c.f. https://virtualenv.pypa.io/en/latest/cli_interface.html#section-seeder
|
# c.f. https://virtualenv.pypa.io/en/latest/cli_interface.html#section-seeder
|
||||||
if not _IS_WIN and pip_constraint != "embed" and Version(pip_constraint) >= Version("19.3"):
|
if not _IS_WIN and pip_version != "embed" and Version(pip_version) >= Version("19.3"):
|
||||||
additional_flags.append("--symlink-app-data")
|
additional_flags.append("--symlink-app-data")
|
||||||
|
|
||||||
call(
|
call(
|
||||||
@@ -132,12 +135,21 @@ def virtualenv(
|
|||||||
python,
|
python,
|
||||||
venv_path,
|
venv_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
paths = [str(venv_path), str(venv_path / "Scripts")] if _IS_WIN else [str(venv_path / "bin")]
|
paths = [str(venv_path), str(venv_path / "Scripts")] if _IS_WIN else [str(venv_path / "bin")]
|
||||||
env = os.environ.copy()
|
venv_env = os.environ.copy() if env is None else env.copy()
|
||||||
env["PATH"] = os.pathsep.join([*paths, env["PATH"]])
|
venv_env["PATH"] = os.pathsep.join([*paths, venv_env["PATH"]])
|
||||||
env["VIRTUAL_ENV"] = str(venv_path)
|
venv_env["VIRTUAL_ENV"] = str(venv_path)
|
||||||
return env
|
if not use_uv and pip_version == "embed":
|
||||||
|
call(
|
||||||
|
"pip",
|
||||||
|
"install",
|
||||||
|
"--upgrade",
|
||||||
|
"pip",
|
||||||
|
*constraint_flags(dependency_constraint),
|
||||||
|
env=venv_env,
|
||||||
|
cwd=venv_path,
|
||||||
|
)
|
||||||
|
return venv_env
|
||||||
|
|
||||||
|
|
||||||
def find_uv() -> Path | None:
|
def find_uv() -> Path | None:
|
||||||
|
|||||||
Reference in New Issue
Block a user