Validate pyodide-version option against Pyodide build identifier (#2925)

* Validate pyodide-version against identifier

* Add tests

* Allow Pyodide nightly xbuildenvs too (for later)
This commit is contained in:
Agriya Khetarpal
2026-06-21 18:17:55 +01:00
committed by GitHub
parent 78d8530df9
commit 291be6a345
2 changed files with 98 additions and 1 deletions
+34
View File
@@ -218,6 +218,36 @@ def validate_pyodide_build_version(
raise errors.FatalError(msg)
def validate_pyodide_target_python(
xbuildenv_info: PyodideXBuildEnvInfo, python_configuration: PythonConfiguration
) -> None:
"""
Validate that the resolved Pyodide xbuildenv targets the same Python version
as the identifier being built.
This is to catch the case where a global ``pyodide-version`` is applied to an
identifier whose Python version does not match, such as setting
``pyodide-version = "3Y.0.0"`` (a Python 3.Y environment) while
building ``cp3X-pyodide_wasm32``.
"""
xbuildenv_version = xbuildenv_info["version"]
identifier = python_configuration.identifier
expected_version = python_configuration.version
default_version = python_configuration.default_pyodide_version
xbuildenv_python_minor = ".".join(xbuildenv_info["python"].split(".")[:2])
if xbuildenv_python_minor != expected_version:
msg = unwrap_preserving_paragraphs(f"""
The `pyodide-version` option is set to {xbuildenv_version}, which
provides Python {xbuildenv_python_minor}, but the {identifier} build
needs Python {expected_version}.
Either remove `pyodide-version` so {identifier} uses its default
({default_version}), or stop building {identifier} so that
`pyodide-version` only applies to an identifier it matches.
""")
raise errors.ConfigurationError(msg)
def install_xbuildenv(env: dict[str, str], xbuildenv_cache_path: Path, pyodide_version: str) -> str:
"""Install a particular Pyodide xbuildenv version and set a path to the Pyodide root."""
pyodide_root = xbuildenv_cache_path / pyodide_version / "xbuildenv" / "pyodide-root"
@@ -337,6 +367,10 @@ def setup_python(
xbuildenv_info=xbuildenv_info,
pyodide_build_version=pyodide_build_version,
)
validate_pyodide_target_python(
xbuildenv_info=xbuildenv_info,
python_configuration=python_configuration,
)
xbuildenv_cache_path = CIBW_CACHE_PATH / f"pyodide-build-{pyodide_build_version}"
+64 -1
View File
@@ -25,12 +25,19 @@ from cibuildwheel.options import (
_get_pinned_container_images,
)
from cibuildwheel.platforms import ALL_PLATFORM_MODULES, get_build_identifiers
from cibuildwheel.platforms.pyodide import (
PyodideXBuildEnvInfo,
validate_pyodide_target_python,
)
from cibuildwheel.platforms.pyodide import (
PythonConfiguration as PyodidePythonConfiguration,
)
from cibuildwheel.util import resources
from cibuildwheel.util.packaging import DependencyConstraints
TYPE_CHECKING = False
if TYPE_CHECKING:
from collections.abc import Sequence
from collections.abc import Callable, Sequence
PYPROJECT_1 = """
[tool.cibuildwheel]
@@ -106,6 +113,62 @@ def test_options_1(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
assert local.pyodide_version == "0.29.4"
@pytest.fixture
def make_pyodide_xbuildenv_info() -> Callable[[str, str], PyodideXBuildEnvInfo]:
def _make(version: str, python: str) -> PyodideXBuildEnvInfo:
return {
"version": version,
"python": python,
"emscripten": "5.0.3",
"pyodide_build": {"min": None, "max": None},
"compatible": True,
}
return _make
@pytest.fixture
def make_pyodide_python_configuration() -> Callable[[str, str], PyodidePythonConfiguration]:
def _make(identifier: str, version: str) -> PyodidePythonConfiguration:
return PyodidePythonConfiguration(
version=version,
identifier=identifier,
default_pyodide_version="0.0.0",
node_version="v22",
)
return _make
def test_validate_pyodide_target_python_matching(
make_pyodide_xbuildenv_info: Callable[[str, str], PyodideXBuildEnvInfo],
make_pyodide_python_configuration: Callable[[str, str], PyodidePythonConfiguration],
) -> None:
xbuildenv_info = make_pyodide_xbuildenv_info("314.0.0", "3.14.2")
config = make_pyodide_python_configuration("cp314-pyodide_wasm32", "3.14")
# should not raise
validate_pyodide_target_python(xbuildenv_info, config)
def test_validate_pyodide_target_python_mismatch(
make_pyodide_xbuildenv_info: Callable[[str, str], PyodideXBuildEnvInfo],
make_pyodide_python_configuration: Callable[[str, str], PyodidePythonConfiguration],
) -> None:
# a Python 3.14 xbuildenv applied to a cp313-pyodide_wasm32 build, when a global
# pyodide-version is set across mismatched targets
xbuildenv_info = make_pyodide_xbuildenv_info("314.0.0", "3.14.2")
config = make_pyodide_python_configuration("cp313-pyodide_wasm32", "3.13")
with pytest.raises(errors.ConfigurationError) as exc_info:
validate_pyodide_target_python(xbuildenv_info, config)
message = str(exc_info.value)
assert "cp313-pyodide_wasm32" in message
assert "314.0.0" in message
assert "3.13" in message
assert "3.14" in message
def test_test_and_audit_requires_with_dependency_specifiers(tmp_path: Path) -> None:
"""Regression test for https://github.com/pypa/cibuildwheel/issues/2912"""
pyproject_toml = tmp_path / "pyproject.toml"