diff --git a/bin/generate_schema.py b/bin/generate_schema.py index 6b98ce8ef..3ea67f378 100755 --- a/bin/generate_schema.py +++ b/bin/generate_schema.py @@ -33,11 +33,13 @@ description: How to inherit the parent's value. enable: enum: + - cpython-experimental-riscv64 - cpython-freethreading - cpython-prerelease + - graalpy + - pyodide-prerelease - pypy - pypy-eol - - cpython-experimental-riscv64 description: A Python version or flavor to enable. additionalProperties: false description: cibuildwheel's settings. diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml index 00c555794..0102ff5e7 100644 --- a/cibuildwheel/resources/build-platforms.toml +++ b/cibuildwheel/resources/build-platforms.toml @@ -221,6 +221,7 @@ python_configurations = [ [pyodide] python_configurations = [ { identifier = "cp312-pyodide_wasm32", version = "3.12", default_pyodide_version = "0.27.6", node_version = "v22" }, + { identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.28.0a3", node_version = "v22" }, ] [ios] diff --git a/cibuildwheel/resources/cibuildwheel.schema.json b/cibuildwheel/resources/cibuildwheel.schema.json index 92113e3d7..7d6aaf10d 100644 --- a/cibuildwheel/resources/cibuildwheel.schema.json +++ b/cibuildwheel/resources/cibuildwheel.schema.json @@ -13,11 +13,13 @@ }, "enable": { "enum": [ + "cpython-experimental-riscv64", "cpython-freethreading", "cpython-prerelease", + "graalpy", + "pyodide-prerelease", "pypy", - "pypy-eol", - "cpython-experimental-riscv64" + "pypy-eol" ] }, "description": "A Python version or flavor to enable." diff --git a/cibuildwheel/selector.py b/cibuildwheel/selector.py index 42f4104be..256e4fb04 100644 --- a/cibuildwheel/selector.py +++ b/cibuildwheel/selector.py @@ -29,12 +29,13 @@ class EnableGroup(StrEnum): Groups of build selectors that are not enabled by default. """ + CPythonExperimentalRiscV64 = "cpython-experimental-riscv64" CPythonFreeThreading = "cpython-freethreading" CPythonPrerelease = "cpython-prerelease" + GraalPy = "graalpy" PyPy = "pypy" PyPyEoL = "pypy-eol" - CPythonExperimentalRiscV64 = "cpython-experimental-riscv64" - GraalPy = "graalpy" + PyodidePrerelease = "pyodide-prerelease" @classmethod def all_groups(cls) -> frozenset["EnableGroup"]: @@ -98,6 +99,10 @@ def __call__(self, build_id: str) -> bool: return False if EnableGroup.GraalPy not in self.enable and fnmatch(build_id, "gp*"): return False + if EnableGroup.PyodidePrerelease not in self.enable and fnmatch( + build_id, "cp313-pyodide_*" + ): + return False should_build = selector_matches(self.build_config, build_id) should_skip = selector_matches(self.skip_config, build_id) diff --git a/docs/options.md b/docs/options.md index 3a9abf552..67439176f 100644 --- a/docs/options.md +++ b/docs/options.md @@ -58,7 +58,7 @@ When setting the options, you can use shell-style globbing syntax, as per [fnmat | Python 3.10 | cp310-macosx_x86_64
cp310-macosx_universal2
cp310-macosx_arm64 | cp310-win_amd64
cp310-win32
cp310-win_arm64 | cp310-manylinux_x86_64
cp310-manylinux_i686
cp310-musllinux_x86_64
cp310-musllinux_i686 | cp310-manylinux_aarch64
cp310-manylinux_ppc64le
cp310-manylinux_s390x
cp310-manylinux_armv7l
cp310-manylinux_riscv64
cp310-musllinux_aarch64
cp310-musllinux_ppc64le
cp310-musllinux_s390x
cp310-musllinux_armv7l
cp310-musllinux_riscv64 | | | | Python 3.11 | cp311-macosx_x86_64
cp311-macosx_universal2
cp311-macosx_arm64 | cp311-win_amd64
cp311-win32
cp311-win_arm64 | cp311-manylinux_x86_64
cp311-manylinux_i686
cp311-musllinux_x86_64
cp311-musllinux_i686 | cp311-manylinux_aarch64
cp311-manylinux_ppc64le
cp311-manylinux_s390x
cp311-manylinux_armv7l
cp311-manylinux_riscv64
cp311-musllinux_aarch64
cp311-musllinux_ppc64le
cp311-musllinux_s390x
cp311-musllinux_armv7l
cp311-musllinux_riscv64 | | | | 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-ios_arm64_iphoneos
cp313-ios_arm64_iphonesimulator
cp313-ios_x86_64_iphonesimulator | | +| 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-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 | cp314-win_amd64
cp314-win32
cp314-win_arm64 | cp314-manylinux_x86_64
cp314-manylinux_i686
cp314-musllinux_x86_64
cp314-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 | | | | PyPy3.8 v7.3 | pp38-macosx_x86_64
pp38-macosx_arm64 | pp38-win_amd64 | pp38-manylinux_x86_64
pp38-manylinux_i686 | pp38-manylinux_aarch64 | | | | PyPy3.9 v7.3 | pp39-macosx_x86_64
pp39-macosx_arm64 | pp39-win_amd64 | pp39-manylinux_x86_64
pp39-manylinux_i686 | pp39-manylinux_aarch64 | | | @@ -334,15 +334,18 @@ values are: are disabled by default as they can't be uploaded to PyPI and a PEP will most likely be required before this can happen. - `graalpy`: Enable GraalPy. +- `pyodide-prerelease`: Pyodide versions that haven't released yet, if one is + available. Safe if you are shipping a site with an early build, not for + general distribution. - `all`: Enable all of the above. !!! caution `cpython-prerelease` is provided for testing purposes only. It is not recommended to distribute wheels built with beta releases, such as - uploading to PyPI. Please _do not_ upload these wheels to PyPI, as they are - not guaranteed to work with the final Python release. Once Python is ABI - stable and enters the release candidate phase, that version of Python will - become available without this flag. + uploading to PyPI. Please _do not_ upload these wheels to PyPI (except for + pre-releases), as they are not guaranteed to work with the final Python + release. Once Python is ABI stable and enters the release candidate phase, + that version of Python will become available without this flag. !!! note Free threading is experimental: [What’s New In Python 3.13](https://docs.python.org/3.13/whatsnew/3.13.html#free-threaded-cpython) diff --git a/docs/platforms.md b/docs/platforms.md index d57b1b864..438ba7607 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -170,7 +170,9 @@ You must target pyodide with `--platform pyodide` (or use `--only` on the identi ### Choosing a Pyodide version {: #pyodide-choosing-a-version} -It is also possible to target a specific Pyodide version by setting the `pyodide-version` option to the desired version. Users are responsible for setting an appropriate Pyodide version according to the `pyodide-build` version. A list is available in Pyodide's [cross-build environments metadata file](https://github.com/pyodide/pyodide/blob/main/pyodide-cross-build-environments.json), which can be viewed more easily by installing `pyodide-build` from PyPI and using `pyodide xbuildenv search --all` to see a compatibility table. +It is also possible to target a specific Pyodide version by setting the [`pyodide-version`](options.md#pyodide-version) option to the desired version. Users are responsible for setting an appropriate Pyodide version according to the `pyodide-build` version. A list is available in Pyodide's [cross-build environments metadata file](https://github.com/pyodide/pyodide/blob/main/pyodide-cross-build-environments.json), which can be viewed more easily by installing `pyodide-build` from PyPI and using `pyodide xbuildenv search --all` to see a compatibility table. + +If there are pre-releases available for a newer Python version, the `pyodide-prerelease` [`enable`](options.md#enable) can be used to include pre-release versions. ### Running tests diff --git a/test/test_pyodide.py b/test/test_pyodide.py index 39bc2be32..9240e8266 100644 --- a/test/test_pyodide.py +++ b/test/test_pyodide.py @@ -58,7 +58,7 @@ def test_pyodide_build(tmp_path, use_pyproject_toml): basic_project.generate(project_dir) # check for node in 1 case only to reduce CI load - add_env = {} + add_env = {"CIBW_ENABLE": "pyodide-prerelease"} if use_pyproject_toml: add_env["CIBW_TEST_COMMAND"] = f"python {{project}}/check_node.py {CIBW_CACHE_PATH}" @@ -72,6 +72,7 @@ def test_pyodide_build(tmp_path, use_pyproject_toml): # 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", ] print("actual_wheels", actual_wheels) @@ -130,11 +131,13 @@ def test_filter(): add_env={ "CIBW_TEST_REQUIRES": "pytest", "CIBW_TEST_COMMAND": "python -m pytest {project}", + "CIBW_ENABLE": "pyodide-prerelease", }, ) # 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", ] print("actual_wheels", actual_wheels) print("expected_wheels", expected_wheels) diff --git a/test/utils.py b/test/utils.py index 838e2179c..71071abe0 100644 --- a/test/utils.py +++ b/test/utils.py @@ -261,6 +261,8 @@ def _expected_wheels( if platform == "pyodide" and python_abi_tags is None: python_abi_tags = ["cp312-cp312"] + if EnableGroup.PyodidePrerelease in enable_groups: + python_abi_tags.append("cp313-cp313") elif platform == "ios" and python_abi_tags is None: python_abi_tags = ["cp313-cp313"] elif python_abi_tags is None: diff --git a/unit_test/build_selector_test.py b/unit_test/build_selector_test.py index 1c87c4264..0b29b3887 100644 --- a/unit_test/build_selector_test.py +++ b/unit_test/build_selector_test.py @@ -89,6 +89,26 @@ def test_build_filter_pypy_all(): assert build_selector("pp39-manylinux_x86_64") +def test_build_filter_pyodide_prerelease(): + build_selector = BuildSelector( + build_config="*", + skip_config="", + enable=frozenset([EnableGroup.PyodidePrerelease]), + ) + assert build_selector("cp312-pyodide_wasm32") + assert build_selector("cp313-pyodide_wasm32") + + +def test_build_filter_pyodide(): + build_selector = BuildSelector( + build_config="*", + skip_config="", + enable=frozenset(), + ) + assert build_selector("cp312-pyodide_wasm32") + assert not build_selector("cp313-pyodide_wasm32") + + def test_skip(): build_selector = BuildSelector( build_config="*",