From b7cac6dfeffdcac258e8fcce8407d5d8891a9b92 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 23 Jul 2026 11:40:11 -0400 Subject: [PATCH] fix: don't error when a global build-frontend is set on pyodide (#2945) Since #2609, the pyodide platform required the 'pyodide-build' frontend, but a global build-frontend setting (TOML or CIBW_BUILD_FRONTEND) overrides the platform default, so previously-working configs like build-frontend = "build" failed with a ConfigurationError. Even "default" failed, since it was mapped to "build" before the check. Resolve "default" to the platform default, and warn and use pyodide-build when another frontend is set on pyodide, matching pre-#2609 behavior where the frontend name only affected verbosity flags. Assisted-by: ClaudeCode:claude-opus-4.8 --- cibuildwheel/options.py | 16 ++++++++++++---- docs/options.md | 6 +++--- docs/platforms.md | 2 +- unit_test/options_test.py | 28 ++++++++++++++++++++++++---- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/cibuildwheel/options.py b/cibuildwheel/options.py index 77189dab..f3d4701a 100644 --- a/cibuildwheel/options.py +++ b/cibuildwheel/options.py @@ -43,7 +43,7 @@ from packaging.specifiers import SpecifierSet from cibuildwheel import errors from cibuildwheel.architecture import Architecture from cibuildwheel.environment import EnvironmentParseError, ParsedEnvironment, parse_environment -from cibuildwheel.frontend import BuildFrontendConfig +from cibuildwheel.frontend import BuildFrontendConfig, BuildFrontendName from cibuildwheel.logger import log from cibuildwheel.oci_container import OCIContainerEngineConfig from cibuildwheel.projectfiles import get_requires_python_str, resolve_dependency_groups @@ -850,8 +850,11 @@ class Options: env_plat=False, option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False), ) + default_frontend: BuildFrontendName = ( + "pyodide-build" if self.platform == "pyodide" else "build" + ) if not build_frontend_str or build_frontend_str == "default": - build_frontend = BuildFrontendConfig("build") + build_frontend = BuildFrontendConfig(default_frontend) else: try: build_frontend = BuildFrontendConfig.from_config_string(build_frontend_str) @@ -860,8 +863,13 @@ class Options: raise errors.ConfigurationError(msg) from e if self.platform == "pyodide" and build_frontend.name != "pyodide-build": - msg = "The pyodide platform requires the 'pyodide-build' build frontend" - raise errors.ConfigurationError(msg) + # pip and uv could become an error, eventually. build -> pyodide-build is + # probably fine to keep as a warning + log.warning( + f"The pyodide platform ignores the {build_frontend.name!r} build " + "frontend; using 'pyodide-build' instead" + ) + build_frontend = BuildFrontendConfig("pyodide-build", build_frontend.args) if self.platform != "pyodide" and build_frontend.name == "pyodide-build": msg = "The 'pyodide-build' build frontend is only supported on the pyodide platform" raise errors.ConfigurationError(msg) diff --git a/docs/options.md b/docs/options.md index fd4d18ce..6b53c8fb 100644 --- a/docs/options.md +++ b/docs/options.md @@ -483,9 +483,9 @@ files (from workspaces) are not supported. On Android, the "pip" frontend is not supported. -On Pyodide, `build-frontend` must be `pyodide-build`, which is the default for that -platform. See [Pyodide build frontend support](platforms.md#pyodide-build-frontend) for -details. +On Pyodide, `pyodide-build` is the default and only supported frontend; setting +another frontend produces a warning and uses `pyodide-build` instead. See +[Pyodide build frontend support](platforms.md#pyodide-build-frontend) for details. You can specify extra arguments to pass to the build frontend using the optional `args` option. diff --git a/docs/platforms.md b/docs/platforms.md index 035b7ec3..57674dde 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -190,7 +190,7 @@ The `--libdir` option specifies the directory containing cross-compiled shared l ### Build frontend support {: #pyodide-build-frontend} -The pyodide platform builds wheels by shelling out to `pyodide build`, via the `pyodide-build` [`build-frontend`](options.md#build-frontend), which itself is a meta build frontend and passes through commands to pypa/build with specialised handling. This is the only supported frontend for this platform, and is used by default. +The pyodide platform builds wheels by shelling out to `pyodide build`, via the `pyodide-build` [`build-frontend`](options.md#build-frontend), which itself is a meta build frontend and passes through commands to pypa/build with specialised handling. This is the only supported frontend for this platform, and is used by default. A global [`build-frontend`](options.md#build-frontend) setting naming another frontend is ignored with a warning on this platform. [`build-verbosity`](options.md#build-verbosity) is passed through to `pyodide build` as `-v`/`-vv`. It is capped at `-vv`. `pyodide build` has no `-vvv` flag. diff --git a/unit_test/options_test.py b/unit_test/options_test.py index 596ad27d..bff5d6ed 100644 --- a/unit_test/options_test.py +++ b/unit_test/options_test.py @@ -515,13 +515,33 @@ def test_pyodide_build_frontend_args(tmp_path: Path) -> None: assert build_frontend.args == ["--exports=whole_archive"] +@pytest.mark.parametrize( + "build_frontend_str", + ["default", "pip", "build", "build[uv]", "uv"], +) +def test_pyodide_global_build_frontend_coerced(tmp_path: Path, build_frontend_str: str) -> None: + """A global non-pyodide frontend setting is coerced to pyodide-build, not an error.""" + args = CommandLineArguments.defaults() + args.package_dir = tmp_path + + tmp_path.joinpath("pyproject.toml").write_text( + textwrap.dedent( + f"""\ + [tool.cibuildwheel] + build-frontend = "{build_frontend_str}" + """ + ) + ) + + options = Options(platform="pyodide", command_line_arguments=args, env={}) + build_frontend = options.build_options(identifier=None).build_frontend + + assert build_frontend.name == "pyodide-build" + + @pytest.mark.parametrize( ("platform", "build_frontend_str"), [ - ("pyodide", "pip"), - ("pyodide", "build"), - ("pyodide", "build[uv]"), - ("pyodide", "uv"), ("linux", "pyodide-build"), ("macos", "pyodide-build"), ("windows", "pyodide-build"),