diff --git a/README.md b/README.md
index b841e9acd..10f865136 100644
--- a/README.md
+++ b/README.md
@@ -22,25 +22,26 @@ What does it do?
While cibuildwheel itself requires a recent Python version to run (we support the last three releases), it can target the following versions to build wheels:
-| | macOS Intel | macOS Apple Silicon | Windows 64bit | Windows 32bit | Windows Arm64 | manylinux
musllinux x86_64 | manylinux
musllinux i686 | manylinux
musllinux aarch64 | manylinux
musllinux ppc64le | manylinux
musllinux s390x | manylinux
musllinux armv7l | Android | iOS | Pyodide |
-| ------------------ | ----------- | ------------------- | ------------- | ------------- | -------------- | ------------------------------ | ---------------------------- | ------------------------------- | ------------------------------- | ----------------------------- | ------------------------------ | ------- | --- | -------------- |
-| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | N/A | N/A | N/A |
-| CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | N/A | N/A | N/A |
-| CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | N/A | N/A | N/A |
-| CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | N/A | N/A | ✅3 |
-| CPython 3.13 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | ✅ | ✅ | ✅3 |
-| CPython 3.14 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | ✅ | ✅ | N/A |
-| PyPy 3.8 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | ✅1 | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
-| PyPy 3.9 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | ✅1 | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
-| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | ✅1 | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
-| PyPy 3.11 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | ✅1 | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
-| GraalPy 3.11 v24.2 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | N/A | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
-| GraalPy 3.12 v25.0 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | N/A | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
+| | macOS Intel | macOS Apple Silicon | Windows 64bit | Windows 32bit | Windows Arm64 | manylinux
musllinux x86_64 | manylinux
musllinux i686 | manylinux
musllinux aarch64 | manylinux
musllinux ppc64le | manylinux
musllinux s390x | manylinux
musllinux armv7l | Android | iOS | Pyodide |
+| ------------------------ | ----------- | ------------------- | ------------- | ------------- | -------------- | ------------------------------ | ---------------------------- | ------------------------------- | ------------------------------- | ----------------------------- | ------------------------------ | ------- | --- | -------------- |
+| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | N/A | N/A | N/A |
+| CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | N/A | N/A | N/A |
+| CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | N/A | N/A | N/A |
+| CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | N/A | N/A | ✅3 |
+| CPython 3.13 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | ✅ | ✅ | ✅3 |
+| CPython 3.14 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | ✅ | ✅ | N/A |
+| CPython 3.155 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | N/A | N/A | N/A |
+| PyPy 3.9 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | ✅1 | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
+| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | ✅1 | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
+| PyPy 3.11 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | ✅1 | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
+| GraalPy 3.11 v24.2 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | N/A | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
+| GraalPy 3.12 v25.0 | ✅ | ✅ | ✅ | N/A | N/A | ✅1 | N/A | ✅1 | N/A | N/A | N/A | N/A | N/A | N/A |
**1** PyPy & GraalPy are only supported for manylinux wheels.
**2** Windows arm64 support is experimental.
**3** Experimental, not yet supported on PyPI, but can be used directly in web deployment. Use `--platform pyodide` to build.
**4** manylinux armv7l support is experimental. As there are no RHEL based image for this architecture, it's using an Ubuntu based image instead.
+**5** Python 3.15 requires opt-in using [`enable`](https://cibuildwheel.pypa.io/en/stable/options/#enable).
- Builds manylinux, musllinux, macOS, and Windows wheels for CPython, PyPy, and GraalPy
- Works on GitHub Actions, Azure Pipelines, CircleCI, and GitLab CI
diff --git a/cibuildwheel/platforms/macos.py b/cibuildwheel/platforms/macos.py
index 4fe894cf0..d2df5fb19 100644
--- a/cibuildwheel/platforms/macos.py
+++ b/cibuildwheel/platforms/macos.py
@@ -157,6 +157,8 @@ def install_cpython(_tmp: Path, version: str, url: str, free_threading: bool) ->
args = []
if version.startswith("3.14"):
args += ["-applyChoiceChangesXML", str(resources.FREE_THREAD_ENABLE_314.resolve())]
+ elif version.startswith("3.15"):
+ args += ["-applyChoiceChangesXML", str(resources.FREE_THREAD_ENABLE_315.resolve())]
call("sudo", "installer", "-pkg", pkg_path, *args, "-target", "/")
pkg_path.unlink()
env = os.environ.copy()
diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml
index 03abceff1..b7ebf6eaf 100644
--- a/cibuildwheel/resources/build-platforms.toml
+++ b/cibuildwheel/resources/build-platforms.toml
@@ -7,6 +7,8 @@ python_configurations = [
{ identifier = "cp313-manylinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-manylinux_x86_64", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-manylinux_x86_64", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-manylinux_x86_64", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-manylinux_x86_64", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-manylinux_i686", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-manylinux_i686", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-manylinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -14,6 +16,8 @@ python_configurations = [
{ identifier = "cp313-manylinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-manylinux_i686", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-manylinux_i686", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-manylinux_i686", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-manylinux_i686", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "pp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
{ identifier = "pp310-manylinux_x86_64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
{ identifier = "pp311-manylinux_x86_64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" },
@@ -26,6 +30,8 @@ python_configurations = [
{ identifier = "cp313-manylinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-manylinux_aarch64", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-manylinux_aarch64", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-manylinux_aarch64", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-manylinux_aarch64", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-manylinux_ppc64le", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-manylinux_ppc64le", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-manylinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -33,6 +39,8 @@ python_configurations = [
{ identifier = "cp313-manylinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-manylinux_ppc64le", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-manylinux_ppc64le", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-manylinux_ppc64le", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-manylinux_ppc64le", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-manylinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-manylinux_s390x", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-manylinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -40,6 +48,8 @@ python_configurations = [
{ identifier = "cp313-manylinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-manylinux_s390x", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-manylinux_s390x", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-manylinux_s390x", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-manylinux_s390x", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-manylinux_armv7l", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-manylinux_armv7l", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-manylinux_armv7l", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -47,6 +57,8 @@ python_configurations = [
{ identifier = "cp313-manylinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-manylinux_armv7l", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-manylinux_armv7l", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-manylinux_armv7l", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-manylinux_armv7l", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-manylinux_riscv64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-manylinux_riscv64", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-manylinux_riscv64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -54,6 +66,8 @@ python_configurations = [
{ identifier = "cp313-manylinux_riscv64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-manylinux_riscv64", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-manylinux_riscv64", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-manylinux_riscv64", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-manylinux_riscv64", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "pp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
{ identifier = "pp310-manylinux_aarch64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
{ identifier = "pp311-manylinux_aarch64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" },
@@ -69,6 +83,8 @@ python_configurations = [
{ identifier = "cp313-musllinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-musllinux_x86_64", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-musllinux_x86_64", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-musllinux_x86_64", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-musllinux_x86_64", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-musllinux_i686", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-musllinux_i686", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-musllinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -76,6 +92,8 @@ python_configurations = [
{ identifier = "cp313-musllinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-musllinux_i686", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-musllinux_i686", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-musllinux_i686", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-musllinux_i686", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-musllinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-musllinux_aarch64", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-musllinux_aarch64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -83,6 +101,8 @@ python_configurations = [
{ identifier = "cp313-musllinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-musllinux_aarch64", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-musllinux_aarch64", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-musllinux_aarch64", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-musllinux_aarch64", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-musllinux_ppc64le", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-musllinux_ppc64le", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-musllinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -90,6 +110,8 @@ python_configurations = [
{ identifier = "cp313-musllinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-musllinux_ppc64le", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-musllinux_ppc64le", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-musllinux_ppc64le", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-musllinux_ppc64le", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-musllinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-musllinux_s390x", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-musllinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -97,6 +119,8 @@ python_configurations = [
{ identifier = "cp313-musllinux_s390x", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-musllinux_s390x", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-musllinux_s390x", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-musllinux_s390x", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-musllinux_s390x", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-musllinux_armv7l", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-musllinux_armv7l", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-musllinux_armv7l", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -104,6 +128,8 @@ python_configurations = [
{ identifier = "cp313-musllinux_armv7l", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-musllinux_armv7l", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-musllinux_armv7l", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-musllinux_armv7l", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-musllinux_armv7l", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
{ identifier = "cp39-musllinux_riscv64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp310-musllinux_riscv64", version = "3.10", path_str = "/opt/python/cp310-cp310" },
{ identifier = "cp311-musllinux_riscv64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
@@ -111,6 +137,8 @@ python_configurations = [
{ identifier = "cp313-musllinux_riscv64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
{ identifier = "cp314-musllinux_riscv64", version = "3.14", path_str = "/opt/python/cp314-cp314" },
{ identifier = "cp314t-musllinux_riscv64", version = "3.14", path_str = "/opt/python/cp314-cp314t" },
+ { identifier = "cp315-musllinux_riscv64", version = "3.15", path_str = "/opt/python/cp315-cp315" },
+ { identifier = "cp315t-musllinux_riscv64", version = "3.15", path_str = "/opt/python/cp315-cp315t" },
]
[macos]
@@ -136,6 +164,12 @@ python_configurations = [
{ identifier = "cp314t-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.4/python-3.14.4-macos11.pkg" },
{ identifier = "cp314t-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.4/python-3.14.4-macos11.pkg" },
{ identifier = "cp314t-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.4/python-3.14.4-macos11.pkg" },
+ { identifier = "cp315-macosx_x86_64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b1-macos11.pkg" },
+ { identifier = "cp315-macosx_arm64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b1-macos11.pkg" },
+ { identifier = "cp315-macosx_universal2", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b1-macos11.pkg" },
+ { identifier = "cp315t-macosx_x86_64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b1-macos11.pkg" },
+ { identifier = "cp315t-macosx_arm64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b1-macos11.pkg" },
+ { identifier = "cp315t-macosx_universal2", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b1-macos11.pkg" },
{ identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" },
{ identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" },
{ identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_x86_64.tar.bz2" },
@@ -164,6 +198,10 @@ python_configurations = [
{ identifier = "cp314t-win32", version = "3.14.4" },
{ identifier = "cp314-win_amd64", version = "3.14.4" },
{ identifier = "cp314t-win_amd64", version = "3.14.4" },
+ { identifier = "cp315-win32", version = "3.15.0-b1" },
+ { identifier = "cp315t-win32", version = "3.15.0-b1" },
+ { identifier = "cp315-win_amd64", version = "3.15.0-b1" },
+ { identifier = "cp315t-win_amd64", version = "3.15.0-b1" },
{ identifier = "cp39-win_arm64", version = "3.9.10" },
{ identifier = "cp310-win_arm64", version = "3.10.11" },
{ identifier = "cp311-win_arm64", version = "3.11.9" },
@@ -171,6 +209,8 @@ python_configurations = [
{ identifier = "cp313-win_arm64", version = "3.13.13" },
{ identifier = "cp314-win_arm64", version = "3.14.4" },
{ identifier = "cp314t-win_arm64", version = "3.14.4" },
+ { identifier = "cp315-win_arm64", version = "3.15.0-b1" },
+ { identifier = "cp315t-win_arm64", version = "3.15.0-b1" },
{ identifier = "pp39-win_amd64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" },
{ identifier = "pp310-win_amd64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip" },
{ identifier = "pp311-win_amd64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.22-win64.zip" },
diff --git a/cibuildwheel/resources/constraints-python315.txt b/cibuildwheel/resources/constraints-python315.txt
new file mode 100644
index 000000000..84bd6213b
--- /dev/null
+++ b/cibuildwheel/resources/constraints-python315.txt
@@ -0,0 +1,34 @@
+# This file was autogenerated by uv via the following command:
+# nox -s update_constraints
+altgraph==0.17.5
+ # via macholib
+build==1.5.0
+ # via -r cibuildwheel/resources/constraints.in
+delocate==0.13.0
+ # via -r cibuildwheel/resources/constraints.in
+distlib==0.4.0
+ # via virtualenv
+filelock==3.29.0
+ # via
+ # python-discovery
+ # virtualenv
+macholib==1.16.4
+ # via delocate
+packaging==26.2
+ # via
+ # build
+ # delocate
+pip==26.1
+ # via -r cibuildwheel/resources/constraints.in
+platformdirs==4.9.6
+ # via
+ # python-discovery
+ # virtualenv
+pyproject-hooks==1.2.0
+ # via build
+python-discovery==1.2.2
+ # via virtualenv
+typing-extensions==4.15.0
+ # via delocate
+virtualenv==21.3.0
+ # via -r cibuildwheel/resources/constraints.in
diff --git a/cibuildwheel/resources/free-threaded-enable-315.xml b/cibuildwheel/resources/free-threaded-enable-315.xml
new file mode 100644
index 000000000..9a0d5d9f1
--- /dev/null
+++ b/cibuildwheel/resources/free-threaded-enable-315.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ attributeSetting
+ 1
+ choiceAttribute
+ selected
+ choiceIdentifier
+ org.python.Python.PythonTFramework-3.15
+
+
+
diff --git a/cibuildwheel/resources/pinned_docker_images.cfg b/cibuildwheel/resources/pinned_docker_images.cfg
index 2b1b9ef25..fda748e12 100644
--- a/cibuildwheel/resources/pinned_docker_images.cfg
+++ b/cibuildwheel/resources/pinned_docker_images.cfg
@@ -1,54 +1,54 @@
[x86_64]
-manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.05.02-2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.05.02-2
-manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.05.02-2
-musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2026.05.02-2
+manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.05.07-2
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.05.07-2
+manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.05.07-2
+musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2026.05.07-2
[i686]
-manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.05.02-2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.05.02-2
-manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.05.02-2
-musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2026.05.02-2
+manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.05.07-2
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.05.07-2
+manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.05.07-2
+musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2026.05.07-2
[aarch64]
-manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.05.02-2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.05.02-2
-manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.05.02-2
-musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2026.05.02-2
+manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.05.07-2
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.05.07-2
+manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.05.07-2
+musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2026.05.07-2
[ppc64le]
-manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2026.05.02-2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2026.05.02-2
-manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2026.05.02-2
-musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2026.05.02-2
+manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2026.05.07-2
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2026.05.07-2
+manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2026.05.07-2
+musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2026.05.07-2
[s390x]
-manylinux2014 = quay.io/pypa/manylinux2014_s390x:2026.05.02-2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2026.05.02-2
-manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2026.05.02-2
-musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2026.05.02-2
+manylinux2014 = quay.io/pypa/manylinux2014_s390x:2026.05.07-2
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2026.05.07-2
+manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2026.05.07-2
+musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2026.05.07-2
[pypy_x86_64]
-manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.05.02-2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.05.02-2
-manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.05.02-2
+manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.05.07-2
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.05.07-2
+manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.05.07-2
[pypy_i686]
-manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.05.02-2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.05.02-2
-manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.05.02-2
+manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.05.07-2
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.05.07-2
+manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.05.07-2
[pypy_aarch64]
-manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.05.02-2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.05.02-2
-manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.05.02-2
+manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.05.07-2
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.05.07-2
+manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.05.07-2
[armv7l]
-manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2026.05.02-2
-manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l:2026.05.02-2
-musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2026.05.02-2
+manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2026.05.07-2
+manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l:2026.05.07-2
+musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2026.05.07-2
[riscv64]
-manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2026.05.02-2
-musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2026.05.02-2
+manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2026.05.07-2
+musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2026.05.07-2
diff --git a/cibuildwheel/util/resources.py b/cibuildwheel/util/resources.py
index d06fc058d..37775b188 100644
--- a/cibuildwheel/util/resources.py
+++ b/cibuildwheel/util/resources.py
@@ -8,6 +8,7 @@
PATH: Final[Path] = Path(__file__).parent.parent / "resources"
INSTALL_CERTIFI_SCRIPT: Final[Path] = PATH / "install_certifi.py"
FREE_THREAD_ENABLE_314: Final[Path] = PATH / "free-threaded-enable-314.xml"
+FREE_THREAD_ENABLE_315: Final[Path] = PATH / "free-threaded-enable-315.xml"
NODEJS: Final[Path] = PATH / "nodejs.toml"
DEFAULTS: Final[Path] = PATH / "defaults.toml"
PINNED_DOCKER_IMAGES: Final[Path] = PATH / "pinned_docker_images.cfg"
diff --git a/docs/options.md b/docs/options.md
index 9ffc706b5..f9f7d0f84 100644
--- a/docs/options.md
+++ b/docs/options.md
@@ -60,6 +60,7 @@ When setting the options, you can use shell-style globbing syntax, as per [fnmat
| Python 3.12 | cp312-macosx_x86_64
cp312-macosx_universal2
cp312-macosx_arm64 | cp312-win_amd64
cp312-win32
cp312-win_arm64 | cp312-manylinux_x86_64
cp312-manylinux_i686
cp312-musllinux_x86_64
cp312-musllinux_i686 | cp312-manylinux_aarch64
cp312-manylinux_ppc64le
cp312-manylinux_s390x
cp312-manylinux_armv7l
cp312-manylinux_riscv64
cp312-musllinux_aarch64
cp312-musllinux_ppc64le
cp312-musllinux_s390x
cp312-musllinux_armv7l
cp312-musllinux_riscv64 | | | cp312-pyodide_wasm32 |
| Python 3.13 | cp313-macosx_x86_64
cp313-macosx_universal2
cp313-macosx_arm64 | cp313-win_amd64
cp313-win32
cp313-win_arm64 | cp313-manylinux_x86_64
cp313-manylinux_i686
cp313-musllinux_x86_64
cp313-musllinux_i686 | cp313-manylinux_aarch64
cp313-manylinux_ppc64le
cp313-manylinux_s390x
cp313-manylinux_armv7l
cp313-manylinux_riscv64
cp313-musllinux_aarch64
cp313-musllinux_ppc64le
cp313-musllinux_s390x
cp313-musllinux_armv7l
cp313-musllinux_riscv64 | cp313-android_arm64_v8a
cp313-android_x86_64 | cp313-ios_arm64_iphoneos
cp313-ios_arm64_iphonesimulator
cp313-ios_x86_64_iphonesimulator | cp313-pyodide_wasm32 |
| Python 3.14 | cp314-macosx_x86_64
cp314-macosx_universal2
cp314-macosx_arm64
cp314t-macosx_x86_64
cp314t-macosx_universal2
cp314t-macosx_arm64 | cp314-win_amd64
cp314-win32
cp314-win_arm64
cp314t-win_amd64
cp314t-win32
cp314t-win_arm64 | cp314-manylinux_x86_64
cp314-manylinux_i686
cp314-musllinux_x86_64
cp314-musllinux_i686
cp314t-manylinux_x86_64
cp314t-manylinux_i686
cp314t-musllinux_x86_64
cp314t-musllinux_i686 | cp314-manylinux_aarch64
cp314-manylinux_ppc64le
cp314-manylinux_s390x
cp314-manylinux_armv7l
cp314-manylinux_riscv64
cp314-musllinux_aarch64
cp314-musllinux_ppc64le
cp314-musllinux_s390x
cp314-musllinux_armv7l
cp314-musllinux_riscv64
cp314t-manylinux_aarch64
cp314t-manylinux_ppc64le
cp314t-manylinux_s390x
cp314t-manylinux_armv7l
cp314t-manylinux_riscv64
cp314t-musllinux_aarch64
cp314t-musllinux_ppc64le
cp314t-musllinux_s390x
cp314t-musllinux_armv7l
cp314t-musllinux_riscv64 | cp314-android_arm64_v8a
cp314-android_x86_64 | cp314-ios_arm64_iphoneos
cp314-ios_arm64_iphonesimulator
cp314-ios_x86_64_iphonesimulator | |
+| Python 3.15 | cp315-macosx_x86_64
cp315-macosx_universal2
cp315-macosx_arm64
cp315t-macosx_x86_64
cp315t-macosx_universal2
cp315t-macosx_arm64 | cp315-win_amd64
cp315-win32
cp315-win_arm64
cp315t-win_amd64
cp315t-win32
cp315t-win_arm64 | cp315-manylinux_x86_64
cp315-manylinux_i686
cp315-musllinux_x86_64
cp315-musllinux_i686
cp315t-manylinux_x86_64
cp315t-manylinux_i686
cp315t-musllinux_x86_64
cp315t-musllinux_i686 | cp315-manylinux_aarch64
cp315-manylinux_ppc64le
cp315-manylinux_s390x
cp315-manylinux_armv7l
cp315-manylinux_riscv64
cp315-musllinux_aarch64
cp315-musllinux_ppc64le
cp315-musllinux_s390x
cp315-musllinux_armv7l
cp315-musllinux_riscv64
cp315t-manylinux_aarch64
cp315t-manylinux_ppc64le
cp315t-manylinux_s390x
cp315t-manylinux_armv7l
cp315t-manylinux_riscv64
cp315t-musllinux_aarch64
cp315t-musllinux_ppc64le
cp315t-musllinux_s390x
cp315t-musllinux_armv7l
cp315t-musllinux_riscv64 | cp315-android_arm64_v8a
cp315-android_x86_64 | cp315-ios_arm64_iphoneos
cp315-ios_arm64_iphonesimulator
cp315-ios_x86_64_iphonesimulator | |
| PyPy3.9 v7.3 | pp39-macosx_x86_64
pp39-macosx_arm64 | pp39-win_amd64 | pp39-manylinux_x86_64
pp39-manylinux_i686 | pp39-manylinux_aarch64 | | | |
| PyPy3.10 v7.3 | pp310-macosx_x86_64
pp310-macosx_arm64 | pp310-win_amd64 | pp310-manylinux_x86_64
pp310-manylinux_i686 | pp310-manylinux_aarch64 | | | |
| PyPy3.11 v7.3 | pp311-macosx_x86_64
pp311-macosx_arm64 | pp311-win_amd64 | pp311-manylinux_x86_64
pp311-manylinux_i686 | pp311-manylinux_aarch64 | | | |
diff --git a/noxfile.py b/noxfile.py
index 738ad3722..319f1b915 100755
--- a/noxfile.py
+++ b/noxfile.py
@@ -79,7 +79,7 @@ def update_constraints(session: nox.Session) -> None:
env = os.environ.copy()
env["UV_CUSTOM_COMPILE_COMMAND"] = f"nox -s {session.name}"
- for minor_version in range(9, 15):
+ for minor_version in range(9, 16):
python_version = f"3.{minor_version}"
output_file = resources / f"constraints-python{python_version.replace('.', '')}.txt"
session.run(
@@ -94,7 +94,7 @@ def update_constraints(session: nox.Session) -> None:
)
shutil.copyfile(
- resources / "constraints-python314.txt",
+ resources / "constraints-python315.txt",
resources / "constraints.txt",
)
diff --git a/test/utils.py b/test/utils.py
index f90ae927f..209b7f5d3 100644
--- a/test/utils.py
+++ b/test/utils.py
@@ -292,7 +292,10 @@ def _expected_wheels(
enable_groups = get_enable_groups()
if EnableGroup.CPythonPrerelease in enable_groups:
- ... # Add cp315 here when available
+ python_abi_tags += [
+ "cp315-cp315",
+ "cp315-cp315t",
+ ]
if EnableGroup.PyPyEoL in enable_groups:
python_abi_tags += [