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
This commit is contained in:
Henry Schreiner
2026-07-23 11:40:11 -04:00
committed by GitHub
parent 1520daf8ae
commit b7cac6dfef
4 changed files with 40 additions and 12 deletions
+12 -4
View File
@@ -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)
+3 -3
View File
@@ -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.
+1 -1
View File
@@ -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.
+24 -4
View File
@@ -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"),