From 87bcefeb4376bd5514a61f7d4806b9334cc02c50 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 6 Apr 2026 18:41:19 +0530 Subject: [PATCH 01/19] Use `pyodide config get emscripten_dir` --- cibuildwheel/platforms/pyodide.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/cibuildwheel/platforms/pyodide.py b/cibuildwheel/platforms/pyodide.py index e0560b4a0..21d7b04a8 100644 --- a/cibuildwheel/platforms/pyodide.py +++ b/cibuildwheel/platforms/pyodide.py @@ -94,20 +94,19 @@ def ensure_node(major_version: str) -> Path: return path -def install_emscripten( - env: dict[str, str], version: str, xbuildenv_cache_path: Path, pyodide_version: str -) -> Path: +def install_emscripten(env: dict[str, str], version: str, xbuildenv_cache_path: Path) -> Path: """Install Emscripten via pyodide-build, which also applies Pyodide-specific patches.""" - emcc_path = ( - xbuildenv_cache_path / pyodide_version / "emsdk" / "upstream" / "emscripten" / "emcc" + emscripten_dir = Path( + call("pyodide", "config", "get", "emscripten_dir", env=env, capture_stdout=True).strip() ) with FileLock(CIBW_CACHE_PATH / "emscripten.lock"): - if emcc_path.exists(): - return emcc_path + if emscripten_dir.exists(): + return emscripten_dir call( "pyodide", "xbuildenv", "install-emscripten", + "--force", "--version", version, "--path", @@ -115,8 +114,8 @@ def install_emscripten( env=env, cwd=CIBW_CACHE_PATH, ) - assert emcc_path.exists() - return emcc_path + assert emscripten_dir.exists() + return emscripten_dir def get_all_xbuildenv_version_info(env: dict[str, str]) -> list[PyodideXBuildEnvInfo]: @@ -315,9 +314,9 @@ def setup_python( log.step( f"Installing Emscripten {emscripten_version} and applying Pyodide-specific patches ..." ) - emcc_path = install_emscripten(env, emscripten_version, xbuildenv_cache_path, pyodide_version) + emscripten_dir = install_emscripten(env, emscripten_version, xbuildenv_cache_path) - env["PATH"] = os.pathsep.join([str(emcc_path.parent), env["PATH"]]) + env["PATH"] = os.pathsep.join([str(emscripten_dir), env["PATH"]]) return env From 17679b8e8fadd340ba51a993bbd8f79ff5d57352 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 6 Apr 2026 18:41:53 +0530 Subject: [PATCH 02/19] Update constraints --- cibuildwheel/resources/constraints-pyodide312.txt | 14 +++++++------- cibuildwheel/resources/constraints-pyodide313.txt | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cibuildwheel/resources/constraints-pyodide312.txt b/cibuildwheel/resources/constraints-pyodide312.txt index 693f4602e..96fd519f4 100644 --- a/cibuildwheel/resources/constraints-pyodide312.txt +++ b/cibuildwheel/resources/constraints-pyodide312.txt @@ -2,15 +2,15 @@ # nox -s update_constraints annotated-types==0.7.0 # via pydantic -auditwheel-emscripten==0.2.3 +auditwheel-emscripten==0.2.4 # via pyodide-build -build==1.2.2.post1 +build==1.4.2 # via # -r .nox/update_constraints/tmp/constraints-pyodide.in # pyodide-build certifi==2026.2.25 # via requests -charset-normalizer==3.4.6 +charset-normalizer==3.4.7 # via requests click==8.1.8 # via @@ -50,9 +50,9 @@ pydantic==2.12.5 # pyodide-lock pydantic-core==2.41.5 # via pydantic -pygments==2.19.2 +pygments==2.20.0 # via rich -pyodide-build==0.33.0 +pyodide-build==0.34.1 # via -r .nox/update_constraints/tmp/constraints-pyodide.in pyodide-cli==0.5.0 # via @@ -62,9 +62,9 @@ pyodide-lock==0.1.2 # via pyodide-build pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv -requests==2.32.5 +requests==2.33.1 # via pyodide-build rich==14.3.3 # via diff --git a/cibuildwheel/resources/constraints-pyodide313.txt b/cibuildwheel/resources/constraints-pyodide313.txt index 693f4602e..96fd519f4 100644 --- a/cibuildwheel/resources/constraints-pyodide313.txt +++ b/cibuildwheel/resources/constraints-pyodide313.txt @@ -2,15 +2,15 @@ # nox -s update_constraints annotated-types==0.7.0 # via pydantic -auditwheel-emscripten==0.2.3 +auditwheel-emscripten==0.2.4 # via pyodide-build -build==1.2.2.post1 +build==1.4.2 # via # -r .nox/update_constraints/tmp/constraints-pyodide.in # pyodide-build certifi==2026.2.25 # via requests -charset-normalizer==3.4.6 +charset-normalizer==3.4.7 # via requests click==8.1.8 # via @@ -50,9 +50,9 @@ pydantic==2.12.5 # pyodide-lock pydantic-core==2.41.5 # via pydantic -pygments==2.19.2 +pygments==2.20.0 # via rich -pyodide-build==0.33.0 +pyodide-build==0.34.1 # via -r .nox/update_constraints/tmp/constraints-pyodide.in pyodide-cli==0.5.0 # via @@ -62,9 +62,9 @@ pyodide-lock==0.1.2 # via pyodide-build pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv -requests==2.32.5 +requests==2.33.1 # via pyodide-build rich==14.3.3 # via From 2df97d124c20a7a3210603fa378131bdc6bec37b Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 6 Apr 2026 18:52:19 +0530 Subject: [PATCH 03/19] Updates for `pyemscripten` platform tag --- test/test_pyodide.py | 10 +++++----- test/utils.py | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/test_pyodide.py b/test/test_pyodide.py index 45355ad5c..4538f73ef 100644 --- a/test/test_pyodide.py +++ b/test/test_pyodide.py @@ -79,8 +79,8 @@ def test_pyodide_build(tmp_path: Path, use_pyproject_toml: bool) -> None: # check that the expected wheels are produced expected_wheels = [ - "spam-0.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", - "spam-0.1.0-cp313-cp313-pyodide_2025_0_wasm32.whl", + "spam-0.1.0-cp312-cp312-pyemscripten_2024_0_wasm32.whl", + "spam-0.1.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", ] print("actual_wheels", actual_wheels) @@ -144,8 +144,8 @@ def test_filter() -> None: ) # check that the expected wheels are produced expected_wheels = [ - "spam-0.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", - "spam-0.1.0-cp313-cp313-pyodide_2025_0_wasm32.whl", + "spam-0.1.0-cp312-cp312-pyemscripten_2024_0_wasm32.whl", + "spam-0.1.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", ] assert set(actual_wheels) == set(expected_wheels) @@ -170,6 +170,6 @@ def test_pyodide_repair_wheel(tmp_path: Path) -> None: # check that the expected wheels are produced expected_wheels = [ - "spam-0.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", + "spam-0.1.0-cp312-cp312-pyemscripten_2024_0_wasm32.whl", ] assert set(actual_wheels) == set(expected_wheels) diff --git a/test/utils.py b/test/utils.py index dc04640fa..68a761bf8 100644 --- a/test/utils.py +++ b/test/utils.py @@ -414,14 +414,14 @@ def _expected_wheels( elif platform == "pyodide": platform_tags = { - "cp312-cp312": ["pyodide_2024_0_wasm32"], - "cp313-cp313": ["pyodide_2025_0_wasm32"], + "cp312-cp312": ["pyemscripten_2024_0_wasm32"], + "cp313-cp313": ["pyemscripten_2025_0_wasm32"], }.get(python_abi_tag, []) if not platform_tags: # for example if the python tag is `none` or `abi3`, all # platform tags are built with that python tag - platform_tags = ["pyodide_2024_0_wasm32"] + platform_tags = ["pyemscripten_2024_0_wasm32"] else: msg = f"Unsupported platform {platform!r}" From 4bd785de872269c0b27362ee800f17288b2b4789 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 6 Apr 2026 20:28:16 +0530 Subject: [PATCH 04/19] Weird constraints stuff... --- cibuildwheel/resources/constraints-python310.txt | 6 +++--- cibuildwheel/resources/constraints-python311.txt | 4 ++-- cibuildwheel/resources/constraints-python312.txt | 4 ++-- cibuildwheel/resources/constraints-python313.txt | 4 ++-- cibuildwheel/resources/constraints-python314.txt | 4 ++-- cibuildwheel/resources/constraints-python38.txt | 4 ++-- cibuildwheel/resources/constraints-python39.txt | 6 +++--- cibuildwheel/resources/constraints.txt | 4 ++-- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cibuildwheel/resources/constraints-python310.txt b/cibuildwheel/resources/constraints-python310.txt index b4a1cc832..a01a3addb 100644 --- a/cibuildwheel/resources/constraints-python310.txt +++ b/cibuildwheel/resources/constraints-python310.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.0 +build==1.4.2 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -28,9 +28,9 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv -tomli==2.4.0 +tomli==2.4.1 # via build typing-extensions==4.15.0 # via diff --git a/cibuildwheel/resources/constraints-python311.txt b/cibuildwheel/resources/constraints-python311.txt index cfe88baae..cb5e1ebe1 100644 --- a/cibuildwheel/resources/constraints-python311.txt +++ b/cibuildwheel/resources/constraints-python311.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.0 +build==1.4.2 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv typing-extensions==4.15.0 # via delocate diff --git a/cibuildwheel/resources/constraints-python312.txt b/cibuildwheel/resources/constraints-python312.txt index cfe88baae..cb5e1ebe1 100644 --- a/cibuildwheel/resources/constraints-python312.txt +++ b/cibuildwheel/resources/constraints-python312.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.0 +build==1.4.2 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv typing-extensions==4.15.0 # via delocate diff --git a/cibuildwheel/resources/constraints-python313.txt b/cibuildwheel/resources/constraints-python313.txt index cfe88baae..cb5e1ebe1 100644 --- a/cibuildwheel/resources/constraints-python313.txt +++ b/cibuildwheel/resources/constraints-python313.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.0 +build==1.4.2 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv typing-extensions==4.15.0 # via delocate diff --git a/cibuildwheel/resources/constraints-python314.txt b/cibuildwheel/resources/constraints-python314.txt index cfe88baae..cb5e1ebe1 100644 --- a/cibuildwheel/resources/constraints-python314.txt +++ b/cibuildwheel/resources/constraints-python314.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.0 +build==1.4.2 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv typing-extensions==4.15.0 # via delocate diff --git a/cibuildwheel/resources/constraints-python38.txt b/cibuildwheel/resources/constraints-python38.txt index 58fc349d5..5b2c13ad3 100644 --- a/cibuildwheel/resources/constraints-python38.txt +++ b/cibuildwheel/resources/constraints-python38.txt @@ -28,9 +28,9 @@ platformdirs==4.3.6 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv -tomli==2.4.0 +tomli==2.4.1 # via build typing-extensions==4.13.2 # via diff --git a/cibuildwheel/resources/constraints-python39.txt b/cibuildwheel/resources/constraints-python39.txt index 74ae43386..66d2377fb 100644 --- a/cibuildwheel/resources/constraints-python39.txt +++ b/cibuildwheel/resources/constraints-python39.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.0 +build==1.4.2 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -28,9 +28,9 @@ platformdirs==4.4.0 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv -tomli==2.4.0 +tomli==2.4.1 # via build typing-extensions==4.15.0 # via diff --git a/cibuildwheel/resources/constraints.txt b/cibuildwheel/resources/constraints.txt index cfe88baae..cb5e1ebe1 100644 --- a/cibuildwheel/resources/constraints.txt +++ b/cibuildwheel/resources/constraints.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.0 +build==1.4.2 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.0 +python-discovery==1.2.1 # via virtualenv typing-extensions==4.15.0 # via delocate From 499e9657f8ca81883ecb2de55efb03cad2eb4214 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 6 Apr 2026 20:47:40 +0530 Subject: [PATCH 05/19] Revert "Weird constraints stuff..." This reverts commit 4bd785de872269c0b27362ee800f17288b2b4789. --- cibuildwheel/resources/constraints-python310.txt | 6 +++--- cibuildwheel/resources/constraints-python311.txt | 4 ++-- cibuildwheel/resources/constraints-python312.txt | 4 ++-- cibuildwheel/resources/constraints-python313.txt | 4 ++-- cibuildwheel/resources/constraints-python314.txt | 4 ++-- cibuildwheel/resources/constraints-python38.txt | 4 ++-- cibuildwheel/resources/constraints-python39.txt | 6 +++--- cibuildwheel/resources/constraints.txt | 4 ++-- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cibuildwheel/resources/constraints-python310.txt b/cibuildwheel/resources/constraints-python310.txt index a01a3addb..b4a1cc832 100644 --- a/cibuildwheel/resources/constraints-python310.txt +++ b/cibuildwheel/resources/constraints-python310.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.2 +build==1.4.0 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -28,9 +28,9 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.1 +python-discovery==1.2.0 # via virtualenv -tomli==2.4.1 +tomli==2.4.0 # via build typing-extensions==4.15.0 # via diff --git a/cibuildwheel/resources/constraints-python311.txt b/cibuildwheel/resources/constraints-python311.txt index cb5e1ebe1..cfe88baae 100644 --- a/cibuildwheel/resources/constraints-python311.txt +++ b/cibuildwheel/resources/constraints-python311.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.2 +build==1.4.0 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.1 +python-discovery==1.2.0 # via virtualenv typing-extensions==4.15.0 # via delocate diff --git a/cibuildwheel/resources/constraints-python312.txt b/cibuildwheel/resources/constraints-python312.txt index cb5e1ebe1..cfe88baae 100644 --- a/cibuildwheel/resources/constraints-python312.txt +++ b/cibuildwheel/resources/constraints-python312.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.2 +build==1.4.0 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.1 +python-discovery==1.2.0 # via virtualenv typing-extensions==4.15.0 # via delocate diff --git a/cibuildwheel/resources/constraints-python313.txt b/cibuildwheel/resources/constraints-python313.txt index cb5e1ebe1..cfe88baae 100644 --- a/cibuildwheel/resources/constraints-python313.txt +++ b/cibuildwheel/resources/constraints-python313.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.2 +build==1.4.0 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.1 +python-discovery==1.2.0 # via virtualenv typing-extensions==4.15.0 # via delocate diff --git a/cibuildwheel/resources/constraints-python314.txt b/cibuildwheel/resources/constraints-python314.txt index cb5e1ebe1..cfe88baae 100644 --- a/cibuildwheel/resources/constraints-python314.txt +++ b/cibuildwheel/resources/constraints-python314.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.2 +build==1.4.0 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.1 +python-discovery==1.2.0 # via virtualenv typing-extensions==4.15.0 # via delocate diff --git a/cibuildwheel/resources/constraints-python38.txt b/cibuildwheel/resources/constraints-python38.txt index 5b2c13ad3..58fc349d5 100644 --- a/cibuildwheel/resources/constraints-python38.txt +++ b/cibuildwheel/resources/constraints-python38.txt @@ -28,9 +28,9 @@ platformdirs==4.3.6 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.1 +python-discovery==1.2.0 # via virtualenv -tomli==2.4.1 +tomli==2.4.0 # via build typing-extensions==4.13.2 # via diff --git a/cibuildwheel/resources/constraints-python39.txt b/cibuildwheel/resources/constraints-python39.txt index 66d2377fb..74ae43386 100644 --- a/cibuildwheel/resources/constraints-python39.txt +++ b/cibuildwheel/resources/constraints-python39.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.2 +build==1.4.0 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -28,9 +28,9 @@ platformdirs==4.4.0 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.1 +python-discovery==1.2.0 # via virtualenv -tomli==2.4.1 +tomli==2.4.0 # via build typing-extensions==4.15.0 # via diff --git a/cibuildwheel/resources/constraints.txt b/cibuildwheel/resources/constraints.txt index cb5e1ebe1..cfe88baae 100644 --- a/cibuildwheel/resources/constraints.txt +++ b/cibuildwheel/resources/constraints.txt @@ -2,7 +2,7 @@ # nox -s update_constraints altgraph==0.17.5 # via macholib -build==1.4.2 +build==1.4.0 # via -r cibuildwheel/resources/constraints.in delocate==0.13.0 # via -r cibuildwheel/resources/constraints.in @@ -26,7 +26,7 @@ platformdirs==4.9.4 # virtualenv pyproject-hooks==1.2.0 # via build -python-discovery==1.2.1 +python-discovery==1.2.0 # via virtualenv typing-extensions==4.15.0 # via delocate From 8064a46542716724510e405c2b3f1192899cfdab Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 6 Apr 2026 20:47:55 +0530 Subject: [PATCH 06/19] Add some special constraints for pyodide --- test/test_dependency_versions.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index 855fd3546..2a226a584 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -140,11 +140,19 @@ def test_dependency_constraints( project_dir = tmp_path / "project" test_projects.new_c_project().generate(project_dir) - tool_versions = { - "pip": "23.1.2", - "build": "1.2.2", - "delocate": "0.10.3", - } + if utils.get_platform() == "pyodide": + # pyodide-build 0.34+ requires build~=1.4.0, so we must use a + # compatible version here. delocate is macOS-only and not used on pyodide. + tool_versions = { + "pip": "23.1.2", + "build": "1.4.2", + } + else: + tool_versions = { + "pip": "23.1.2", + "build": "1.2.2", + "delocate": "0.10.3", + } if method == "file": constraints_file = tmp_path / "constraints file.txt" From ac56575f3f538f36b7ae5c684d89880f619b070d Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 6 Apr 2026 20:53:35 +0530 Subject: [PATCH 07/19] Wheel pyemscripten collision --- test/test_custom_repair_wheel.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_custom_repair_wheel.py b/test/test_custom_repair_wheel.py index 901f559cd..8bfe6a3fa 100644 --- a/test/test_custom_repair_wheel.py +++ b/test/test_custom_repair_wheel.py @@ -18,10 +18,10 @@ wheel = Path(sys.argv[1]) dest_dir = Path(sys.argv[2]) platform = wheel.stem.split("-")[-1] -if platform.startswith("pyodide"): - # for the sake of this test, munge the pyodide platforms into one, it's +if platform.startswith("pyemscripten"): + # for the sake of this test, munge the pyemscripten platforms into one, it's # not valid, but it does activate the uniqueness check - platform = "pyodide" + platform = "pyemscripten" name = f"spam-0.1.0-py2-none-{platform}.whl" dest = dest_dir / name From 52fa455c6fcdbab7f7994119bd344bf0995ffb08 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 6 Apr 2026 21:04:05 +0530 Subject: [PATCH 08/19] Put delocate back in constraints (not needed tho) --- test/test_dependency_versions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index 2a226a584..44f16af8d 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -146,6 +146,7 @@ def test_dependency_constraints( tool_versions = { "pip": "23.1.2", "build": "1.4.2", + "delocate": "0.10.3", } else: tool_versions = { From 46a2627a77cd35b79cd871a17d7f32b39a9cbef1 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 19:15:11 +0530 Subject: [PATCH 09/19] Drop Pyodide 0.27.7 (cp312-pyodide_wasm32) --- cibuildwheel/resources/build-platforms.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml index f75627ada..2ae9a25a9 100644 --- a/cibuildwheel/resources/build-platforms.toml +++ b/cibuildwheel/resources/build-platforms.toml @@ -225,7 +225,6 @@ python_configurations = [ [pyodide] python_configurations = [ - { identifier = "cp312-pyodide_wasm32", version = "3.12", default_pyodide_version = "0.27.7", node_version = "v22" }, { identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.29.3", node_version = "v22" }, ] From 088d6e568fec27ee98c4f627eba8a9c9a32e51dc Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 19:15:45 +0530 Subject: [PATCH 10/19] Add Pyodide 314.0.0a1 (cp314-pyodide_wasm32) --- cibuildwheel/resources/build-platforms.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml index 2ae9a25a9..234d865c0 100644 --- a/cibuildwheel/resources/build-platforms.toml +++ b/cibuildwheel/resources/build-platforms.toml @@ -226,6 +226,7 @@ python_configurations = [ [pyodide] python_configurations = [ { identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.29.3", node_version = "v22" }, + { identifier = "cp314-pyodide_wasm32", version = "3.14", default_pyodide_version = "314.0.0a1", node_version = "v24" }, ] [android] From 455e5682637c175a35785f69abb8ad69ef23fa2f Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 19:26:19 +0530 Subject: [PATCH 11/19] Delete no-longer-needed Pyodide 312 constraints --- .../resources/constraints-pyodide312.txt | 91 ------------------- 1 file changed, 91 deletions(-) delete mode 100644 cibuildwheel/resources/constraints-pyodide312.txt diff --git a/cibuildwheel/resources/constraints-pyodide312.txt b/cibuildwheel/resources/constraints-pyodide312.txt deleted file mode 100644 index 96fd519f4..000000000 --- a/cibuildwheel/resources/constraints-pyodide312.txt +++ /dev/null @@ -1,91 +0,0 @@ -# This file was autogenerated by uv via the following command: -# nox -s update_constraints -annotated-types==0.7.0 - # via pydantic -auditwheel-emscripten==0.2.4 - # via pyodide-build -build==1.4.2 - # via - # -r .nox/update_constraints/tmp/constraints-pyodide.in - # pyodide-build -certifi==2026.2.25 - # via requests -charset-normalizer==3.4.7 - # via requests -click==8.1.8 - # via - # -r .nox/update_constraints/tmp/constraints-pyodide.in - # pyodide-build - # pyodide-cli -distlib==0.4.0 - # via virtualenv -filelock==3.25.2 - # via - # python-discovery - # virtualenv -idna==3.11 - # via requests -leb128==1.0.9 - # via auditwheel-emscripten -markdown-it-py==4.0.0 - # via rich -mdurl==0.1.2 - # via markdown-it-py -packaging==26.0 - # via - # auditwheel-emscripten - # build - # pyodide-build - # wheel -pip==26.0.1 - # via -r .nox/update_constraints/tmp/constraints-pyodide.in -platformdirs==4.9.4 - # via - # pyodide-build - # python-discovery - # virtualenv -pydantic==2.12.5 - # via - # pyodide-build - # pyodide-lock -pydantic-core==2.41.5 - # via pydantic -pygments==2.20.0 - # via rich -pyodide-build==0.34.1 - # via -r .nox/update_constraints/tmp/constraints-pyodide.in -pyodide-cli==0.5.0 - # via - # auditwheel-emscripten - # pyodide-build -pyodide-lock==0.1.2 - # via pyodide-build -pyproject-hooks==1.2.0 - # via build -python-discovery==1.2.1 - # via virtualenv -requests==2.33.1 - # via pyodide-build -rich==14.3.3 - # via - # pyodide-build - # pyodide-cli -ruamel-yaml==0.19.1 - # via pyodide-build -typing-extensions==4.15.0 - # via - # pydantic - # pydantic-core - # typing-inspection -typing-inspection==0.4.2 - # via pydantic -urllib3==2.6.3 - # via requests -virtualenv==21.2.0 - # via - # build - # pyodide-build -wheel==0.46.3 - # via - # auditwheel-emscripten - # pyodide-build From 9396cae08c4bc459e061e2ef799de99314459a82 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 19:26:30 +0530 Subject: [PATCH 12/19] Update Pyodide 313 and 314 constraints --- .../resources/constraints-pyodide313.txt | 6 +- .../resources/constraints-pyodide314.txt | 91 +++++++++++++++++++ 2 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 cibuildwheel/resources/constraints-pyodide314.txt diff --git a/cibuildwheel/resources/constraints-pyodide313.txt b/cibuildwheel/resources/constraints-pyodide313.txt index 96fd519f4..53d85c36c 100644 --- a/cibuildwheel/resources/constraints-pyodide313.txt +++ b/cibuildwheel/resources/constraints-pyodide313.txt @@ -39,7 +39,7 @@ packaging==26.0 # wheel pip==26.0.1 # via -r .nox/update_constraints/tmp/constraints-pyodide.in -platformdirs==4.9.4 +platformdirs==4.9.6 # via # pyodide-build # python-discovery @@ -62,7 +62,7 @@ pyodide-lock==0.1.2 # via pyodide-build pyproject-hooks==1.2.0 # via build -python-discovery==1.2.1 +python-discovery==1.2.2 # via virtualenv requests==2.33.1 # via pyodide-build @@ -81,7 +81,7 @@ typing-inspection==0.4.2 # via pydantic urllib3==2.6.3 # via requests -virtualenv==21.2.0 +virtualenv==21.2.1 # via # build # pyodide-build diff --git a/cibuildwheel/resources/constraints-pyodide314.txt b/cibuildwheel/resources/constraints-pyodide314.txt new file mode 100644 index 000000000..53d85c36c --- /dev/null +++ b/cibuildwheel/resources/constraints-pyodide314.txt @@ -0,0 +1,91 @@ +# This file was autogenerated by uv via the following command: +# nox -s update_constraints +annotated-types==0.7.0 + # via pydantic +auditwheel-emscripten==0.2.4 + # via pyodide-build +build==1.4.2 + # via + # -r .nox/update_constraints/tmp/constraints-pyodide.in + # pyodide-build +certifi==2026.2.25 + # via requests +charset-normalizer==3.4.7 + # via requests +click==8.1.8 + # via + # -r .nox/update_constraints/tmp/constraints-pyodide.in + # pyodide-build + # pyodide-cli +distlib==0.4.0 + # via virtualenv +filelock==3.25.2 + # via + # python-discovery + # virtualenv +idna==3.11 + # via requests +leb128==1.0.9 + # via auditwheel-emscripten +markdown-it-py==4.0.0 + # via rich +mdurl==0.1.2 + # via markdown-it-py +packaging==26.0 + # via + # auditwheel-emscripten + # build + # pyodide-build + # wheel +pip==26.0.1 + # via -r .nox/update_constraints/tmp/constraints-pyodide.in +platformdirs==4.9.6 + # via + # pyodide-build + # python-discovery + # virtualenv +pydantic==2.12.5 + # via + # pyodide-build + # pyodide-lock +pydantic-core==2.41.5 + # via pydantic +pygments==2.20.0 + # via rich +pyodide-build==0.34.1 + # via -r .nox/update_constraints/tmp/constraints-pyodide.in +pyodide-cli==0.5.0 + # via + # auditwheel-emscripten + # pyodide-build +pyodide-lock==0.1.2 + # via pyodide-build +pyproject-hooks==1.2.0 + # via build +python-discovery==1.2.2 + # via virtualenv +requests==2.33.1 + # via pyodide-build +rich==14.3.3 + # via + # pyodide-build + # pyodide-cli +ruamel-yaml==0.19.1 + # via pyodide-build +typing-extensions==4.15.0 + # via + # pydantic + # pydantic-core + # typing-inspection +typing-inspection==0.4.2 + # via pydantic +urllib3==2.6.3 + # via requests +virtualenv==21.2.1 + # via + # build + # pyodide-build +wheel==0.46.3 + # via + # auditwheel-emscripten + # pyodide-build From f0289d8d3ea2bb3b3d744519425d3363810180d5 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 20:01:21 +0530 Subject: [PATCH 13/19] Add back prerelease stuff and update tests --- cibuildwheel/selector.py | 22 ++++++++++++---------- test/utils.py | 5 +++-- unit_test/build_selector_test.py | 4 ++-- unit_test/options_test.py | 4 ++-- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/cibuildwheel/selector.py b/cibuildwheel/selector.py index 80dc03090..57139319d 100644 --- a/cibuildwheel/selector.py +++ b/cibuildwheel/selector.py @@ -97,17 +97,19 @@ def __call__(self, build_id: str) -> bool: return False if EnableGroup.GraalPy not in self.enable and fnmatch(build_id, "gp*"): return False - # TODO: Re-enable this when we have Pyodide prereleases again (e.g., 0.29.0a1+) - # Python 3.13 support became stable in Pyodide 0.28.0, so it no longer needs a prerelease - # flag. - # Also update Pyodide tests in unit_test/build_selector_test.py accordingly. - # When re-enabling, update the pattern to match the experimental Python version in case - # it is bumped to Python 3.14 (likely cp314-pyodide_* but could remain as 3.13 as well). + # NOTE: Disable this when we don't have any Pyodide prereleases (e.g., 314.0.0a1+) + # When doing this, also: + # 1. update Pyodide tests in unit_test/build_selector_test.py and unit_test/options_test.py accordingly. + # 2. update Python versions for Pyodide identifiers in cibuildwheel/selector.py. + # 3. update constraints as necessary via bin/generate_pyodide_constraints.py and add/delete + # Pyodide constraints files in cibuildwheel/resources/constraints/ as necessary. + # When disabling, update the pattern to match the experimental Python version in case + # it is bumped to Python 3.15 (likely cp315-pyodide_* but could remain as 3.14 as well). # This depends on the CPython version being used in the Pyodide runtime at the time. - # if EnableGroup.PyodidePrerelease not in self.enable and fnmatch( - # build_id, "cp313-pyodide_*" - # ): - # return False + if EnableGroup.PyodidePrerelease not in self.enable and fnmatch( + build_id, "cp314-pyodide_*" + ): + return False should_build = selector_matches(self.build_config, build_id) should_skip = selector_matches(self.skip_config, build_id) diff --git a/test/utils.py b/test/utils.py index 68a761bf8..b1272e656 100644 --- a/test/utils.py +++ b/test/utils.py @@ -264,10 +264,11 @@ def _expected_wheels( if musllinux_versions is None: musllinux_versions = ["musllinux_1_2"] - if platform == "pyodide" and python_abi_tags is None: + # To be kept in sync with Python versions for Pyodide identifiers in cibuildwheel/selector.py. + if platform == "pyodide" and python_abi_tags is None: # noqa: SIM114 python_abi_tags = [ - "cp312-cp312", "cp313-cp313", + "cp314-cp314", ] elif platform == "android" and python_abi_tags is None: # noqa: SIM114 python_abi_tags = [ diff --git a/unit_test/build_selector_test.py b/unit_test/build_selector_test.py index 71a6fcd6c..e98cd5fdf 100644 --- a/unit_test/build_selector_test.py +++ b/unit_test/build_selector_test.py @@ -97,8 +97,8 @@ def test_build_filter_pyodide_prerelease() -> None: skip_config="", enable=frozenset([EnableGroup.PyodidePrerelease]), ) - assert build_selector("cp312-pyodide_wasm32") assert build_selector("cp313-pyodide_wasm32") + assert build_selector("cp314-pyodide_wasm32") def test_build_filter_pyodide() -> None: @@ -107,8 +107,8 @@ def test_build_filter_pyodide() -> None: skip_config="", enable=frozenset(), ) - assert build_selector("cp312-pyodide_wasm32") assert build_selector("cp313-pyodide_wasm32") + assert not build_selector("cp314-pyodide_wasm32") def test_skip() -> None: diff --git a/unit_test/options_test.py b/unit_test/options_test.py index 0c42b1f9a..3160213c7 100644 --- a/unit_test/options_test.py +++ b/unit_test/options_test.py @@ -36,7 +36,7 @@ environment-pass = ["EXAMPLE_ENV"] -pyodide-version = "0.28.0" +pyodide-version = "0.29.3" [tool.cibuildwheel.macos] test-requires = "else" @@ -93,7 +93,7 @@ def test_options_1(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: assert local.manylinux_images["x86_64"] == pinned_x86_64_container_image["manylinux_2_34"] local = options.build_options("cp312-pyodide_wasm32") - assert local.pyodide_version == "0.28.0" + assert local.pyodide_version == "0.29.3" def test_passthrough(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: From 9749c1112ec19083a6b82b9b73b295dce8b45236 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 20:10:25 +0530 Subject: [PATCH 14/19] Fix `test_pyodide_on_windows` --- unit_test/main_tests/main_platform_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unit_test/main_tests/main_platform_test.py b/unit_test/main_tests/main_platform_test.py index 874aa2575..51097d0e6 100644 --- a/unit_test/main_tests/main_platform_test.py +++ b/unit_test/main_tests/main_platform_test.py @@ -308,7 +308,7 @@ def test_pyodide_on_windows( monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] ) -> None: monkeypatch.setattr(sys, "platform", "win32") - monkeypatch.setattr(sys, "argv", [*sys.argv, "--only", "cp312-pyodide_wasm32"]) + monkeypatch.setattr(sys, "argv", [*sys.argv, "--only", "cp314-pyodide_wasm32"]) with pytest.raises(SystemExit) as exit: main() From e3c8ca1ba6db331f2b0ec85034d288e9900ab74a Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:19:36 +0530 Subject: [PATCH 15/19] Update and fix tests some more --- test/test_abi_variants.py | 9 +++++++-- test/test_dependency_versions.py | 4 ++-- test/test_pyodide.py | 6 +++--- test/utils.py | 19 +++++++++---------- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/test/test_abi_variants.py b/test/test_abi_variants.py index 25fc9ca5d..fdf797be0 100644 --- a/test/test_abi_variants.py +++ b/test/test_abi_variants.py @@ -43,15 +43,20 @@ def test_abi3(tmp_path: Path) -> None: project_dir, add_env={ # free_threaded, GraalPy, and PyPy do not have a Py_LIMITED_API equivalent, just build one of those + # pyodide uses cp313 (the stable version) which supports limited API / abi3 # also limit the number of builds for test performance reasons - "CIBW_BUILD": "cp39-* cp310-* pp310-* gp312_250-* cp312-* cp314t-*", + "CIBW_BUILD": ( + "cp313-*" + if utils.get_platform() == "pyodide" + else "cp39-* cp310-* pp310-* gp312_250-* cp312-* cp314t-*" + ), "CIBW_ENABLE": "all", }, ) # check that the expected wheels are produced if utils.get_platform() == "pyodide": - # there's only 1 possible configuration for pyodide, cp312. It builds + # there's only 1 possible configuration for pyodide, cp313. It builds # a wheel that is tagged abi3, compatible back to 3.10 expected_wheels = utils.expected_wheels( "spam", diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index 44f16af8d..de5b6c7fa 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -77,13 +77,13 @@ def get_versions_from_constraint_file(constraint_file: Path) -> dict[str, str]: return dict(re.findall(VERSION_REGEX, constraint_file_text)) -@pytest.mark.parametrize("python_version", ["3.8", "3.12"]) +@pytest.mark.parametrize("python_version", ["3.8", "3.13"]) def test_pinned_versions( tmp_path: Path, python_version: str, build_frontend_env_nouv: dict[str, str] ) -> None: if utils.get_platform() == "linux": pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead") - if python_version != "3.12" and utils.get_platform() == "pyodide": + if python_version != "3.13" and utils.get_platform() == "pyodide": pytest.skip(f"pyodide does not support Python {python_version}") if ( python_version == "3.8" diff --git a/test/test_pyodide.py b/test/test_pyodide.py index 4538f73ef..96873661d 100644 --- a/test/test_pyodide.py +++ b/test/test_pyodide.py @@ -79,8 +79,8 @@ def test_pyodide_build(tmp_path: Path, use_pyproject_toml: bool) -> None: # check that the expected wheels are produced expected_wheels = [ - "spam-0.1.0-cp312-cp312-pyemscripten_2024_0_wasm32.whl", "spam-0.1.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", + "spam-0.1.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", ] print("actual_wheels", actual_wheels) @@ -144,8 +144,8 @@ def test_filter() -> None: ) # check that the expected wheels are produced expected_wheels = [ - "spam-0.1.0-cp312-cp312-pyemscripten_2024_0_wasm32.whl", "spam-0.1.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", + "spam-0.1.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", ] assert set(actual_wheels) == set(expected_wheels) @@ -170,6 +170,6 @@ def test_pyodide_repair_wheel(tmp_path: Path) -> None: # check that the expected wheels are produced expected_wheels = [ - "spam-0.1.0-cp312-cp312-pyemscripten_2024_0_wasm32.whl", + "spam-0.1.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", ] assert set(actual_wheels) == set(expected_wheels) diff --git a/test/utils.py b/test/utils.py index b1272e656..d2f2afc96 100644 --- a/test/utils.py +++ b/test/utils.py @@ -26,7 +26,7 @@ PYPY_ARCHS = ["x86_64", "i686", "AMD64", "aarch64", "arm64"] GRAALPY_ARCHS = ["x86_64", "AMD64", "aarch64", "arm64"] -SINGLE_PYTHON_VERSION: Final[tuple[int, int]] = (3, 12) +SINGLE_PYTHON_VERSION: Final[tuple[int, int]] = (3, 13) # temporary workaround: set by build_frontend_env fixture to skip graalpy # when uv is the build frontend (compatibility issue between graalpy and uv) @@ -265,11 +265,10 @@ def _expected_wheels( musllinux_versions = ["musllinux_1_2"] # To be kept in sync with Python versions for Pyodide identifiers in cibuildwheel/selector.py. - if platform == "pyodide" and python_abi_tags is None: # noqa: SIM114 - python_abi_tags = [ - "cp313-cp313", - "cp314-cp314", - ] + if platform == "pyodide" and python_abi_tags is None: + python_abi_tags = ["cp313-cp313"] + if EnableGroup.PyodidePrerelease in enable_groups: + python_abi_tags.append("cp314-cp314") elif platform == "android" and python_abi_tags is None: # noqa: SIM114 python_abi_tags = [ "cp313-cp313", @@ -415,14 +414,14 @@ def _expected_wheels( elif platform == "pyodide": platform_tags = { - "cp312-cp312": ["pyemscripten_2024_0_wasm32"], "cp313-cp313": ["pyemscripten_2025_0_wasm32"], + "cp314-cp314": ["pyemscripten_2026_0_wasm32"], }.get(python_abi_tag, []) if not platform_tags: - # for example if the python tag is `none` or `abi3`, all - # platform tags are built with that python tag - platform_tags = ["pyemscripten_2024_0_wasm32"] + # for example if the python tag is `none` or `abi3`, the wheel + # is built by the stable cp313 Python version + platform_tags = ["pyemscripten_2025_0_wasm32"] else: msg = f"Unsupported platform {platform!r}" From f4e522967786a2df0752dc0b545ee5d00600460a Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:24:58 +0530 Subject: [PATCH 16/19] Also enable pyodide-prerelease in GHA sample build --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ff92bd2e4..4ce07f751 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -323,11 +323,13 @@ jobs: output-dir: wheelhouse env: CIBW_PLATFORM: pyodide + CIBW_ENABLE: pyodide-prerelease - name: Run tests with 'CIBW_PLATFORM' set to 'pyodide' run: uv run --no-sync ./bin/run_tests.py env: CIBW_PLATFORM: pyodide + CIBW_ENABLE: pyodide-prerelease test-uv-extras: name: Test uv extra on ${{ matrix.os }} ${{ matrix.test_select }} From 3fe33942fc958c7a002e2f68ac50b84f8db7f1d3 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 23:04:17 +0530 Subject: [PATCH 17/19] Update tests yet again (`SINGLE_PYTHON_VERSION` changes) --- test/test_dependency_versions.py | 2 +- test/test_macos_archs.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_dependency_versions.py b/test/test_dependency_versions.py index de5b6c7fa..32cfc6ca0 100644 --- a/test/test_dependency_versions.py +++ b/test/test_dependency_versions.py @@ -124,7 +124,7 @@ def test_pinned_versions( expected_wheels = [ w for w in utils.expected_wheels("spam", "0.1.0") - if f"-cp{version_no_dot}" in w or f"-pp{version_no_dot}" in w + if f"-cp{version_no_dot}-cp{version_no_dot}-" in w or f"-pp{version_no_dot}-" in w ] assert set(actual_wheels) == set(expected_wheels) diff --git a/test/test_macos_archs.py b/test/test_macos_archs.py index 534541afa..7137be2d1 100644 --- a/test/test_macos_archs.py +++ b/test/test_macos_archs.py @@ -34,7 +34,7 @@ def test_cross_compiled_build(tmp_path: Path) -> None: add_env={"CIBW_ARCHS": "x86_64, universal2, arm64"}, single_python=True, ) - python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION) + python_tag = "cp{0}{1}-cp{0}{1}-".format(*utils.SINGLE_PYTHON_VERSION) expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w] assert set(actual_wheels) == set(expected_wheels) @@ -176,7 +176,7 @@ def test_universal2_testing_on_x86_64( else: assert warning_message in captured.err - python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION) + python_tag = "cp{0}{1}-cp{0}{1}-".format(*utils.SINGLE_PYTHON_VERSION) expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w and "universal2" in w] assert set(actual_wheels) == set(expected_wheels) @@ -210,7 +210,7 @@ def test_universal2_testing_on_arm64( assert "running tests on arm64 with pillow" in captured.out assert "running tests on x86_64 with pillow" in captured.out - python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION) + python_tag = "cp{0}{1}-cp{0}{1}-".format(*utils.SINGLE_PYTHON_VERSION) expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w and "universal2" in w] assert set(actual_wheels) == set(expected_wheels) From 6092434647a4ac731f44f1e661a7309c4b2befb7 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Fri, 10 Apr 2026 23:04:47 +0530 Subject: [PATCH 18/19] Add a Pyodide-specific maintenance guide --- docs/_internal/pyodide-maintenance.md | 109 ++++++++++++++++++++++++++ docs/contributing.md | 6 ++ 2 files changed, 115 insertions(+) create mode 100644 docs/_internal/pyodide-maintenance.md diff --git a/docs/_internal/pyodide-maintenance.md b/docs/_internal/pyodide-maintenance.md new file mode 100644 index 000000000..4129a16c4 --- /dev/null +++ b/docs/_internal/pyodide-maintenance.md @@ -0,0 +1,109 @@ +# Maintaining Pyodide support + +This page describes some short steps on how to update cibuildwheel's Pyodide platform code when the set of supported Pyodide Python versions changes – for example, when: + +- a new Pyodide alpha release arrives with support for a new [Pyodide ABI](https://pyodide.org/en/latest/development/abi.html) (which may be tied to updates in Emscripten and CPython versions, compiler/linker flags, Rust toolchain support and so on), or +- when that alpha graduates to a stable release. + +## Background + +Pyodide ships/may ship two kinds of Python builds at any point in time (note that these numbers may not be up to date): + +- **Stable** – the most recent full Pyodide release (e.g., `0.29.x` / cp313). This is enabled by default with no special `CIBW_ENABLE` flag needed. +- **Prerelease** – an alpha/beta/rc Pyodide release that uses the _next_ CPython version (e.g., `314.0.0a1` / cp314). Users must opt in with `CIBW_ENABLE: pyodide-prerelease` to build against this version. This may or may not be available at any given time, depending on the Pyodide release cycle. + +The guards in `cibuildwheel/selector.py` enforce this distinction. The constraints files under `cibuildwheel/resources/` pin the exact tool versions that go with each build. + +--- + +## When a new Pyodide prerelease becomes available + +For example, consider a scenario when Pyodide ships a new `315.0.0a1` with cp315 support. + +### 1. Add the new Python configuration + +In `cibuildwheel/resources/build-platforms.toml`, add an entry under `[pyodide]`: + +```toml +{ identifier = "cp315-pyodide_wasm32", version = "3.15", default_pyodide_version = "315.0.0a1", node_version = "v24" }, +``` + +`version` is the CPython version string, `default_pyodide_version` is the Pyodide release to use when the user does not pin one explicitly (use the latest available alpha/beta for a prerelease entry), and `node_version` is the minimum Node.js major required by that Pyodide release — check the [pyodide-build FAQ](https://pyodide-build.readthedocs.io/en/latest/faq.html#what-node-js-version-do-i-need) for a rudimentary idea of what the correct value is. + +### 2. Update the prerelease guards in the selector + +In `cibuildwheel/selector.py`, update the patterns in the `PyodidePrerelease` guards to match the new identifier: + +```python +if EnableGroup.PyodidePrerelease not in self.enable and fnmatch( + build_id, "cp315-pyodide_*" +): + return False +``` + +Also, update the comment above it to reflect the new version numbers and the instructions for when this guard should eventually be disabled. + +### 3. Generate and pin a constraints file + +The easiest way is to run the `update_constraints` `nox` session, which reads `build-platforms.toml` and regenerates all Pyodide constraints files automatically: + +```bash +nox -s update_constraints +``` + +Alternatively, run the generator script directly: + +```bash +python bin/generate_pyodide_constraints.py 315.0.0a1 \ + | uv pip compile - --python-version=3.15 \ + -o cibuildwheel/resources/constraints-pyodide315.txt +``` + +### 4. Update tests and update CI configuration + +- Update the unit tests so the new identifier is accepted by the selector with `PyodidePrerelease` enabled and rejected without it. Pyodide-specific integration tests may also need their hardcoded expected-wheel lists extended. + +- Run the full test suite with `CIBW_PLATFORM=pyodide` and `CIBW_ENABLE=pyodide-prerelease` environment variables to make sure the new configuration is well exercised in CI. + +- In GHA, make sure `CIBW_ENABLE: pyodide-prerelease` is set in the Pyodide CI job so that the prerelease identifier is exercised in CI. + +## When a Pyodide prerelease becomes stable + +Pyodide uses a versioning scheme where the stable release for a given CPython version is named `[PythonMajorMinor].0.0`, so the first stable release shipping cp314 will be **`314.0.0`**. See [pyodide/pyodide#6084](https://github.com/pyodide/pyodide/issues/6084) for a rationale of this versioning scheme. + +### 1. Update the stable entries, and remove (or replace) the prerelease entry + +In `build-platforms.toml`, update the former prerelease entry's `default_pyodide_version` to the new stable release (e.g. `314.0.0`) and remove the prerelease marker from the identifier if present. Remove previous prerelease entries if they are now obsolete, or update them to the next prerelease if one is available. Based on your discretion, you may choose to keep the old stable entry for a while if it is still supported by Pyodide, or remove it immediately if it is already retired. + +### 2. Disable or update the prerelease guards + +In `selector.py`: + +- **If a new prerelease is available**: update the `fnmatch` pattern to the next identifier (e.g. `cp315-pyodide_*`) as described above. +- **If there is no new prerelease**L remove the `PyodidePrerelease` logic entirely. + +### 3. Update the constraints file + +Run `nox -s update_constraints` to regenerate the constraints file for the newly stable version. If the entry was already in `build-platforms.toml` as a prerelease, its constraints file already exists, and this step just refreshes it against the stable Pyodide release and updates the dependencies' versions. + +### 4. Update tests and CI configuration + +Update the unit tests so the newly stable identifier is accepted by the selector without needing `PyodidePrerelease` in the enable set. Pyodide-specific integration tests may also need their hardcoded expected-wheel lists extended. + +- Run the full test suite with `CIBW_PLATFORM=pyodide` environment variables to make sure the new configuration is well exercised in CI. + +- Remove `CIBW_ENABLE: pyodide-prerelease` from the GHA Pyodide CI job steps, as no prerelease identifiers should remain after the stable release ships. + +## When an old Pyodide version is to be retired + +### 1. Remove the python configuration + +Delete the entry from `build-platforms.toml`. + +### 2. Delete the constraints file + +Remove `cibuildwheel/resources/constraints-pyodideXYZ.txt`. + +### 3. Update tests and CI configuration + +Remove references to the old identifier from the unit tests, integration tests, and drop any expected-wheel entries for it from the test helper. Also, ensure that no CI job is still trying to build it. diff --git a/docs/contributing.md b/docs/contributing.md index 31c879a79..739e7c021 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -208,3 +208,9 @@ git push && git push --tags Then head to https://github.com/pypa/cibuildwheel/releases and create a GitHub release from the new tag, pasting in the changelog entry. Once the release is created inside GitHub, a CI job will create the assets and upload them to PyPI. If there were any schema updates, run `pipx run ./bin/generate_schema.py --schemastore > partial-cibuildwheel.json` and contribute the changes to SchemaStore. + +### Platform-specific maintenance + +This section is a stub. Please open a PR to add guidance for any platform you would like to help maintain! + +- **Pyodide**: see [Maintaining Pyodide support](_internal/pyodide-maintenance.md) for instructions and maintainer-specific information on updating Pyodide-related code in cibuildwheel and updating to new Pyodide releases. From 40ffec086b3068e0e4e2b86e9ef5ff6ff1156d9f Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Mon, 13 Apr 2026 20:22:04 +0530 Subject: [PATCH 19/19] Add suggestions from Hood and Gyeongjae Co-Authored-By: Hood Chatham Co-Authored-By: Gyeongjae Choi --- docs/_internal/pyodide-maintenance.md | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/docs/_internal/pyodide-maintenance.md b/docs/_internal/pyodide-maintenance.md index 4129a16c4..6b422b337 100644 --- a/docs/_internal/pyodide-maintenance.md +++ b/docs/_internal/pyodide-maintenance.md @@ -1,13 +1,13 @@ # Maintaining Pyodide support -This page describes some short steps on how to update cibuildwheel's Pyodide platform code when the set of supported Pyodide Python versions changes – for example, when: +This page describes how to update cibuildwheel's Pyodide platform code when either: -- a new Pyodide alpha release arrives with support for a new [Pyodide ABI](https://pyodide.org/en/latest/development/abi.html) (which may be tied to updates in Emscripten and CPython versions, compiler/linker flags, Rust toolchain support and so on), or -- when that alpha graduates to a stable release. +- a new Pyodide alpha release arrives with support for a new [PyEmscripten Platform](https://pyodide.org/en/latest/development/abi.html) (which is tied to updates in Emscripten and CPython versions, compiler/linker flags, and so on), or +- when that alpha release graduates to a stable one. ## Background -Pyodide ships/may ship two kinds of Python builds at any point in time (note that these numbers may not be up to date): +Pyodide has two types of releases that matter to cibuildheel: - **Stable** – the most recent full Pyodide release (e.g., `0.29.x` / cp313). This is enabled by default with no special `CIBW_ENABLE` flag needed. - **Prerelease** – an alpha/beta/rc Pyodide release that uses the _next_ CPython version (e.g., `314.0.0a1` / cp314). Users must opt in with `CIBW_ENABLE: pyodide-prerelease` to build against this version. This may or may not be available at any given time, depending on the Pyodide release cycle. @@ -41,11 +41,9 @@ if EnableGroup.PyodidePrerelease not in self.enable and fnmatch( return False ``` -Also, update the comment above it to reflect the new version numbers and the instructions for when this guard should eventually be disabled. - ### 3. Generate and pin a constraints file -The easiest way is to run the `update_constraints` `nox` session, which reads `build-platforms.toml` and regenerates all Pyodide constraints files automatically: +Run the `update_constraints` `nox` session, which reads `build-platforms.toml` and regenerates all Pyodide constraints files automatically: ```bash nox -s update_constraints @@ -63,9 +61,7 @@ python bin/generate_pyodide_constraints.py 315.0.0a1 \ - Update the unit tests so the new identifier is accepted by the selector with `PyodidePrerelease` enabled and rejected without it. Pyodide-specific integration tests may also need their hardcoded expected-wheel lists extended. -- Run the full test suite with `CIBW_PLATFORM=pyodide` and `CIBW_ENABLE=pyodide-prerelease` environment variables to make sure the new configuration is well exercised in CI. - -- In GHA, make sure `CIBW_ENABLE: pyodide-prerelease` is set in the Pyodide CI job so that the prerelease identifier is exercised in CI. +- Run the full test suite with `CIBW_PLATFORM=pyodide` and `CIBW_ENABLE=pyodide-prerelease` environment variables to make sure the new configuration is exercised in CI. ## When a Pyodide prerelease becomes stable @@ -80,7 +76,7 @@ In `build-platforms.toml`, update the former prerelease entry's `default_pyodide In `selector.py`: - **If a new prerelease is available**: update the `fnmatch` pattern to the next identifier (e.g. `cp315-pyodide_*`) as described above. -- **If there is no new prerelease**L remove the `PyodidePrerelease` logic entirely. +- **If there is no new prerelease**: comment out the `PyodidePrerelease` logic. ### 3. Update the constraints file @@ -90,9 +86,7 @@ Run `nox -s update_constraints` to regenerate the constraints file for the newly Update the unit tests so the newly stable identifier is accepted by the selector without needing `PyodidePrerelease` in the enable set. Pyodide-specific integration tests may also need their hardcoded expected-wheel lists extended. -- Run the full test suite with `CIBW_PLATFORM=pyodide` environment variables to make sure the new configuration is well exercised in CI. - -- Remove `CIBW_ENABLE: pyodide-prerelease` from the GHA Pyodide CI job steps, as no prerelease identifiers should remain after the stable release ships. +- Run the full test suite with `CIBW_PLATFORM=pyodide` and `CIBW_ENABLE=pyodide-prerelease` environment variables to make sure the new configuration is exercised in CI. ## When an old Pyodide version is to be retired