diff --git a/README.md b/README.md
index 12585957..6a955ad5 100644
--- a/README.md
+++ b/README.md
@@ -22,25 +22,24 @@ 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 | ✅ | ✅ | ✅ |
-| CPython 3.14 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | ✅ | ✅ | ✅ |
-| CPython 3.155 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | ✅ | ✅ | ✅ |
-| 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.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 | ✅ | ✅ | ✅ |
+| CPython 3.14 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | ✅ | ✅ | ✅ |
+| CPython 3.15 | ✅ | ✅ | ✅ | ✅ | ✅2 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅4 | ✅ | ✅ | ✅ |
+| 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.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** Not supported on PyPI, uses old `pyodide` tag instead of `pyemscripten`. Requires `pyodide-eol` [`enable`](https://cibuildwheel.pypa.io/en/stable/options/#enable).
**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, Windows, pyemscripten, iOS, and Android wheels
- Supports CPython, PyPy, and GraalPy
diff --git a/cibuildwheel/selector.py b/cibuildwheel/selector.py
index 2a8892dd..d710de9d 100644
--- a/cibuildwheel/selector.py
+++ b/cibuildwheel/selector.py
@@ -92,7 +92,7 @@ class BuildSelector:
return False
# filter out groups that are not enabled
- if EnableGroup.CPythonPrerelease not in self.enable and fnmatch(build_id, "cp315*"):
+ if EnableGroup.CPythonPrerelease not in self.enable and fnmatch(build_id, "cp316*"):
return False
is_pypy_eol = fnmatch(build_id, "pp3?-*") or fnmatch(build_id, "pp310-*")
is_pypy = fnmatch(build_id, "pp*") and not is_pypy_eol
diff --git a/test/utils.py b/test/utils.py
index e0131bb9..eeaa212b 100644
--- a/test/utils.py
+++ b/test/utils.py
@@ -278,20 +278,18 @@ def _expected_wheels(
# To be kept in sync with Python versions for Pyodide identifiers in cibuildwheel/selector.py.
if platform == "pyodide" and python_abi_tags is None:
- python_abi_tags = ["cp313-cp313", "cp314-cp314"]
+ python_abi_tags = ["cp313-cp313", "cp314-cp314", "cp315-cp315"]
if EnableGroup.PyodideEoL in enable_groups:
python_abi_tags.insert(0, "cp312-cp312")
- if EnableGroup.CPythonPrerelease in enable_groups:
- python_abi_tags.append("cp315-cp315")
- elif (platform == "android" and python_abi_tags is None) or (
- platform == "ios" and python_abi_tags is None
- ):
+ elif platform in {"android", "ios"} and python_abi_tags is None:
python_abi_tags = [
"cp313-cp313",
"cp314-cp314",
+ "cp315-cp315",
]
if EnableGroup.CPythonPrerelease in enable_groups:
- python_abi_tags += ["cp315-cp315"]
+ # python_abi_tags += ["cp316-cp316"]
+ ... # Add cp316 here when available
elif python_abi_tags is None:
python_abi_tags = [
"cp39-cp39",
@@ -301,13 +299,16 @@ def _expected_wheels(
"cp313-cp313",
"cp314-cp314",
"cp314-cp314t",
+ "cp315-cp315",
+ "cp315-cp315t",
]
if EnableGroup.CPythonPrerelease in enable_groups:
- python_abi_tags += [
- "cp315-cp315",
- "cp315-cp315t",
- ]
+ # python_abi_tags += [
+ # "cp316-cp316",
+ # "cp316-cp316t",
+ # ]
+ ... # Add cp316 here when available
if EnableGroup.PyPyEoL in enable_groups:
python_abi_tags += [
diff --git a/unit_test/build_selector_test.py b/unit_test/build_selector_test.py
index 134125c1..c5431db0 100644
--- a/unit_test/build_selector_test.py
+++ b/unit_test/build_selector_test.py
@@ -16,6 +16,7 @@ def test_build() -> None:
assert build_selector("cp312-manylinux_x86_64")
assert build_selector("cp313-manylinux_x86_64")
assert build_selector("cp314-manylinux_x86_64")
+ assert build_selector("cp315-manylinux_x86_64")
assert build_selector("pp311-manylinux_x86_64")
assert build_selector("cp36-manylinux_i686")
assert build_selector("cp37-manylinux_i686")
@@ -37,6 +38,7 @@ def test_build() -> None:
assert build_selector("cp312-win_amd64")
assert build_selector("cp313-win_amd64")
assert build_selector("cp314-win_amd64")
+ assert build_selector("cp315-win_amd64")
assert not build_selector("pp310-win_amd64")
assert not build_selector("pp311-win_amd64")
@@ -100,7 +102,7 @@ def test_build_filter_pyodide() -> None:
assert build_selector("cp313-pyodide_wasm32")
assert build_selector("cp314-pyodide_wasm32")
assert not build_selector("cp312-pyodide_wasm32")
- assert not build_selector("cp315-pyodide_wasm32")
+ assert build_selector("cp315-pyodide_wasm32")
def test_build_filter_pyodide_eol() -> None:
@@ -112,7 +114,7 @@ def test_build_filter_pyodide_eol() -> None:
assert build_selector("cp312-pyodide_wasm32")
assert build_selector("cp313-pyodide_wasm32")
assert build_selector("cp314-pyodide_wasm32")
- assert not build_selector("cp315-pyodide_wasm32")
+ assert build_selector("cp315-pyodide_wasm32")
def test_skip() -> None:
diff --git a/unit_test/linux_build_steps_test.py b/unit_test/linux_build_steps_test.py
index b93530be..dd6200ab 100644
--- a/unit_test/linux_build_steps_test.py
+++ b/unit_test/linux_build_steps_test.py
@@ -97,9 +97,11 @@ def test_linux_container_split(tmp_path: Path, monkeypatch: pytest.MonkeyPatch)
"cp313-manylinux_x86_64",
"cp314-manylinux_x86_64",
"cp314t-manylinux_x86_64",
+ "cp315-manylinux_x86_64",
+ "cp315t-manylinux_x86_64",
]
- assert before_alls(build_steps[3]) == [""] * 4
- assert container_engines(build_steps[3]) == [default_container_engine] * 4
+ assert before_alls(build_steps[3]) == [""] * 6
+ assert container_engines(build_steps[3]) == [default_container_engine] * 6
def test_package_dir_outside_working_directory_raises_configuration_error(
diff --git a/unit_test/option_prepare_test.py b/unit_test/option_prepare_test.py
index 5bad4d28..b277c8c4 100644
--- a/unit_test/option_prepare_test.py
+++ b/unit_test/option_prepare_test.py
@@ -13,7 +13,7 @@ from cibuildwheel.__main__ import main
from cibuildwheel.oci_container import OCIPlatform
from cibuildwheel.util import file
-DEFAULT_IDS = {"cp39", "cp310", "cp311", "cp312", "cp313", "cp314", "cp314t"}
+DEFAULT_IDS = {"cp39", "cp310", "cp311", "cp312", "cp313", "cp314", "cp314t", "cp315", "cp315t"}
ALL_IDS = DEFAULT_IDS | {"pp39", "pp310", "pp311", "gp312_250"}
@@ -155,6 +155,8 @@ before-all = "true"
"cp313",
"cp314",
"cp314t",
+ "cp315",
+ "cp315t",
"pp39",
"pp310",
"pp311",
@@ -176,6 +178,8 @@ before-all = "true"
"cp313",
"cp314",
"cp314t",
+ "cp315",
+ "cp315t",
"pp39",
"pp310",
"pp311",