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