Compare commits
2
Commits
audit
...
reduce-uv-magic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
355c5a46b2 | ||
|
|
bc79c16a71 |
+25
-33
@@ -47,8 +47,6 @@ runs:
|
||||
from subprocess import run
|
||||
|
||||
EXTRAS = set(e.strip() for e in "${{ inputs.extras }}".split(",") if e.strip())
|
||||
if sys.platform == "linux":
|
||||
EXTRAS.discard("uv")
|
||||
|
||||
|
||||
class EnvBuilder(venv.EnvBuilder):
|
||||
@@ -73,47 +71,41 @@ runs:
|
||||
shutil.rmtree(venv_path)
|
||||
builder = EnvBuilder()
|
||||
builder.create(venv_path)
|
||||
exposed_binaries = {"cibuildwheel"}
|
||||
if "uv" in EXTRAS:
|
||||
exposed_binaries.add("uv")
|
||||
clean_bin_path = builder.bin_path.parent / f"{builder.bin_path.name}.clean"
|
||||
clean_bin_path.mkdir()
|
||||
for path in list(builder.bin_path.iterdir()):
|
||||
if path.stem in exposed_binaries:
|
||||
try:
|
||||
os.symlink(path, clean_bin_path / path.name)
|
||||
except OSError:
|
||||
import shutil
|
||||
cibw_bin = [p for p in builder.bin_path.glob("cibuildwheel*") if p.stem == "cibuildwheel"][0]
|
||||
|
||||
shutil.copy2(path, clean_bin_path / path.name)
|
||||
full_path = f"{clean_bin_path}{os.pathsep}{os.environ['PATH']}"
|
||||
with open(os.environ["GITHUB_OUTPUT"], "at") as f:
|
||||
f.write(f"updated-path={full_path}\n")
|
||||
f.write(f"cibw-bin={cibw_bin}\n")
|
||||
f.write(f"prepend-path={builder.bin_path if 'uv' in EXTRAS else ''}\n")
|
||||
|
||||
print("::endgroup::")
|
||||
EOF
|
||||
shell: bash
|
||||
|
||||
# Redirecting stderr to stdout to fix interleaving issue in Actions.
|
||||
- run: >
|
||||
cibuildwheel
|
||||
"${{ inputs.package-dir }}"
|
||||
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
|
||||
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
|
||||
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
|
||||
2>&1
|
||||
env:
|
||||
PATH: "${{ steps.cibw.outputs.updated-path }}"
|
||||
- run: |
|
||||
prepend_path="${{ steps.cibw.outputs.prepend-path }}"
|
||||
if [ -n "$prepend_path" ]; then
|
||||
export PATH="$prepend_path:$PATH"
|
||||
fi
|
||||
"${{ steps.cibw.outputs.cibw-bin }}" \
|
||||
"${{ inputs.package-dir }}" \
|
||||
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}} \
|
||||
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}} \
|
||||
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}} \
|
||||
2>&1
|
||||
shell: bash
|
||||
if: runner.os != 'Windows'
|
||||
|
||||
# Windows needs powershell to interact nicely with Meson
|
||||
- run: >
|
||||
cibuildwheel
|
||||
"${{ inputs.package-dir }}"
|
||||
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
|
||||
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
|
||||
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
|
||||
env:
|
||||
PATH: "${{ steps.cibw.outputs.updated-path }}"
|
||||
- run: |
|
||||
$PrependPath = "${{ steps.cibw.outputs.prepend-path }}"
|
||||
if ($PrependPath) {
|
||||
$env:PATH = "$PrependPath;$env:PATH"
|
||||
}
|
||||
& "${{ steps.cibw.outputs.cibw-bin }}" `
|
||||
"${{ inputs.package-dir }}" `
|
||||
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}} `
|
||||
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}} `
|
||||
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
|
||||
shell: pwsh
|
||||
if: runner.os == 'Windows'
|
||||
|
||||
@@ -34,7 +34,7 @@ from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file
|
||||
from ..util.helpers import prepare_command
|
||||
from ..util.packaging import find_compatible_wheel
|
||||
from ..util.python_build_standalone import create_python_build_standalone_environment
|
||||
from ..venv import constraint_flags, find_uv, virtualenv
|
||||
from ..venv import constraint_flags, ensure_uv, virtualenv
|
||||
|
||||
ANDROID_TRIPLET = {
|
||||
"arm64_v8a": "aarch64-linux-android",
|
||||
@@ -191,11 +191,9 @@ def setup_env(
|
||||
log.step("Setting up build environment...")
|
||||
build_frontend = build_options.build_frontend.name
|
||||
use_uv = build_frontend == "build[uv]"
|
||||
uv_path = find_uv()
|
||||
if use_uv and uv_path is None:
|
||||
msg = "uv not found"
|
||||
raise AssertionError(msg)
|
||||
pip = ["pip"] if not use_uv else [str(uv_path), "pip"]
|
||||
if use_uv:
|
||||
ensure_uv()
|
||||
pip = ["pip"] if not use_uv else ["uv", "pip"]
|
||||
|
||||
# Create virtual environment
|
||||
python_exe = create_python_build_standalone_environment(
|
||||
@@ -578,11 +576,9 @@ def test_wheel(state: BuildState, wheel: Path, *, build_frontend: str) -> None:
|
||||
|
||||
log.step("Testing wheel...")
|
||||
use_uv = build_frontend == "build[uv]"
|
||||
uv_path = find_uv()
|
||||
if use_uv and uv_path is None:
|
||||
msg = "uv not found"
|
||||
raise AssertionError(msg)
|
||||
pip = ["pip"] if not use_uv else [str(uv_path), "pip"]
|
||||
if use_uv:
|
||||
ensure_uv()
|
||||
pip = ["pip"] if not use_uv else ["uv", "pip"]
|
||||
|
||||
native_arch = arch_synonym(platform.machine(), platforms.native_platform(), "android")
|
||||
if state.config.arch != native_arch:
|
||||
|
||||
@@ -33,7 +33,7 @@ from ..util.file import (
|
||||
)
|
||||
from ..util.helpers import prepare_command, unwrap
|
||||
from ..util.packaging import find_compatible_wheel, get_pip_version
|
||||
from ..venv import constraint_flags, find_uv, virtualenv
|
||||
from ..venv import constraint_flags, ensure_uv, virtualenv
|
||||
|
||||
|
||||
@functools.cache
|
||||
@@ -217,8 +217,9 @@ def setup_python(
|
||||
environment: ParsedEnvironment,
|
||||
build_frontend: BuildFrontendName,
|
||||
) -> tuple[Path, dict[str, str]]:
|
||||
uv_path = find_uv()
|
||||
use_uv = build_frontend == "build[uv]"
|
||||
if use_uv:
|
||||
ensure_uv()
|
||||
|
||||
tmp.mkdir()
|
||||
implementation_id = python_configuration.identifier.split("-")[0]
|
||||
@@ -370,14 +371,13 @@ def setup_python(
|
||||
env=env,
|
||||
)
|
||||
case "build[uv]":
|
||||
assert uv_path is not None
|
||||
call(
|
||||
uv_path,
|
||||
"uv",
|
||||
"pip",
|
||||
"install",
|
||||
"--upgrade",
|
||||
"delocate",
|
||||
"build[virtualenv, uv]",
|
||||
"build",
|
||||
*constraint_flags(dependency_constraint),
|
||||
env=env,
|
||||
)
|
||||
@@ -414,11 +414,9 @@ def build(options: Options, tmp_path: Path) -> None:
|
||||
build_options = options.build_options(config.identifier)
|
||||
build_frontend = build_options.build_frontend
|
||||
use_uv = build_frontend.name == "build[uv]"
|
||||
uv_path = find_uv()
|
||||
if use_uv and uv_path is None:
|
||||
msg = "uv not found"
|
||||
raise AssertionError(msg)
|
||||
pip = ["pip"] if not use_uv else [str(uv_path), "pip"]
|
||||
if use_uv:
|
||||
ensure_uv()
|
||||
pip = ["pip"] if not use_uv else ["uv", "pip"]
|
||||
log.build_start(config.identifier)
|
||||
|
||||
identifier_tmp_dir = tmp_path / config.identifier
|
||||
|
||||
@@ -24,7 +24,7 @@ from ..util.cmd import call, shell
|
||||
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file
|
||||
from ..util.helpers import prepare_command, unwrap
|
||||
from ..util.packaging import find_compatible_wheel, get_pip_version
|
||||
from ..venv import constraint_flags, find_uv, virtualenv
|
||||
from ..venv import constraint_flags, ensure_uv, virtualenv
|
||||
|
||||
|
||||
def get_nuget_args(
|
||||
@@ -272,7 +272,8 @@ def setup_python(
|
||||
build_frontend = "build"
|
||||
|
||||
use_uv = build_frontend == "build[uv]"
|
||||
uv_path = find_uv()
|
||||
if use_uv:
|
||||
ensure_uv()
|
||||
|
||||
log.step("Setting up build environment...")
|
||||
venv_path = tmp / "venv"
|
||||
@@ -323,13 +324,12 @@ def setup_python(
|
||||
env=env,
|
||||
)
|
||||
case "build[uv]":
|
||||
assert uv_path is not None
|
||||
call(
|
||||
uv_path,
|
||||
"uv",
|
||||
"pip",
|
||||
"install",
|
||||
"--upgrade",
|
||||
"build[virtualenv]",
|
||||
"build",
|
||||
*constraint_flags(dependency_constraint),
|
||||
env=env,
|
||||
)
|
||||
|
||||
+14
-9
@@ -1,4 +1,3 @@
|
||||
import contextlib
|
||||
import functools
|
||||
import os
|
||||
import shutil
|
||||
@@ -108,6 +107,7 @@ def virtualenv(
|
||||
assert python.exists()
|
||||
|
||||
if use_uv:
|
||||
ensure_uv()
|
||||
call("uv", "venv", venv_path, "--python", python)
|
||||
else:
|
||||
virtualenv_app, virtualenv_version = _ensure_virtualenv(version)
|
||||
@@ -156,12 +156,17 @@ def virtualenv(
|
||||
return venv_env
|
||||
|
||||
|
||||
def find_uv() -> Path | None:
|
||||
# Prefer uv in our environment
|
||||
with contextlib.suppress(ImportError, FileNotFoundError):
|
||||
from uv import find_uv_bin # noqa: PLC0415
|
||||
def ensure_uv() -> None:
|
||||
"""
|
||||
Ensures uv is available on PATH. Raises an error with a helpful message if not found.
|
||||
|
||||
return Path(find_uv_bin())
|
||||
|
||||
uv_on_path = shutil.which("uv")
|
||||
return Path(uv_on_path) if uv_on_path else None
|
||||
When using build-frontend=build[uv], callers must ensure uv is available
|
||||
on PATH before invoking cibuildwheel.
|
||||
"""
|
||||
if shutil.which("uv") is None:
|
||||
msg = (
|
||||
"uv not found on PATH. When using build-frontend=build[uv], "
|
||||
"ensure uv is installed and available on PATH. "
|
||||
"You can install it with 'pip install uv' or see https://docs.astral.sh/uv/getting-started/installation/"
|
||||
)
|
||||
raise FileNotFoundError(msg)
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ To build Linux, macOS, and Windows wheels using GitHub Actions, create a `.githu
|
||||
`package-dir: .`, `output-dir: wheelhouse` and `config-file: ''`
|
||||
locations (those values are the defaults). You can also pass a
|
||||
comma-separated list of extras to install additional packages.
|
||||
For example, `extras: "uv"` to install UV into the virtual environment.
|
||||
For example, `extras: "uv"` to make uv available for cibuildwheel to use.
|
||||
|
||||
!!! tab "pipx"
|
||||
The GitHub Actions runners have pipx installed, so you can easily build in
|
||||
|
||||
+13
-7
@@ -470,13 +470,19 @@ Default: `build`
|
||||
|
||||
Choose which build frontend to use.
|
||||
|
||||
You can use "build\[uv\]", which will use an external [uv][] everywhere
|
||||
possible, both through `--installer=uv` passed to build, as well as when making
|
||||
all build and test environments. This will generally speed up cibuildwheel.
|
||||
Make sure you have an external uv on Windows and macOS, either by
|
||||
pre-installing it, or installing cibuildwheel with the `uv` extra, which is
|
||||
possible by manually passing `cibuildwheel[uv]` to installers or by using the
|
||||
`extras` option in the [cibuildwheel action](ci-services.md#github-actions).
|
||||
You can use "build\[uv\]", which will use [uv][] everywhere possible, both
|
||||
through `--installer=uv` passed to build, as well as when making all build and
|
||||
test environments. This will generally speed up cibuildwheel.
|
||||
|
||||
When using `build[uv]`, ensure uv is available on PATH. You can do this by:
|
||||
|
||||
- Pre-installing uv (e.g., via `pip install uv` or using `astral-sh/setup-uv`
|
||||
in GitHub Actions)
|
||||
- Installing cibuildwheel with the `uv` extra by manually passing
|
||||
`cibuildwheel[uv]` to installers
|
||||
- Using the `extras: "uv"` option in the [cibuildwheel action](ci-services.md#github-actions),
|
||||
which installs uv in an isolated environment
|
||||
|
||||
uv currently does not support iOS or musllinux on s390x, ppc64le and riscv64.
|
||||
|
||||
On Android and Pyodide, the "pip" frontend is not supported.
|
||||
|
||||
+4
-4
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from collections.abc import Generator
|
||||
|
||||
@@ -11,7 +12,6 @@ from cibuildwheel.ci import detect_ci_provider
|
||||
from cibuildwheel.options import CommandLineArguments, Options
|
||||
from cibuildwheel.selector import EnableGroup
|
||||
from cibuildwheel.typing import PLATFORMS
|
||||
from cibuildwheel.venv import find_uv
|
||||
|
||||
from .utils import DEFAULT_CIBW_ENABLE, EMULATED_ARCHS, get_platform
|
||||
|
||||
@@ -180,10 +180,10 @@ def build_frontend_env(request: pytest.FixtureRequest) -> dict[str, str]:
|
||||
pytest.skip(f"Can't use pip as build frontend for {platform}")
|
||||
if platform == "pyodide" and frontend == "build[uv]":
|
||||
pytest.skip("Can't use uv with pyodide yet")
|
||||
uv_path = find_uv()
|
||||
if uv_path is None and frontend == "build[uv]":
|
||||
uv_available = shutil.which("uv") is not None
|
||||
if not uv_available and frontend == "build[uv]":
|
||||
pytest.skip("Can't find uv, so skipping uv tests")
|
||||
if uv_path is not None and frontend == "build" and platform not in {"android", "ios"}:
|
||||
if uv_available and frontend == "build" and platform not in {"android", "ios"}:
|
||||
pytest.skip("No need to check build when uv is present")
|
||||
|
||||
return {"CIBW_BUILD_FRONTEND": frontend}
|
||||
|
||||
Reference in New Issue
Block a user