feat: Pyodide improvements: version setting, standalone environments (#2002)
* Fix a typo: pyoodide ➡️ pyodide * Add `pyodide_build_version` attribute * Add version to xbuildenv log step * Add version to Emscripten log step * Use `pyodide-build`'s version for updating constraints * Bump Pyodide constraints by updating `pyodide-build` * Add a schema for `pyodide-version` * Update Pyodide constraints * Bump `pyodide-build` to new 0.29.0 * Test out another Pyodide identifier * Update outdated Pyodide constraints * Add Pyodide version to temp directory name * Remove Pyodide 0.26.1 from build configurations * Retrieve + validate + install specific xbuildenvs * Test wheel builds with Pyodide 0.26.2 * Add correct Pyodide version to identifier temp dir * Don't pre-call Pyodide xbuildenv search * Fetch just the stable Pyodide versions * Refactor search + validation + install into one step * Move all of it under a lock * Reorder xbuildenv installation * Add env and cwd to xbuildenv search call * Temporarily lower to 0.26.2 target * Separate out search, validate, install; again * Run xbuildenv search in `CIBW_CACHE_PATH` * Remove prior `PYODIDE_ROOT` env vars, copy envs * Validate doesn't need to depend on searching * Add file lock when searching xbuildenvs * Test the original version: 0.26.1 * Update Pyodide constraints * Update constraints for `pyodide-build` 0.29.0 again * Bump Pyodide from version 0.26.1 ➡️ version 0.26.4 * Add note on compatibility for macOS + other archs * Note Pyodide version for Pyodide identifier * Docs about `CIBW_PYODIDE_VERSION` * Don't fetch just the stable versions * Discard a variable that's not used later * Rename `search_xbuildenv` ➡️ `get_xbuildenv_versions` * `validate_xbuildenv` ➡️ `validate_xbuildenv_version` * Replace ordered comment, add newline * Replace sentence on macOS support Co-Authored-By: Hood Chatham <roberthoodchatham@gmail.com> * Capitalise: "pyodide" ➡️ "Pyodide" Co-Authored-By: Hood Chatham <roberthoodchatham@gmail.com> * "work" ➡️ "may succeed" Co-Authored-By: Hood Chatham <roberthoodchatham@gmail.com> * Add another job to test a custom Pyodide version * Handle "v"-prefixed + non-prefixed versions * Convert to a proper toml-able option, and remove some hardcoded versions This removes the enscripten and pyodide-build version specs from pyproject.toml - pyodide-build is spec'd in the constraints file, and the emscripten version can be read from the pyodide-build output. * Add a schema entry * Add docs for CIBW_PYODIDE_VERSION * Rephrase * Add tests for pyodide-version * Apply suggestions from code review * Add python_build_standalone util * Hook up to python-build-standalone, removing dependency on host python * Remove python hard-code in action.yml * Add log step * Add workaround for https://github.com/pyodide/pyodide-build/issues/143 * Add emscripten pytest test * Remove unneeded checks * Fix a pytest invoke for emscripten * Generate pyodide-build constraints from the pinned pyodide version * Remove pyodide python-build-standalone workaround * Fixup paths from newer version of pyodide-build * Fix/skip some failing tests * Use `python -m pytest` on pyodide, even on Linux * Docs fixes * Don't call the github API at runtime, cache the release assets instead * Ignore pylint false positive * Add version auto-updating for pyodide * Add support for pyodide 3.13. * Fix tests for multiple pyodide wheels * Remove workaround for unreleased pyodide-build * Rename to "test_pyodide" * Fix pathname confusion * Remove extra github actions job * Fix expectation for test_abi_none * Fix the custom_repair_wheel test to actually have clashing names * Fix pinned version test * Document test-command limitation * Remove pyodide 0.28.0a1 for now * Update constraints files * Docs/test fixes post removing pyodide cp313 * Fix ABI test expectation * Docs improvements * Improve some comments * Remove logic duplication * remove pyodide special casing * Refactor constraints code to use a utility script, circumventing import issues * chore: nicer nox env Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * fix: typo in variable name found by copilot Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * Apply suggestions from code review * Some more Pyodide version updates in the docs section * We haven't released Pyodide v0.27.6 yet * Back to the Github URL for cross-build-environments * `pyodide-build`, not `emsdk` for Windows skips Co-Authored-By: Hood Chatham <roberthoodchatham@gmail.com> * Move to a separate `_json_request` function Co-Authored-By: Hood Chatham <roberthoodchatham@gmail.com> * Rename "retries" ➡️ "retry_count" * Add some type hints * Copy env vars before `UV_CUSTOM_COMPILE_COMMAND` * Use `HTTPError.headers.get` instead * Remove extra end quote * Change download tests URL to `https://badssl.com/` Co-Authored-By: Joe Rickerby <1244307+joerick@users.noreply.github.com> * Download size changes, too * Use jsdelivr for Github asset mirroring * Bump to Pyodide v0.27.6 * Fix unit tests * Move to pyodide v0.27.6 again * Bump to pyodide-build 0.30.4 * Use new URL for cross-build environments metadata Co-authored-by: Joe Rickerby <joerick@mac.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com> Co-authored-by: Joe Rickerby <joerick@mac.com> Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com> Co-authored-by: Joe Rickerby <1244307+joerick@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Hood Chatham
Joe Rickerby
Joe Rickerby
Henry Schreiner
pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
parent
c3c260dff7
commit
163864158d
@@ -195,7 +195,7 @@ jobs:
|
|||||||
run: uv run --no-sync pytest --run-emulation ${{ matrix.arch }} test/test_emulation.py
|
run: uv run --no-sync pytest --run-emulation ${{ matrix.arch }} test/test_emulation.py
|
||||||
|
|
||||||
test-pyodide:
|
test-pyodide:
|
||||||
name: Test cibuildwheel building Pyodide wheels
|
name: Test pyodide
|
||||||
needs: lint
|
needs: lint
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
timeout-minutes: 180
|
timeout-minutes: 180
|
||||||
@@ -222,6 +222,19 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CIBW_PLATFORM: pyodide
|
CIBW_PLATFORM: pyodide
|
||||||
|
|
||||||
|
- name: Run a sample build (GitHub Action) for an overridden Pyodide version
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
package-dir: sample_proj
|
||||||
|
output-dir: wheelhouse
|
||||||
|
# In case this breaks at any point in time, switch to using the latest version
|
||||||
|
# available or any other version that is not the same as the default one set
|
||||||
|
# in cibuildwheel/resources/build-platforms.toml.
|
||||||
|
env:
|
||||||
|
CIBW_PLATFORM: pyodide
|
||||||
|
CIBW_BUILD: "cp312*"
|
||||||
|
CIBW_PYODIDE_VERSION: "0.27.6"
|
||||||
|
|
||||||
- name: Run tests with 'CIBW_PLATFORM' set to 'pyodide'
|
- name: Run tests with 'CIBW_PLATFORM' set to 'pyodide'
|
||||||
run: |
|
run: |
|
||||||
uv run --no-sync ./bin/run_tests.py
|
uv run --no-sync ./bin/run_tests.py
|
||||||
|
|||||||
+1
-2
@@ -24,11 +24,10 @@ branding:
|
|||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
# Set up the version of Python that supports pyodide
|
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.11 - 3.13"
|
||||||
update-environment: false
|
update-environment: false
|
||||||
|
|
||||||
- id: cibw
|
- id: cibw
|
||||||
|
|||||||
Executable
+69
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import textwrap
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from cibuildwheel.extra import get_pyodide_xbuildenv_info
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.argument(
|
||||||
|
"pyodide-version",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--output-file",
|
||||||
|
type=click.Path(),
|
||||||
|
default=None,
|
||||||
|
help="Output file to write the constraints to. If not provided, the constraints will be printed to stdout.",
|
||||||
|
)
|
||||||
|
def generate_pyodide_constraints(pyodide_version: str, output_file: str | None = None) -> None:
|
||||||
|
"""
|
||||||
|
Generate constraints for a specific Pyodide version. The constraints are
|
||||||
|
generated based on the Pyodide version's xbuildenv info, which is retrieved
|
||||||
|
from the Pyodide repository.
|
||||||
|
|
||||||
|
These constraints should then be 'pinned' using `uv pip compile`.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
bin/generate_pyodide_constraints.py 0.27.0
|
||||||
|
"""
|
||||||
|
xbuildenv_info = get_pyodide_xbuildenv_info()
|
||||||
|
try:
|
||||||
|
pyodide_version_xbuildenv_info = xbuildenv_info["releases"][pyodide_version]
|
||||||
|
except KeyError as e:
|
||||||
|
msg = f"Pyodide version {pyodide_version} not found in xbuildenv info. Versions available: {', '.join(xbuildenv_info['releases'].keys())}"
|
||||||
|
raise click.BadParameter(msg) from e
|
||||||
|
|
||||||
|
pyodide_build_min_version = pyodide_version_xbuildenv_info.get("min_pyodide_build_version")
|
||||||
|
pyodide_build_max_version = pyodide_version_xbuildenv_info.get("max_pyodide_build_version")
|
||||||
|
|
||||||
|
pyodide_build_specifier_parts: list[str] = []
|
||||||
|
|
||||||
|
if pyodide_build_min_version:
|
||||||
|
pyodide_build_specifier_parts.append(f">={pyodide_build_min_version}")
|
||||||
|
if pyodide_build_max_version:
|
||||||
|
pyodide_build_specifier_parts.append(f"<={pyodide_build_max_version}")
|
||||||
|
|
||||||
|
pyodide_build_specifier = ",".join(pyodide_build_specifier_parts)
|
||||||
|
|
||||||
|
constraints_txt = textwrap.dedent(f"""
|
||||||
|
pip
|
||||||
|
build[virtualenv]
|
||||||
|
pyodide-build{pyodide_build_specifier}
|
||||||
|
click<8.2
|
||||||
|
""")
|
||||||
|
|
||||||
|
if output_file is None:
|
||||||
|
print(constraints_txt)
|
||||||
|
else:
|
||||||
|
Path(output_file).write_text(constraints_txt)
|
||||||
|
print(f"Constraints written to {output_file}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate_pyodide_constraints()
|
||||||
@@ -197,6 +197,9 @@ properties:
|
|||||||
xbuild-tools:
|
xbuild-tools:
|
||||||
description: Binaries on the path that should be included in an isolated cross-build environment
|
description: Binaries on the path that should be included in an isolated cross-build environment
|
||||||
type: string_array
|
type: string_array
|
||||||
|
pyodide-version:
|
||||||
|
type: string
|
||||||
|
description: Specify the version of Pyodide to use
|
||||||
repair-wheel-command:
|
repair-wheel-command:
|
||||||
description: Execute a shell command to repair each built wheel.
|
description: Execute a shell command to repair each built wheel.
|
||||||
type: string_array
|
type: string_array
|
||||||
|
|||||||
Executable
+59
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from cibuildwheel.extra import github_api_request
|
||||||
|
from cibuildwheel.util.python_build_standalone import (
|
||||||
|
PythonBuildStandaloneAsset,
|
||||||
|
PythonBuildStandaloneReleaseData,
|
||||||
|
)
|
||||||
|
from cibuildwheel.util.resources import PYTHON_BUILD_STANDALONE_RELEASES
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""
|
||||||
|
This script updates the vendored list of release assets to the latest
|
||||||
|
version of astral-sh/python-build-standalone.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Get the latest release tag from the GitHub API
|
||||||
|
latest_release = github_api_request("repos/astral-sh/python-build-standalone/releases/latest")
|
||||||
|
latest_tag = latest_release["tag_name"]
|
||||||
|
|
||||||
|
# Get the list of assets for the latest release
|
||||||
|
github_assets = github_api_request(
|
||||||
|
f"repos/astral-sh/python-build-standalone/releases/tags/{latest_tag}"
|
||||||
|
)["assets"]
|
||||||
|
|
||||||
|
assets: list[PythonBuildStandaloneAsset] = []
|
||||||
|
|
||||||
|
for github_asset in github_assets:
|
||||||
|
name = github_asset["name"]
|
||||||
|
if not name.endswith("install_only.tar.gz"):
|
||||||
|
continue
|
||||||
|
url = github_asset["browser_download_url"]
|
||||||
|
assets.append({"name": name, "url": url})
|
||||||
|
|
||||||
|
# Write the assets to the JSON file. One day, we might need to support
|
||||||
|
# multiple releases, but for now, we only support the latest one
|
||||||
|
json_file_contents: PythonBuildStandaloneReleaseData = {
|
||||||
|
"releases": [
|
||||||
|
{
|
||||||
|
"tag": latest_tag,
|
||||||
|
"assets": assets,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
with PYTHON_BUILD_STANDALONE_RELEASES.open("w", encoding="utf-8") as f:
|
||||||
|
json.dump(json_file_contents, f, indent=2)
|
||||||
|
# Add a trailing newline, our pre-commit hook requires it
|
||||||
|
f.write("\n")
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"Updated {PYTHON_BUILD_STANDALONE_RELEASES.name} with {len(assets)} assets for tag {latest_tag}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+51
-2
@@ -19,7 +19,7 @@ from packaging.version import Version
|
|||||||
from rich.logging import RichHandler
|
from rich.logging import RichHandler
|
||||||
from rich.syntax import Syntax
|
from rich.syntax import Syntax
|
||||||
|
|
||||||
from cibuildwheel.extra import dump_python_configurations
|
from cibuildwheel.extra import dump_python_configurations, get_pyodide_xbuildenv_info
|
||||||
|
|
||||||
log = logging.getLogger("cibw")
|
log = logging.getLogger("cibw")
|
||||||
|
|
||||||
@@ -57,7 +57,14 @@ class ConfigApple(TypedDict):
|
|||||||
url: str
|
url: str
|
||||||
|
|
||||||
|
|
||||||
AnyConfig = ConfigWinCP | ConfigWinPP | ConfigWinGP | ConfigApple
|
class ConfigPyodide(TypedDict):
|
||||||
|
identifier: str
|
||||||
|
version: str
|
||||||
|
default_pyodide_version: str
|
||||||
|
node_version: str
|
||||||
|
|
||||||
|
|
||||||
|
AnyConfig = ConfigWinCP | ConfigWinPP | ConfigWinGP | ConfigApple | ConfigPyodide
|
||||||
|
|
||||||
|
|
||||||
# The following set of "Versions" classes allow the initial call to the APIs to
|
# The following set of "Versions" classes allow the initial call to the APIs to
|
||||||
@@ -347,6 +354,39 @@ class CPythonIOSVersions:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class PyodideVersions:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
xbuildenv_info = get_pyodide_xbuildenv_info()
|
||||||
|
self.releases = xbuildenv_info["releases"]
|
||||||
|
|
||||||
|
def update_version_pyodide(
|
||||||
|
self, identifier: str, version: Version, spec: Specifier, node_version: str
|
||||||
|
) -> ConfigPyodide | None:
|
||||||
|
# get releases that match the python version
|
||||||
|
releases = [
|
||||||
|
r for r in self.releases.values() if spec.contains(Version(r["python_version"]))
|
||||||
|
]
|
||||||
|
# sort by version, latest first
|
||||||
|
releases.sort(key=lambda r: Version(r["version"]), reverse=True)
|
||||||
|
|
||||||
|
if not releases:
|
||||||
|
msg = f"Pyodide not found for {spec}!"
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
final_releases = [r for r in releases if not Version(r["version"]).is_prerelease]
|
||||||
|
|
||||||
|
# prefer a final release if available, otherwise use the latest
|
||||||
|
# pre-release
|
||||||
|
release = final_releases[0] if final_releases else releases[0]
|
||||||
|
|
||||||
|
return ConfigPyodide(
|
||||||
|
identifier=identifier,
|
||||||
|
version=str(version),
|
||||||
|
default_pyodide_version=release["version"],
|
||||||
|
node_version=node_version,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# This is a universal interface to all the above Versions classes. Given an
|
# This is a universal interface to all the above Versions classes. Given an
|
||||||
# identifier, it updates a config dict.
|
# identifier, it updates a config dict.
|
||||||
|
|
||||||
@@ -369,6 +409,8 @@ class AllVersions:
|
|||||||
|
|
||||||
self.graalpy = GraalPyVersions()
|
self.graalpy = GraalPyVersions()
|
||||||
|
|
||||||
|
self.pyodide = PyodideVersions()
|
||||||
|
|
||||||
def update_config(self, config: MutableMapping[str, str]) -> None:
|
def update_config(self, config: MutableMapping[str, str]) -> None:
|
||||||
identifier = config["identifier"]
|
identifier = config["identifier"]
|
||||||
version = Version(config["version"])
|
version = Version(config["version"])
|
||||||
@@ -407,6 +449,10 @@ class AllVersions:
|
|||||||
config_update = self.windows_arm64.update_version_windows(spec)
|
config_update = self.windows_arm64.update_version_windows(spec)
|
||||||
elif "ios" in identifier:
|
elif "ios" in identifier:
|
||||||
config_update = self.ios_cpython.update_version_ios(identifier, version)
|
config_update = self.ios_cpython.update_version_ios(identifier, version)
|
||||||
|
elif "pyodide" in identifier:
|
||||||
|
config_update = self.pyodide.update_version_pyodide(
|
||||||
|
identifier, version, spec, config["node_version"]
|
||||||
|
)
|
||||||
|
|
||||||
assert config_update is not None, f"{identifier} not found!"
|
assert config_update is not None, f"{identifier} not found!"
|
||||||
config.update(**config_update)
|
config.update(**config_update)
|
||||||
@@ -445,6 +491,9 @@ def update_pythons(force: bool, level: str) -> None:
|
|||||||
for config in configs["ios"]["python_configurations"]:
|
for config in configs["ios"]["python_configurations"]:
|
||||||
all_versions.update_config(config)
|
all_versions.update_config(config)
|
||||||
|
|
||||||
|
for config in configs["pyodide"]["python_configurations"]:
|
||||||
|
all_versions.update_config(config)
|
||||||
|
|
||||||
result_toml = dump_python_configurations(configs)
|
result_toml = dump_python_configurations(configs)
|
||||||
|
|
||||||
rich.print() # spacer
|
rich.print() # spacer
|
||||||
|
|||||||
+70
-1
@@ -2,9 +2,16 @@
|
|||||||
These are utilities for the `/bin` scripts, not for the `cibuildwheel` program.
|
These are utilities for the `/bin` scripts, not for the `cibuildwheel` program.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import typing
|
||||||
|
import urllib.error
|
||||||
|
import urllib.request
|
||||||
from collections.abc import Mapping, Sequence
|
from collections.abc import Mapping, Sequence
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from typing import Protocol
|
from typing import Any, NotRequired, Protocol
|
||||||
|
|
||||||
|
from cibuildwheel import __version__ as cibw_version
|
||||||
|
|
||||||
__all__ = ("Printable", "dump_python_configurations")
|
__all__ = ("Printable", "dump_python_configurations")
|
||||||
|
|
||||||
@@ -30,3 +37,65 @@ def dump_python_configurations(
|
|||||||
output.write("\n")
|
output.write("\n")
|
||||||
# Strip the final newline, to avoid two blank lines at the end.
|
# Strip the final newline, to avoid two blank lines at the end.
|
||||||
return output.getvalue()[:-1]
|
return output.getvalue()[:-1]
|
||||||
|
|
||||||
|
|
||||||
|
def _json_request(request: urllib.request.Request, timeout: int = 30) -> dict[str, Any]:
|
||||||
|
with urllib.request.urlopen(request, timeout=timeout) as response:
|
||||||
|
return typing.cast(dict[str, Any], json.load(response))
|
||||||
|
|
||||||
|
|
||||||
|
def github_api_request(path: str, *, max_retries: int = 3) -> dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Makes a GitHub API request to the given path and returns the JSON response.
|
||||||
|
"""
|
||||||
|
api_url = f"https://api.github.com/{path}"
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/vnd.github.v3+json",
|
||||||
|
"User-Agent": f"cibuildwheel/{cibw_version}",
|
||||||
|
}
|
||||||
|
request = urllib.request.Request(api_url, headers=headers)
|
||||||
|
|
||||||
|
for retry_count in range(max_retries):
|
||||||
|
try:
|
||||||
|
return _json_request(request)
|
||||||
|
except (urllib.error.URLError, TimeoutError) as e:
|
||||||
|
# pylint: disable=E1101
|
||||||
|
if (
|
||||||
|
isinstance(e, urllib.error.HTTPError)
|
||||||
|
and (e.code == 403 or e.code == 429)
|
||||||
|
and e.headers.get("x-ratelimit-remaining") == "0"
|
||||||
|
):
|
||||||
|
reset_time = int(e.headers.get("x-ratelimit-reset", 0))
|
||||||
|
wait_time = max(0, reset_time - int(e.headers.get("date", 0)))
|
||||||
|
print(f"Github rate limit exceeded. Waiting for {wait_time} seconds.")
|
||||||
|
time.sleep(wait_time)
|
||||||
|
else:
|
||||||
|
print(f"Retrying GitHub API request due to error: {e}")
|
||||||
|
|
||||||
|
if retry_count == max_retries - 1:
|
||||||
|
print(f"GitHub API request failed (Network error: {e}). Check network connection.")
|
||||||
|
raise e
|
||||||
|
|
||||||
|
# Should never be reached but to keep the type checker happy
|
||||||
|
msg = "Unexpected execution path in github_api_request"
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
class PyodideXBuildEnvRelease(typing.TypedDict):
|
||||||
|
version: str
|
||||||
|
python_version: str
|
||||||
|
emscripten_version: str
|
||||||
|
min_pyodide_build_version: NotRequired[str]
|
||||||
|
max_pyodide_build_version: NotRequired[str]
|
||||||
|
|
||||||
|
|
||||||
|
class PyodideXBuildEnvInfo(typing.TypedDict):
|
||||||
|
releases: dict[str, PyodideXBuildEnvRelease]
|
||||||
|
|
||||||
|
|
||||||
|
def get_pyodide_xbuildenv_info() -> PyodideXBuildEnvInfo:
|
||||||
|
xbuildenv_info_url = (
|
||||||
|
"https://pyodide.github.io/pyodide/api/pyodide-cross-build-environments.json"
|
||||||
|
)
|
||||||
|
with urllib.request.urlopen(xbuildenv_info_url) as response:
|
||||||
|
return typing.cast(PyodideXBuildEnvInfo, json.loads(response.read().decode("utf-8")))
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ class BuildOptions:
|
|||||||
build_frontend: BuildFrontendConfig | None
|
build_frontend: BuildFrontendConfig | None
|
||||||
config_settings: str
|
config_settings: str
|
||||||
container_engine: OCIContainerEngineConfig
|
container_engine: OCIContainerEngineConfig
|
||||||
|
pyodide_version: str | None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def package_dir(self) -> Path:
|
def package_dir(self) -> Path:
|
||||||
@@ -850,6 +851,8 @@ class Options:
|
|||||||
msg = f"Failed to parse container config. {e}"
|
msg = f"Failed to parse container config. {e}"
|
||||||
raise errors.ConfigurationError(msg) from e
|
raise errors.ConfigurationError(msg) from e
|
||||||
|
|
||||||
|
pyodide_version = self.reader.get("pyodide-version", env_plat=False)
|
||||||
|
|
||||||
return BuildOptions(
|
return BuildOptions(
|
||||||
globals=self.globals,
|
globals=self.globals,
|
||||||
test_command=test_command,
|
test_command=test_command,
|
||||||
@@ -871,6 +874,7 @@ class Options:
|
|||||||
build_frontend=build_frontend,
|
build_frontend=build_frontend,
|
||||||
config_settings=config_settings,
|
config_settings=config_settings,
|
||||||
container_engine=container_engine,
|
container_engine=container_engine,
|
||||||
|
pyodide_version=pyodide_version or None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def check_for_invalid_configuration(self, identifiers: Iterable[str]) -> None:
|
def check_for_invalid_configuration(self, identifiers: Iterable[str]) -> None:
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import functools
|
import functools
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import tomllib
|
import tomllib
|
||||||
|
import typing
|
||||||
from collections.abc import Set
|
from collections.abc import Set
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
from typing import Final
|
from typing import Final, TypedDict
|
||||||
|
|
||||||
from filelock import FileLock
|
from filelock import FileLock
|
||||||
|
|
||||||
@@ -28,8 +30,12 @@ from ..util.file import (
|
|||||||
extract_zip,
|
extract_zip,
|
||||||
move_file,
|
move_file,
|
||||||
)
|
)
|
||||||
from ..util.helpers import prepare_command
|
from ..util.helpers import prepare_command, unwrap, unwrap_preserving_paragraphs
|
||||||
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
|
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
|
||||||
|
from ..util.python_build_standalone import (
|
||||||
|
PythonBuildStandaloneError,
|
||||||
|
create_python_build_standalone_environment,
|
||||||
|
)
|
||||||
from ..venv import constraint_flags, virtualenv
|
from ..venv import constraint_flags, virtualenv
|
||||||
|
|
||||||
IS_WIN: Final[bool] = sys.platform.startswith("win")
|
IS_WIN: Final[bool] = sys.platform.startswith("win")
|
||||||
@@ -39,12 +45,23 @@ IS_WIN: Final[bool] = sys.platform.startswith("win")
|
|||||||
class PythonConfiguration:
|
class PythonConfiguration:
|
||||||
version: str
|
version: str
|
||||||
identifier: str
|
identifier: str
|
||||||
pyodide_version: str
|
default_pyodide_version: str
|
||||||
pyodide_build_version: str
|
|
||||||
emscripten_version: str
|
|
||||||
node_version: str
|
node_version: str
|
||||||
|
|
||||||
|
|
||||||
|
class PyodideXBuildEnvInfoVersionRange(TypedDict):
|
||||||
|
min: str | None
|
||||||
|
max: str | None
|
||||||
|
|
||||||
|
|
||||||
|
class PyodideXBuildEnvInfo(TypedDict):
|
||||||
|
version: str
|
||||||
|
python: str
|
||||||
|
emscripten: str
|
||||||
|
pyodide_build: PyodideXBuildEnvInfoVersionRange
|
||||||
|
compatible: bool
|
||||||
|
|
||||||
|
|
||||||
@functools.cache
|
@functools.cache
|
||||||
def ensure_node(major_version: str) -> Path:
|
def ensure_node(major_version: str) -> Path:
|
||||||
with resources.NODEJS.open("rb") as f:
|
with resources.NODEJS.open("rb") as f:
|
||||||
@@ -77,8 +94,6 @@ def ensure_node(major_version: str) -> Path:
|
|||||||
|
|
||||||
|
|
||||||
def install_emscripten(tmp: Path, version: str) -> Path:
|
def install_emscripten(tmp: Path, version: str) -> Path:
|
||||||
# We don't need to match the emsdk version to the version we install, but
|
|
||||||
# we do for stability
|
|
||||||
url = f"https://github.com/emscripten-core/emsdk/archive/refs/tags/{version}.zip"
|
url = f"https://github.com/emscripten-core/emsdk/archive/refs/tags/{version}.zip"
|
||||||
installation_path = CIBW_CACHE_PATH / f"emsdk-{version}"
|
installation_path = CIBW_CACHE_PATH / f"emsdk-{version}"
|
||||||
emsdk_path = installation_path / f"emsdk-{version}/emsdk"
|
emsdk_path = installation_path / f"emsdk-{version}/emsdk"
|
||||||
@@ -96,16 +111,82 @@ def install_emscripten(tmp: Path, version: str) -> Path:
|
|||||||
return emcc_path
|
return emcc_path
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_xbuildenv_version_info(env: dict[str, str]) -> list[PyodideXBuildEnvInfo]:
|
||||||
|
xbuildenvs_info_str = call(
|
||||||
|
"pyodide",
|
||||||
|
"xbuildenv",
|
||||||
|
"search",
|
||||||
|
"--json",
|
||||||
|
"--all",
|
||||||
|
env=env,
|
||||||
|
cwd=CIBW_CACHE_PATH,
|
||||||
|
capture_stdout=True,
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
xbuildenvs_info = json.loads(xbuildenvs_info_str)
|
||||||
|
|
||||||
|
if "environments" not in xbuildenvs_info:
|
||||||
|
msg = f"Invalid xbuildenvs info, got {xbuildenvs_info}"
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
return typing.cast(list[PyodideXBuildEnvInfo], xbuildenvs_info["environments"])
|
||||||
|
|
||||||
|
|
||||||
|
def get_xbuildenv_version_info(
|
||||||
|
env: dict[str, str], version: str, pyodide_build_version: str
|
||||||
|
) -> PyodideXBuildEnvInfo:
|
||||||
|
xbuildenvs_info = get_all_xbuildenv_version_info(env)
|
||||||
|
for xbuildenv_info in xbuildenvs_info:
|
||||||
|
if xbuildenv_info["version"] == version:
|
||||||
|
return xbuildenv_info
|
||||||
|
|
||||||
|
msg = unwrap(f"""
|
||||||
|
Could not find Pyodide cross-build environment version {version} in the available
|
||||||
|
versions as reported by pyodide-build v{pyodide_build_version}.
|
||||||
|
Available pyodide xbuildenv versions are:
|
||||||
|
{", ".join(e["version"] for e in xbuildenvs_info if e["compatible"])}
|
||||||
|
""")
|
||||||
|
raise errors.FatalError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
# The default pyodide xbuildenv version that's specified in
|
||||||
|
# build-platforms.toml is compatible with the pyodide-build version that's
|
||||||
|
# pinned in the bundled constraints file. But if the user changes
|
||||||
|
# pyodide-version and/or dependency-constraints in the cibuildwheel config, we
|
||||||
|
# need to check if the xbuildenv version is compatible with the pyodide-build
|
||||||
|
# version.
|
||||||
|
def validate_pyodide_build_version(
|
||||||
|
xbuildenv_info: PyodideXBuildEnvInfo, pyodide_build_version: str
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Validate the Pyodide version is compatible with the installed
|
||||||
|
pyodide-build version.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pyodide_version = xbuildenv_info["version"]
|
||||||
|
|
||||||
|
if not xbuildenv_info["compatible"]:
|
||||||
|
msg = unwrap_preserving_paragraphs(f"""
|
||||||
|
The Pyodide xbuildenv version {pyodide_version} is not compatible
|
||||||
|
with the pyodide-build version {pyodide_build_version}. Please use
|
||||||
|
the 'pyodide xbuildenv search --all' command to find a compatible
|
||||||
|
version.
|
||||||
|
|
||||||
|
Set the pyodide-build version using the `dependency-constraints`
|
||||||
|
option, or set the Pyodide xbuildenv version using the
|
||||||
|
`pyodide-version` option.
|
||||||
|
""")
|
||||||
|
raise errors.FatalError(msg)
|
||||||
|
|
||||||
|
|
||||||
def install_xbuildenv(env: dict[str, str], pyodide_build_version: str, pyodide_version: str) -> str:
|
def install_xbuildenv(env: dict[str, str], pyodide_build_version: str, pyodide_version: str) -> str:
|
||||||
"""Install a particular Pyodide xbuildenv version and set a path to the Pyodide root."""
|
"""Install a particular Pyodide xbuildenv version and set a path to the Pyodide root."""
|
||||||
# Since pyodide-build was unvendored from Pyodide v0.27.0, the versions of pyodide-build are
|
# Since pyodide-build was unvendored from Pyodide v0.27.0, the versions of
|
||||||
# not guaranteed to match the versions of Pyodide or be in sync with them. Hence, we shall
|
# pyodide-build are uncoupled from the versions of Pyodide. So, we specify
|
||||||
# specify the pyodide-build version in the root path, which will set up the xbuildenv for
|
# both the pyodide-build version and the Pyodide version in the temp path.
|
||||||
# the requested Pyodide version.
|
xbuildenv_cache_path = CIBW_CACHE_PATH / f"pyodide-build-{pyodide_build_version}"
|
||||||
pyodide_root = (
|
pyodide_root = xbuildenv_cache_path / pyodide_version / "xbuildenv" / "pyodide-root"
|
||||||
CIBW_CACHE_PATH
|
|
||||||
/ f".pyodide-xbuildenv-{pyodide_build_version}/{pyodide_version}/xbuildenv/pyodide-root"
|
|
||||||
)
|
|
||||||
with FileLock(CIBW_CACHE_PATH / "xbuildenv.lock"):
|
with FileLock(CIBW_CACHE_PATH / "xbuildenv.lock"):
|
||||||
if pyodide_root.exists():
|
if pyodide_root.exists():
|
||||||
return str(pyodide_root)
|
return str(pyodide_root)
|
||||||
@@ -114,31 +195,36 @@ def install_xbuildenv(env: dict[str, str], pyodide_build_version: str, pyodide_v
|
|||||||
# PYODIDE_ROOT so copy it first.
|
# PYODIDE_ROOT so copy it first.
|
||||||
env = dict(env)
|
env = dict(env)
|
||||||
env.pop("PYODIDE_ROOT", None)
|
env.pop("PYODIDE_ROOT", None)
|
||||||
|
|
||||||
|
# Install the xbuildenv
|
||||||
call(
|
call(
|
||||||
"pyodide",
|
"pyodide",
|
||||||
"xbuildenv",
|
"xbuildenv",
|
||||||
"install",
|
"install",
|
||||||
|
"--path",
|
||||||
|
str(xbuildenv_cache_path),
|
||||||
pyodide_version,
|
pyodide_version,
|
||||||
env=env,
|
env=env,
|
||||||
cwd=CIBW_CACHE_PATH,
|
cwd=CIBW_CACHE_PATH,
|
||||||
)
|
)
|
||||||
|
assert pyodide_root.exists()
|
||||||
|
|
||||||
return str(pyodide_root)
|
return str(pyodide_root)
|
||||||
|
|
||||||
|
|
||||||
def get_base_python(identifier: str) -> Path:
|
def get_base_python(tmp: Path, python_configuration: PythonConfiguration) -> Path:
|
||||||
implementation_id = identifier.split("-")[0]
|
try:
|
||||||
majorminor = implementation_id[len("cp") :]
|
return create_python_build_standalone_environment(
|
||||||
version_info = (int(majorminor[0]), int(majorminor[1:]))
|
python_version=python_configuration.version,
|
||||||
if version_info == sys.version_info[:2]:
|
temp_dir=tmp,
|
||||||
return Path(sys.executable)
|
cache_dir=CIBW_CACHE_PATH,
|
||||||
|
)
|
||||||
major_minor = ".".join(str(v) for v in version_info)
|
except PythonBuildStandaloneError as e:
|
||||||
python_name = f"python{major_minor}"
|
msg = unwrap(f"""
|
||||||
which_python = shutil.which(python_name)
|
Failed to create a Python build environment:
|
||||||
if which_python is None:
|
{e}
|
||||||
msg = f"CPython {major_minor} is not installed."
|
""")
|
||||||
raise errors.FatalError(msg)
|
raise errors.FatalError(msg) from e
|
||||||
return Path(which_python)
|
|
||||||
|
|
||||||
|
|
||||||
def setup_python(
|
def setup_python(
|
||||||
@@ -146,10 +232,13 @@ def setup_python(
|
|||||||
python_configuration: PythonConfiguration,
|
python_configuration: PythonConfiguration,
|
||||||
constraints_path: Path | None,
|
constraints_path: Path | None,
|
||||||
environment: ParsedEnvironment,
|
environment: ParsedEnvironment,
|
||||||
|
user_pyodide_version: str | None,
|
||||||
) -> dict[str, str]:
|
) -> dict[str, str]:
|
||||||
base_python = get_base_python(python_configuration.identifier)
|
log.step("Installing a base python environment...")
|
||||||
|
base_python = get_base_python(tmp / "base", python_configuration)
|
||||||
|
|
||||||
log.step("Setting up build environment...")
|
log.step("Setting up build environment...")
|
||||||
|
pyodide_version = user_pyodide_version or python_configuration.default_pyodide_version
|
||||||
venv_path = tmp / "venv"
|
venv_path = tmp / "venv"
|
||||||
env = virtualenv(python_configuration.version, base_python, venv_path, None, use_uv=False)
|
env = virtualenv(python_configuration.version, base_python, venv_path, None, use_uv=False)
|
||||||
venv_bin_path = venv_path / "bin"
|
venv_bin_path = venv_path / "bin"
|
||||||
@@ -201,15 +290,28 @@ def setup_python(
|
|||||||
env=env,
|
env=env,
|
||||||
)
|
)
|
||||||
|
|
||||||
log.step(f"Installing Emscripten version: {python_configuration.emscripten_version} ...")
|
pyodide_build_version = call(
|
||||||
emcc_path = install_emscripten(tmp, python_configuration.emscripten_version)
|
"python",
|
||||||
|
"-c",
|
||||||
|
"from importlib.metadata import version; print(version('pyodide-build'))",
|
||||||
|
env=env,
|
||||||
|
capture_stdout=True,
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
xbuildenv_info = get_xbuildenv_version_info(env, pyodide_version, pyodide_build_version)
|
||||||
|
validate_pyodide_build_version(
|
||||||
|
xbuildenv_info=xbuildenv_info,
|
||||||
|
pyodide_build_version=pyodide_build_version,
|
||||||
|
)
|
||||||
|
|
||||||
|
emscripten_version = xbuildenv_info["emscripten"]
|
||||||
|
log.step(f"Installing Emscripten version: {emscripten_version} ...")
|
||||||
|
emcc_path = install_emscripten(tmp, emscripten_version)
|
||||||
|
|
||||||
env["PATH"] = os.pathsep.join([str(emcc_path.parent), env["PATH"]])
|
env["PATH"] = os.pathsep.join([str(emcc_path.parent), env["PATH"]])
|
||||||
|
|
||||||
log.step(f"Installing Pyodide xbuildenv version: {python_configuration.pyodide_version} ...")
|
log.step(f"Installing Pyodide xbuildenv version: {pyodide_version} ...")
|
||||||
env["PYODIDE_ROOT"] = install_xbuildenv(
|
env["PYODIDE_ROOT"] = install_xbuildenv(env, pyodide_build_version, pyodide_version)
|
||||||
env, python_configuration.pyodide_build_version, python_configuration.pyodide_version
|
|
||||||
)
|
|
||||||
|
|
||||||
return env
|
return env
|
||||||
|
|
||||||
@@ -259,6 +361,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
log.build_start(config.identifier)
|
log.build_start(config.identifier)
|
||||||
|
|
||||||
identifier_tmp_dir = tmp_path / config.identifier
|
identifier_tmp_dir = tmp_path / config.identifier
|
||||||
|
|
||||||
built_wheel_dir = identifier_tmp_dir / "built_wheel"
|
built_wheel_dir = identifier_tmp_dir / "built_wheel"
|
||||||
repaired_wheel_dir = identifier_tmp_dir / "repaired_wheel"
|
repaired_wheel_dir = identifier_tmp_dir / "repaired_wheel"
|
||||||
identifier_tmp_dir.mkdir()
|
identifier_tmp_dir.mkdir()
|
||||||
@@ -270,10 +373,11 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
env = setup_python(
|
env = setup_python(
|
||||||
identifier_tmp_dir / "build",
|
tmp=identifier_tmp_dir / "build",
|
||||||
config,
|
python_configuration=config,
|
||||||
constraints_path,
|
constraints_path=constraints_path,
|
||||||
build_options.environment,
|
environment=build_options.environment,
|
||||||
|
user_pyodide_version=build_options.pyodide_version,
|
||||||
)
|
)
|
||||||
pip_version = get_pip_version(env)
|
pip_version = get_pip_version(env)
|
||||||
# The Pyodide command line runner mounts all directories in the host
|
# The Pyodide command line runner mounts all directories in the host
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ python_configurations = [
|
|||||||
|
|
||||||
[pyodide]
|
[pyodide]
|
||||||
python_configurations = [
|
python_configurations = [
|
||||||
{ identifier = "cp312-pyodide_wasm32", version = "3.12", pyodide_version = "0.27.0", pyodide_build_version = "0.29.2", emscripten_version = "3.1.58", node_version = "v20" },
|
{ identifier = "cp312-pyodide_wasm32", version = "3.12", default_pyodide_version = "0.27.6", node_version = "v22" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[ios]
|
[ios]
|
||||||
|
|||||||
@@ -424,6 +424,11 @@
|
|||||||
],
|
],
|
||||||
"title": "CIBW_XBUILD_TOOLS"
|
"title": "CIBW_XBUILD_TOOLS"
|
||||||
},
|
},
|
||||||
|
"pyodide-version": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Specify the version of Pyodide to use",
|
||||||
|
"title": "CIBW_PYODIDE_VERSION"
|
||||||
|
},
|
||||||
"repair-wheel-command": {
|
"repair-wheel-command": {
|
||||||
"description": "Execute a shell command to repair each built wheel.",
|
"description": "Execute a shell command to repair each built wheel.",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
@@ -718,6 +723,9 @@
|
|||||||
"xbuild-tools": {
|
"xbuild-tools": {
|
||||||
"$ref": "#/properties/xbuild-tools"
|
"$ref": "#/properties/xbuild-tools"
|
||||||
},
|
},
|
||||||
|
"pyodide-version": {
|
||||||
|
"$ref": "#/properties/pyodide-version"
|
||||||
|
},
|
||||||
"repair-wheel-command": {
|
"repair-wheel-command": {
|
||||||
"$ref": "#/properties/repair-wheel-command"
|
"$ref": "#/properties/repair-wheel-command"
|
||||||
},
|
},
|
||||||
@@ -830,6 +838,9 @@
|
|||||||
"xbuild-tools": {
|
"xbuild-tools": {
|
||||||
"$ref": "#/properties/xbuild-tools"
|
"$ref": "#/properties/xbuild-tools"
|
||||||
},
|
},
|
||||||
|
"pyodide-version": {
|
||||||
|
"$ref": "#/properties/pyodide-version"
|
||||||
|
},
|
||||||
"repair-wheel-command": {
|
"repair-wheel-command": {
|
||||||
"description": "Execute a shell command to repair each built wheel.",
|
"description": "Execute a shell command to repair each built wheel.",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
@@ -900,6 +911,9 @@
|
|||||||
"xbuild-tools": {
|
"xbuild-tools": {
|
||||||
"$ref": "#/properties/xbuild-tools"
|
"$ref": "#/properties/xbuild-tools"
|
||||||
},
|
},
|
||||||
|
"pyodide-version": {
|
||||||
|
"$ref": "#/properties/pyodide-version"
|
||||||
|
},
|
||||||
"repair-wheel-command": {
|
"repair-wheel-command": {
|
||||||
"$ref": "#/properties/repair-wheel-command"
|
"$ref": "#/properties/repair-wheel-command"
|
||||||
},
|
},
|
||||||
@@ -957,6 +971,9 @@
|
|||||||
"xbuild-tools": {
|
"xbuild-tools": {
|
||||||
"$ref": "#/properties/xbuild-tools"
|
"$ref": "#/properties/xbuild-tools"
|
||||||
},
|
},
|
||||||
|
"pyodide-version": {
|
||||||
|
"$ref": "#/properties/pyodide-version"
|
||||||
|
},
|
||||||
"repair-wheel-command": {
|
"repair-wheel-command": {
|
||||||
"description": "Execute a shell command to repair each built wheel.",
|
"description": "Execute a shell command to repair each built wheel.",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
@@ -1027,6 +1044,9 @@
|
|||||||
"xbuild-tools": {
|
"xbuild-tools": {
|
||||||
"$ref": "#/properties/xbuild-tools"
|
"$ref": "#/properties/xbuild-tools"
|
||||||
},
|
},
|
||||||
|
"pyodide-version": {
|
||||||
|
"$ref": "#/properties/pyodide-version"
|
||||||
|
},
|
||||||
"repair-wheel-command": {
|
"repair-wheel-command": {
|
||||||
"$ref": "#/properties/repair-wheel-command"
|
"$ref": "#/properties/repair-wheel-command"
|
||||||
},
|
},
|
||||||
@@ -1084,6 +1104,9 @@
|
|||||||
"xbuild-tools": {
|
"xbuild-tools": {
|
||||||
"$ref": "#/properties/xbuild-tools"
|
"$ref": "#/properties/xbuild-tools"
|
||||||
},
|
},
|
||||||
|
"pyodide-version": {
|
||||||
|
"$ref": "#/properties/pyodide-version"
|
||||||
|
},
|
||||||
"repair-wheel-command": {
|
"repair-wheel-command": {
|
||||||
"$ref": "#/properties/repair-wheel-command"
|
"$ref": "#/properties/repair-wheel-command"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ annotated-types==0.7.0
|
|||||||
# via pydantic
|
# via pydantic
|
||||||
anyio==4.9.0
|
anyio==4.9.0
|
||||||
# via httpx
|
# via httpx
|
||||||
auditwheel-emscripten==0.0.16
|
auditwheel-emscripten==0.1.0
|
||||||
# via pyodide-build
|
# via pyodide-build
|
||||||
build==1.2.2.post1
|
build==1.2.2.post1
|
||||||
# via
|
# via
|
||||||
@@ -21,8 +21,6 @@ click==8.1.8
|
|||||||
# via
|
# via
|
||||||
# -r .nox/update_constraints/tmp/constraints-pyodide.in
|
# -r .nox/update_constraints/tmp/constraints-pyodide.in
|
||||||
# typer
|
# typer
|
||||||
cmake==4.0.2
|
|
||||||
# via pyodide-build
|
|
||||||
distlib==0.3.9
|
distlib==0.3.9
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.18.0
|
filelock==3.18.0
|
||||||
@@ -53,7 +51,9 @@ packaging==25.0
|
|||||||
pip==25.1.1
|
pip==25.1.1
|
||||||
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
|
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
|
||||||
platformdirs==4.3.8
|
platformdirs==4.3.8
|
||||||
# via virtualenv
|
# via
|
||||||
|
# pyodide-build
|
||||||
|
# virtualenv
|
||||||
pydantic==2.11.4
|
pydantic==2.11.4
|
||||||
# via
|
# via
|
||||||
# pyodide-build
|
# pyodide-build
|
||||||
@@ -62,9 +62,9 @@ pydantic-core==2.33.2
|
|||||||
# via pydantic
|
# via pydantic
|
||||||
pygments==2.19.1
|
pygments==2.19.1
|
||||||
# via rich
|
# via rich
|
||||||
pyodide-build==0.29.2
|
pyodide-build==0.30.4
|
||||||
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
|
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
|
||||||
pyodide-cli==0.2.4
|
pyodide-cli==0.3.0
|
||||||
# via
|
# via
|
||||||
# auditwheel-emscripten
|
# auditwheel-emscripten
|
||||||
# pyodide-build
|
# pyodide-build
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ test-environment = {}
|
|||||||
|
|
||||||
container-engine = "docker"
|
container-engine = "docker"
|
||||||
|
|
||||||
|
pyodide-version = ""
|
||||||
|
|
||||||
manylinux-x86_64-image = "manylinux_2_28"
|
manylinux-x86_64-image = "manylinux_2_28"
|
||||||
manylinux-i686-image = "manylinux2014"
|
manylinux-i686-image = "manylinux2014"
|
||||||
manylinux-aarch64-image = "manylinux_2_28"
|
manylinux-aarch64-image = "manylinux_2_28"
|
||||||
|
|||||||
@@ -0,0 +1,425 @@
|
|||||||
|
{
|
||||||
|
"releases": [
|
||||||
|
{
|
||||||
|
"tag": "20250409",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-aarch64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-aarch64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-aarch64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-aarch64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-i686-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-i686-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-riscv64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-riscv64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-s390x-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-s390x-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.10.17+20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.10.17%2B20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-aarch64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-aarch64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-aarch64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-aarch64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-i686-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-i686-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-riscv64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-riscv64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-s390x-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-s390x-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.11.12+20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.11.12%2B20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-aarch64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-aarch64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-aarch64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-aarch64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-i686-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-i686-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-riscv64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-riscv64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-s390x-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-s390x-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.12.10+20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.12.10%2B20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-aarch64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-aarch64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-aarch64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-aarch64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-i686-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-i686-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-riscv64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-riscv64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-s390x-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-s390x-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.13.3+20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3%2B20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-aarch64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-aarch64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-aarch64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-aarch64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-i686-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-i686-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-riscv64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-riscv64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-s390x-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-s390x-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-x86_64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-x86_64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-x86_64-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-x86_64-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-x86_64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-x86_64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.14.0a6+20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.14.0a6%2B20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-aarch64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-aarch64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-aarch64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-aarch64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-armv7-unknown-linux-gnueabi-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-armv7-unknown-linux-gnueabihf-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-i686-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-i686-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-ppc64le-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-riscv64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-riscv64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-s390x-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-s390x-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64-apple-darwin-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64-apple-darwin-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64-pc-windows-msvc-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64-pc-windows-msvc-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64_v2-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64_v2-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64_v3-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64_v4-unknown-linux-gnu-install_only.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpython-3.9.22+20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz",
|
||||||
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.9.22%2B20250409-x86_64_v4-unknown-linux-musl-install_only.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -165,6 +165,9 @@ def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> T | None:
|
|||||||
continue
|
continue
|
||||||
if not tag.platform.endswith(f"_{arch}"):
|
if not tag.platform.endswith(f"_{arch}"):
|
||||||
continue
|
continue
|
||||||
|
elif platform.startswith("pyodide"):
|
||||||
|
# each Pyodide version has its own platform tag
|
||||||
|
continue
|
||||||
else:
|
else:
|
||||||
# Windows should exactly match
|
# Windows should exactly match
|
||||||
if tag.platform != platform:
|
if tag.platform != platform:
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
import fnmatch
|
||||||
|
import functools
|
||||||
|
import json
|
||||||
|
import platform
|
||||||
|
import typing
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from filelock import FileLock
|
||||||
|
|
||||||
|
from cibuildwheel.util.file import download, extract_tar
|
||||||
|
from cibuildwheel.util.resources import PYTHON_BUILD_STANDALONE_RELEASES
|
||||||
|
|
||||||
|
|
||||||
|
class PythonBuildStandaloneAsset(typing.TypedDict):
|
||||||
|
name: str
|
||||||
|
url: str
|
||||||
|
|
||||||
|
|
||||||
|
class PythonBuildStandaloneRelease(typing.TypedDict):
|
||||||
|
tag: str
|
||||||
|
assets: list[PythonBuildStandaloneAsset]
|
||||||
|
|
||||||
|
|
||||||
|
class PythonBuildStandaloneReleaseData(typing.TypedDict):
|
||||||
|
releases: list[PythonBuildStandaloneRelease]
|
||||||
|
|
||||||
|
|
||||||
|
@functools.cache
|
||||||
|
def get_python_build_standalone_release_data() -> PythonBuildStandaloneReleaseData:
|
||||||
|
with open(PYTHON_BUILD_STANDALONE_RELEASES, "rb") as f:
|
||||||
|
return typing.cast(PythonBuildStandaloneReleaseData, json.load(f))
|
||||||
|
|
||||||
|
|
||||||
|
class PythonBuildStandaloneError(Exception):
|
||||||
|
"""Errors related to python-build-standalone."""
|
||||||
|
|
||||||
|
|
||||||
|
def _get_platform_identifiers() -> tuple[str, str, str | None]:
|
||||||
|
"""
|
||||||
|
Detects the current platform and returns architecture, platform, and libc
|
||||||
|
identifiers.
|
||||||
|
"""
|
||||||
|
system = platform.system()
|
||||||
|
machine = platform.machine()
|
||||||
|
machine_lower = machine.lower()
|
||||||
|
|
||||||
|
arch_identifier: str
|
||||||
|
platform_identifier: str
|
||||||
|
libc_identifier: str | None = None
|
||||||
|
|
||||||
|
# Map Architecture
|
||||||
|
if machine_lower in ["x86_64", "amd64"]:
|
||||||
|
arch_identifier = "x86_64"
|
||||||
|
elif machine_lower in ["aarch64", "arm64"]:
|
||||||
|
arch_identifier = "aarch64"
|
||||||
|
else:
|
||||||
|
msg = f"Unsupported architecture: {system} {machine}. Cannot download appropriate Python build."
|
||||||
|
raise PythonBuildStandaloneError(msg)
|
||||||
|
|
||||||
|
# Map OS + Libc
|
||||||
|
if system == "Linux":
|
||||||
|
platform_identifier = "unknown-linux"
|
||||||
|
libc_identifier = "musl" if "musl" in (platform.libc_ver() or ("", "")) else "gnu"
|
||||||
|
elif system == "Darwin":
|
||||||
|
platform_identifier = "apple-darwin"
|
||||||
|
elif system == "Windows":
|
||||||
|
platform_identifier = "pc-windows-msvc"
|
||||||
|
else:
|
||||||
|
msg = f"Unsupported operating system: {system}. Cannot download appropriate Python build."
|
||||||
|
raise PythonBuildStandaloneError(msg)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"Detected platform: arch='{arch_identifier}', platform='{platform_identifier}', libc='{libc_identifier}'"
|
||||||
|
)
|
||||||
|
return arch_identifier, platform_identifier, libc_identifier
|
||||||
|
|
||||||
|
|
||||||
|
def _get_pbs_asset(
|
||||||
|
*,
|
||||||
|
python_version: str,
|
||||||
|
arch_identifier: str,
|
||||||
|
platform_identifier: str,
|
||||||
|
libc_identifier: str | None,
|
||||||
|
) -> tuple[str, str, str]:
|
||||||
|
"""Finds the asset, returning (tag, filename, url)."""
|
||||||
|
release_data = get_python_build_standalone_release_data()
|
||||||
|
|
||||||
|
expected_suffix = f"{arch_identifier}-{platform_identifier}"
|
||||||
|
if libc_identifier:
|
||||||
|
expected_suffix += f"-{libc_identifier}"
|
||||||
|
expected_suffix += "-install_only.tar.gz"
|
||||||
|
|
||||||
|
asset_pattern = f"cpython-{python_version}.*-{expected_suffix}"
|
||||||
|
print(f"Looking for file with pattern {asset_pattern}")
|
||||||
|
|
||||||
|
for release in release_data["releases"]:
|
||||||
|
for asset in release["assets"]:
|
||||||
|
asset_name = asset["name"]
|
||||||
|
if not fnmatch.fnmatch(asset_name, asset_pattern):
|
||||||
|
continue
|
||||||
|
|
||||||
|
asset_url = asset["url"]
|
||||||
|
return release["tag"], asset_url, asset_name
|
||||||
|
|
||||||
|
# If loop completes without finding a match
|
||||||
|
msg = f"Could not find python-build-standalone release asset matching {asset_pattern!r}."
|
||||||
|
raise PythonBuildStandaloneError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _download_or_get_from_cache(asset_url: str, asset_filename: str, cache_dir: Path) -> Path:
|
||||||
|
with FileLock(cache_dir / (asset_filename + ".lock")):
|
||||||
|
asset_cache_path = cache_dir / asset_filename
|
||||||
|
if asset_cache_path.is_file():
|
||||||
|
print(f"Using cached python_build_standalone: {asset_cache_path}")
|
||||||
|
return asset_cache_path
|
||||||
|
|
||||||
|
print(f"Downloading python_build_standalone: {asset_url} to {asset_cache_path}")
|
||||||
|
download(asset_url, asset_cache_path)
|
||||||
|
return asset_cache_path
|
||||||
|
|
||||||
|
|
||||||
|
def _find_python_executable(extracted_dir: Path) -> Path:
|
||||||
|
"""Finds the python executable within the extracted directory structure."""
|
||||||
|
# Structure is typically 'python/bin/python' or 'python/python.exe'
|
||||||
|
base_install_dir = extracted_dir / "python"
|
||||||
|
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
executable_path = base_install_dir / "python.exe"
|
||||||
|
else:
|
||||||
|
executable_path = base_install_dir / "bin" / "python"
|
||||||
|
|
||||||
|
if not executable_path.is_file():
|
||||||
|
msg = f"Could not locate python executable at expected path {executable_path} within {extracted_dir}."
|
||||||
|
raise PythonBuildStandaloneError(msg)
|
||||||
|
|
||||||
|
print(f"Found python executable: {executable_path}")
|
||||||
|
return executable_path.resolve() # Return absolute path
|
||||||
|
|
||||||
|
|
||||||
|
def create_python_build_standalone_environment(
|
||||||
|
python_version: str, temp_dir: Path, cache_dir: Path
|
||||||
|
) -> Path:
|
||||||
|
"""
|
||||||
|
Returns a Python environment from python-build-standalone, downloading it
|
||||||
|
if necessary using a cache, and expanding it into a fresh base path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
python_version: The Python version string (e.g., "3.12").
|
||||||
|
temp_dir: A directory where the Python environment will be created.
|
||||||
|
cache_dir: A directory to store/retrieve downloaded archives.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The absolute path to the python executable within the created environment (in temp_dir).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PythonBuildStandaloneError: If the platform is unsupported, the build cannot be found,
|
||||||
|
download/extraction fails, or configuration is invalid.
|
||||||
|
"""
|
||||||
|
|
||||||
|
print(f"Creating python-build-standalone environment: version={python_version}")
|
||||||
|
|
||||||
|
arch_id, platform_id, libc_id = _get_platform_identifiers()
|
||||||
|
|
||||||
|
pbs_tag, asset_url, asset_filename = _get_pbs_asset(
|
||||||
|
python_version=python_version,
|
||||||
|
arch_identifier=arch_id,
|
||||||
|
platform_identifier=platform_id,
|
||||||
|
libc_identifier=libc_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Using python-build-standalone release: {pbs_tag}")
|
||||||
|
|
||||||
|
archive_path = _download_or_get_from_cache(
|
||||||
|
asset_url=asset_url, asset_filename=asset_filename, cache_dir=cache_dir
|
||||||
|
)
|
||||||
|
|
||||||
|
python_base_dir = temp_dir / "pbs"
|
||||||
|
assert not python_base_dir.exists()
|
||||||
|
extract_tar(archive_path, python_base_dir)
|
||||||
|
|
||||||
|
return _find_python_executable(python_base_dir)
|
||||||
@@ -16,6 +16,7 @@ BUILD_PLATFORMS: Final[Path] = PATH / "build-platforms.toml"
|
|||||||
CONSTRAINTS: Final[Path] = PATH / "constraints.txt"
|
CONSTRAINTS: Final[Path] = PATH / "constraints.txt"
|
||||||
VIRTUALENV: Final[Path] = PATH / "virtualenv.toml"
|
VIRTUALENV: Final[Path] = PATH / "virtualenv.toml"
|
||||||
CIBUILDWHEEL_SCHEMA: Final[Path] = PATH / "cibuildwheel.schema.json"
|
CIBUILDWHEEL_SCHEMA: Final[Path] = PATH / "cibuildwheel.schema.json"
|
||||||
|
PYTHON_BUILD_STANDALONE_RELEASES: Final[Path] = PATH / "python-build-standalone-releases.json"
|
||||||
|
|
||||||
|
|
||||||
# this value is cached because it's used a lot in unit tests
|
# this value is cached because it's used a lot in unit tests
|
||||||
|
|||||||
+55
-18
@@ -17,7 +17,9 @@ Default: `auto`
|
|||||||
- For `linux`, you need [Docker or Podman](#container-engine) running, on Linux, macOS, or Windows.
|
- For `linux`, you need [Docker or Podman](#container-engine) running, on Linux, macOS, or Windows.
|
||||||
- For `macos` and `windows`, you need to be running on the respective system, with a working compiler toolchain installed - Xcode Command Line tools for macOS, and MSVC for Windows.
|
- For `macos` and `windows`, you need to be running on the respective system, with a working compiler toolchain installed - Xcode Command Line tools for macOS, and MSVC for Windows.
|
||||||
- For `ios` you need to be running on macOS, with Xcode and the iOS simulator installed.
|
- For `ios` you need to be running on macOS, with Xcode and the iOS simulator installed.
|
||||||
- For `pyodide` you need to be on an x86-64 linux runner and `python3.12` must be available in `PATH`.
|
- For `pyodide`, you need a Linux or macOS machine.
|
||||||
|
|
||||||
|
Check the [platforms](platforms.md) page for more information on platform requirements.
|
||||||
|
|
||||||
This option can also be set using the [command-line option](#command-line) `--platform`. This option is not available in the `pyproject.toml` config.
|
This option can also be set using the [command-line option](#command-line) `--platform`. This option is not available in the `pyproject.toml` config.
|
||||||
|
|
||||||
@@ -49,20 +51,19 @@ When both options are specified, both conditions are applied and only builds wit
|
|||||||
When setting the options, you can use shell-style globbing syntax, as per [fnmatch](https://docs.python.org/3/library/fnmatch.html) with the addition of curly bracket syntax `{option1,option2}`, provided by [bracex](https://pypi.org/project/bracex/). All the build identifiers supported by cibuildwheel are shown below:
|
When setting the options, you can use shell-style globbing syntax, as per [fnmatch](https://docs.python.org/3/library/fnmatch.html) with the addition of curly bracket syntax `{option1,option2}`, provided by [bracex](https://pypi.org/project/bracex/). All the build identifiers supported by cibuildwheel are shown below:
|
||||||
|
|
||||||
<div class="build-id-table-marker"></div>
|
<div class="build-id-table-marker"></div>
|
||||||
|
| | macOS | Windows | Linux Intel | Linux Other | iOS | pyodide (WASM) |
|
||||||
| | macOS | Windows | Linux Intel | Linux Other | iOS |
|
|---------------|------------------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|----------------------|
|
||||||
|---------------|------------------------------------------------------------------------|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
|
| Python 3.8 | cp38-macosx_x86_64<br/>cp38-macosx_universal2<br/>cp38-macosx_arm64 | cp38-win_amd64<br/>cp38-win32 | cp38-manylinux_x86_64<br/>cp38-manylinux_i686<br/>cp38-musllinux_x86_64<br/>cp38-musllinux_i686 | cp38-manylinux_aarch64<br/>cp38-manylinux_ppc64le<br/>cp38-manylinux_s390x<br/>cp38-manylinux_armv7l<br/>cp38-manylinux_riscv64<br/>cp38-musllinux_aarch64<br/>cp38-musllinux_ppc64le<br/>cp38-musllinux_s390x<br/>cp38-musllinux_armv7l<br/>cp38-musllinux_riscv64 | | |
|
||||||
| Python 3.8 | cp38-macosx_x86_64<br/>cp38-macosx_universal2<br/>cp38-macosx_arm64 | cp38-win_amd64<br/>cp38-win32 | cp38-manylinux_x86_64<br/>cp38-manylinux_i686<br/>cp38-musllinux_x86_64<br/>cp38-musllinux_i686 | cp38-manylinux_aarch64<br/>cp38-manylinux_ppc64le<br/>cp38-manylinux_s390x<br/>cp38-manylinux_armv7l<br/>cp38-manylinux_riscv64<br/>cp38-musllinux_aarch64<br/>cp38-musllinux_ppc64le<br/>cp38-musllinux_s390x<br/>cp38-musllinux_armv7l<br/>cp38-musllinux_riscv64 | |
|
| Python 3.9 | cp39-macosx_x86_64<br/>cp39-macosx_universal2<br/>cp39-macosx_arm64 | cp39-win_amd64<br/>cp39-win32<br/>cp39-win_arm64 | cp39-manylinux_x86_64<br/>cp39-manylinux_i686<br/>cp39-musllinux_x86_64<br/>cp39-musllinux_i686 | cp39-manylinux_aarch64<br/>cp39-manylinux_ppc64le<br/>cp39-manylinux_s390x<br/>cp39-manylinux_armv7l<br/>cp39-manylinux_riscv64<br/>cp39-musllinux_aarch64<br/>cp39-musllinux_ppc64le<br/>cp39-musllinux_s390x<br/>cp39-musllinux_armv7l<br/>cp39-musllinux_riscv64 | | |
|
||||||
| Python 3.9 | cp39-macosx_x86_64<br/>cp39-macosx_universal2<br/>cp39-macosx_arm64 | cp39-win_amd64<br/>cp39-win32<br/>cp39-win_arm64 | cp39-manylinux_x86_64<br/>cp39-manylinux_i686<br/>cp39-musllinux_x86_64<br/>cp39-musllinux_i686 | cp39-manylinux_aarch64<br/>cp39-manylinux_ppc64le<br/>cp39-manylinux_s390x<br/>cp39-manylinux_armv7l<br/>cp39-manylinux_riscv64<br/>cp39-musllinux_aarch64<br/>cp39-musllinux_ppc64le<br/>cp39-musllinux_s390x<br/>cp39-musllinux_armv7l<br/>cp39-musllinux_riscv64 | |
|
| Python 3.10 | cp310-macosx_x86_64<br/>cp310-macosx_universal2<br/>cp310-macosx_arm64 | cp310-win_amd64<br/>cp310-win32<br/>cp310-win_arm64 | cp310-manylinux_x86_64<br/>cp310-manylinux_i686<br/>cp310-musllinux_x86_64<br/>cp310-musllinux_i686 | cp310-manylinux_aarch64<br/>cp310-manylinux_ppc64le<br/>cp310-manylinux_s390x<br/>cp310-manylinux_armv7l<br/>cp310-manylinux_riscv64<br/>cp310-musllinux_aarch64<br/>cp310-musllinux_ppc64le<br/>cp310-musllinux_s390x<br/>cp310-musllinux_armv7l<br/>cp310-musllinux_riscv64 | | |
|
||||||
| Python 3.10 | cp310-macosx_x86_64<br/>cp310-macosx_universal2<br/>cp310-macosx_arm64 | cp310-win_amd64<br/>cp310-win32<br/>cp310-win_arm64 | cp310-manylinux_x86_64<br/>cp310-manylinux_i686<br/>cp310-musllinux_x86_64<br/>cp310-musllinux_i686 | cp310-manylinux_aarch64<br/>cp310-manylinux_ppc64le<br/>cp310-manylinux_s390x<br/>cp310-manylinux_armv7l<br/>cp310-manylinux_riscv64<br/>cp310-musllinux_aarch64<br/>cp310-musllinux_ppc64le<br/>cp310-musllinux_s390x<br/>cp310-musllinux_armv7l<br/>cp310-musllinux_riscv64 | |
|
| Python 3.11 | cp311-macosx_x86_64<br/>cp311-macosx_universal2<br/>cp311-macosx_arm64 | cp311-win_amd64<br/>cp311-win32<br/>cp311-win_arm64 | cp311-manylinux_x86_64<br/>cp311-manylinux_i686<br/>cp311-musllinux_x86_64<br/>cp311-musllinux_i686 | cp311-manylinux_aarch64<br/>cp311-manylinux_ppc64le<br/>cp311-manylinux_s390x<br/>cp311-manylinux_armv7l<br/>cp311-manylinux_riscv64<br/>cp311-musllinux_aarch64<br/>cp311-musllinux_ppc64le<br/>cp311-musllinux_s390x<br/>cp311-musllinux_armv7l<br/>cp311-musllinux_riscv64 | | |
|
||||||
| Python 3.11 | cp311-macosx_x86_64<br/>cp311-macosx_universal2<br/>cp311-macosx_arm64 | cp311-win_amd64<br/>cp311-win32<br/>cp311-win_arm64 | cp311-manylinux_x86_64<br/>cp311-manylinux_i686<br/>cp311-musllinux_x86_64<br/>cp311-musllinux_i686 | cp311-manylinux_aarch64<br/>cp311-manylinux_ppc64le<br/>cp311-manylinux_s390x<br/>cp311-manylinux_armv7l<br/>cp311-manylinux_riscv64<br/>cp311-musllinux_aarch64<br/>cp311-musllinux_ppc64le<br/>cp311-musllinux_s390x<br/>cp311-musllinux_armv7l<br/>cp311-musllinux_riscv64 | |
|
| Python 3.12 | cp312-macosx_x86_64<br/>cp312-macosx_universal2<br/>cp312-macosx_arm64 | cp312-win_amd64<br/>cp312-win32<br/>cp312-win_arm64 | cp312-manylinux_x86_64<br/>cp312-manylinux_i686<br/>cp312-musllinux_x86_64<br/>cp312-musllinux_i686 | cp312-manylinux_aarch64<br/>cp312-manylinux_ppc64le<br/>cp312-manylinux_s390x<br/>cp312-manylinux_armv7l<br/>cp312-manylinux_riscv64<br/>cp312-musllinux_aarch64<br/>cp312-musllinux_ppc64le<br/>cp312-musllinux_s390x<br/>cp312-musllinux_armv7l<br/>cp312-musllinux_riscv64 | | cp312-pyodide_wasm32 |
|
||||||
| Python 3.12 | cp312-macosx_x86_64<br/>cp312-macosx_universal2<br/>cp312-macosx_arm64 | cp312-win_amd64<br/>cp312-win32<br/>cp312-win_arm64 | cp312-manylinux_x86_64<br/>cp312-manylinux_i686<br/>cp312-musllinux_x86_64<br/>cp312-musllinux_i686 | cp312-manylinux_aarch64<br/>cp312-manylinux_ppc64le<br/>cp312-manylinux_s390x<br/>cp312-manylinux_armv7l<br/>cp312-manylinux_riscv64<br/>cp312-musllinux_aarch64<br/>cp312-musllinux_ppc64le<br/>cp312-musllinux_s390x<br/>cp312-musllinux_armv7l<br/>cp312-musllinux_riscv64 | |
|
| Python 3.13 | cp313-macosx_x86_64<br/>cp313-macosx_universal2<br/>cp313-macosx_arm64 | cp313-win_amd64<br/>cp313-win32<br/>cp313-win_arm64 | cp313-manylinux_x86_64<br/>cp313-manylinux_i686<br/>cp313-musllinux_x86_64<br/>cp313-musllinux_i686 | cp313-manylinux_aarch64<br/>cp313-manylinux_ppc64le<br/>cp313-manylinux_s390x<br/>cp313-manylinux_armv7l<br/>cp313-manylinux_riscv64<br/>cp313-musllinux_aarch64<br/>cp313-musllinux_ppc64le<br/>cp313-musllinux_s390x<br/>cp313-musllinux_armv7l<br/>cp313-musllinux_riscv64 | cp313-ios_arm64_iphoneos<br/>cp313-ios_arm64_iphonesimulator<br/>cp313-ios_x86_64_iphonesimulator | |
|
||||||
| Python 3.13 | cp313-macosx_x86_64<br/>cp313-macosx_universal2<br/>cp313-macosx_arm64 | cp313-win_amd64<br/>cp313-win32<br/>cp313-win_arm64 | cp313-manylinux_x86_64<br/>cp313-manylinux_i686<br/>cp313-musllinux_x86_64<br/>cp313-musllinux_i686 | cp313-manylinux_aarch64<br/>cp313-manylinux_ppc64le<br/>cp313-manylinux_s390x<br/>cp313-manylinux_armv7l<br/>cp313-manylinux_riscv64<br/>cp313-musllinux_aarch64<br/>cp313-musllinux_ppc64le<br/>cp313-musllinux_s390x<br/>cp313-musllinux_armv7l<br/>cp313-musllinux_riscv64 | cp313-ios_arm64_iphoneos<br/>cp313-ios_arm64_iphonesimulator<br/>cp313-ios_x86_64_iphonesimulator |
|
| Python 3.14 | cp314-macosx_x86_64<br/>cp314-macosx_universal2<br/>cp314-macosx_arm64 | cp314-win_amd64<br/>cp314-win32<br/>cp314-win_arm64 | cp314-manylinux_x86_64<br/>cp314-manylinux_i686<br/>cp314-musllinux_x86_64<br/>cp314-musllinux_i686 | cp314-manylinux_aarch64<br/>cp314-manylinux_ppc64le<br/>cp314-manylinux_s390x<br/>cp314-manylinux_armv7l<br/>cp314-manylinux_riscv64<br/>cp314-musllinux_aarch64<br/>cp314-musllinux_ppc64le<br/>cp314-musllinux_s390x<br/>cp314-musllinux_armv7l<br/>cp314-musllinux_riscv64 | | |
|
||||||
| Python 3.14 | cp314-macosx_x86_64<br/>cp314-macosx_universal2<br/>cp314-macosx_arm64 | cp314-win_amd64<br/>cp314-win32<br/>cp314-win_arm64 | cp314-manylinux_x86_64<br/>cp314-manylinux_i686<br/>cp314-musllinux_x86_64<br/>cp314-musllinux_i686 | cp314-manylinux_aarch64<br/>cp314-manylinux_ppc64le<br/>cp314-manylinux_s390x<br/>cp314-manylinux_armv7l<br/>cp314-manylinux_riscv64<br/>cp314-musllinux_aarch64<br/>cp314-musllinux_ppc64le<br/>cp314-musllinux_s390x<br/>cp314-musllinux_armv7l<br/>cp314-musllinux_riscv64 | |
|
| PyPy3.8 v7.3 | pp38-macosx_x86_64<br/>pp38-macosx_arm64 | pp38-win_amd64 | pp38-manylinux_x86_64<br/>pp38-manylinux_i686 | pp38-manylinux_aarch64 | | |
|
||||||
| PyPy3.8 v7.3 | pp38-macosx_x86_64<br/>pp38-macosx_arm64 | pp38-win_amd64 | pp38-manylinux_x86_64<br/>pp38-manylinux_i686 | pp38-manylinux_aarch64 | |
|
| PyPy3.9 v7.3 | pp39-macosx_x86_64<br/>pp39-macosx_arm64 | pp39-win_amd64 | pp39-manylinux_x86_64<br/>pp39-manylinux_i686 | pp39-manylinux_aarch64 | | |
|
||||||
| PyPy3.9 v7.3 | pp39-macosx_x86_64<br/>pp39-macosx_arm64 | pp39-win_amd64 | pp39-manylinux_x86_64<br/>pp39-manylinux_i686 | pp39-manylinux_aarch64 | |
|
| PyPy3.10 v7.3 | pp310-macosx_x86_64<br/>pp310-macosx_arm64 | pp310-win_amd64 | pp310-manylinux_x86_64<br/>pp310-manylinux_i686 | pp310-manylinux_aarch64 | | |
|
||||||
| PyPy3.10 v7.3 | pp310-macosx_x86_64<br/>pp310-macosx_arm64 | pp310-win_amd64 | pp310-manylinux_x86_64<br/>pp310-manylinux_i686 | pp310-manylinux_aarch64 | |
|
| PyPy3.11 v7.3 | pp311-macosx_x86_64<br/>pp311-macosx_arm64 | pp311-win_amd64 | pp311-manylinux_x86_64<br/>pp311-manylinux_i686 | pp311-manylinux_aarch64 | | |
|
||||||
| PyPy3.11 v7.3 | pp311-macosx_x86_64<br/>pp311-macosx_arm64 | pp311-win_amd64 | pp311-manylinux_x86_64<br/>pp311-manylinux_i686 | pp311-manylinux_aarch64 | |
|
|
||||||
|
|
||||||
The list of supported and currently selected build identifiers can also be retrieved by passing the `--print-build-identifiers` flag to cibuildwheel.
|
The list of supported and currently selected build identifiers can also be retrieved by passing the `--print-build-identifiers` flag to cibuildwheel.
|
||||||
The format is `python_tag-platform_tag`, with tags similar to those in [PEP 425](https://www.python.org/dev/peps/pep-0425/#details).
|
The format is `python_tag-platform_tag`, with tags similar to those in [PEP 425](https://www.python.org/dev/peps/pep-0425/#details).
|
||||||
@@ -70,9 +71,6 @@ The format is `python_tag-platform_tag`, with tags similar to those in [PEP 425]
|
|||||||
Windows arm64 platform support is experimental.
|
Windows arm64 platform support is experimental.
|
||||||
Linux riscv64 platform support is experimental and requires an explicit opt-in through [CIBW_ENABLE](#enable).
|
Linux riscv64 platform support is experimental and requires an explicit opt-in through [CIBW_ENABLE](#enable).
|
||||||
|
|
||||||
For an experimental WebAssembly build with `--platform pyodide`,
|
|
||||||
`cp312-pyodide_wasm32` is the only platform identifier.
|
|
||||||
|
|
||||||
See the [cibuildwheel 2 documentation](https://cibuildwheel.pypa.io/en/2.x/) for past end-of-life versions of Python.
|
See the [cibuildwheel 2 documentation](https://cibuildwheel.pypa.io/en/2.x/) for past end-of-life versions of Python.
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
@@ -1223,6 +1221,45 @@ Platform-specific environment variables are also available:<br/>
|
|||||||
dependency-versions = { packages = ["pyodide-build==0.29.1"] }
|
dependency-versions = { packages = ["pyodide-build==0.29.1"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `CIBW_PYODIDE_VERSION` {: #pyodide-version}
|
||||||
|
|
||||||
|
> Specify the Pyodide version to use for `pyodide` platform builds
|
||||||
|
|
||||||
|
This option allows you to specify a specific version of Pyodide to be used when building wheels for the `pyodide` platform. If unset, cibuildwheel will use a pinned Pyodide version.
|
||||||
|
|
||||||
|
This option is particularly useful for:
|
||||||
|
|
||||||
|
- Testing against specific Pyodide alpha or older releases.
|
||||||
|
- Ensuring reproducibility by targeting a known Pyodide version.
|
||||||
|
|
||||||
|
The available Pyodide versions are determined by the version of `pyodide-build` being used. You can list the compatible versions using the command `pyodide xbuildenv search --all` as described in the [Pyodide platform documentation](platforms.md#pyodide-choosing-a-version).
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
You can set the version of `pyodide-build` using the [`CIBW_DEPENDENCY_VERSIONS`](#dependency-versions) option.
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
|
||||||
|
!!! tab examples "Environment variables"
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Build Pyodide wheels using Pyodide version 0.27.6
|
||||||
|
CIBW_PYODIDE_VERSION: 0.27.6
|
||||||
|
|
||||||
|
# Build Pyodide wheels using a specific alpha release
|
||||||
|
CIBW_PYODIDE_VERSION: 0.28.0a2
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tab examples "pyproject.toml"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tool.cibuildwheel.pyodide]
|
||||||
|
# Build Pyodide wheels using Pyodide version 0.27.6
|
||||||
|
pyodide-version = "0.27.6"
|
||||||
|
|
||||||
|
[tool.cibuildwheel.pyodide]
|
||||||
|
# Build Pyodide wheels using a specific alpha release
|
||||||
|
pyodide-version = "0.28.0a2"
|
||||||
|
```
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
|
|||||||
+14
-6
@@ -3,7 +3,7 @@ title: Platforms
|
|||||||
---
|
---
|
||||||
# Platforms
|
# Platforms
|
||||||
|
|
||||||
## Linux
|
## Linux {: #linux}
|
||||||
|
|
||||||
### System requirements
|
### System requirements
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ Linux wheels are built in [`manylinux`/`musllinux` containers](https://github.co
|
|||||||
|
|
||||||
- Alternative Docker images can be specified with the `CIBW_MANYLINUX_*_IMAGE`/`CIBW_MUSLLINUX_*_IMAGE` options to allow for a custom, preconfigured build environment for the Linux builds. See [options](options.md#linux-image) for more details.
|
- Alternative Docker images can be specified with the `CIBW_MANYLINUX_*_IMAGE`/`CIBW_MUSLLINUX_*_IMAGE` options to allow for a custom, preconfigured build environment for the Linux builds. See [options](options.md#linux-image) for more details.
|
||||||
|
|
||||||
## macOS
|
## macOS {: #macos}
|
||||||
|
|
||||||
### System requirements
|
### System requirements
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ Regarding testing,
|
|||||||
As a workaround, the tag can be fixed before running delocate to repair the wheel. The [`wheel tags`](https://wheel.readthedocs.io/en/stable/reference/wheel_tags.html) command is ideal for this. See [this workflow](https://gist.github.com/anderssonjohan/49f07e33fc5cb2420515a8ac76dc0c95#file-build-pendulum-wheels-yml-L39-L53) for an example usage of `wheel tags`.
|
As a workaround, the tag can be fixed before running delocate to repair the wheel. The [`wheel tags`](https://wheel.readthedocs.io/en/stable/reference/wheel_tags.html) command is ideal for this. See [this workflow](https://gist.github.com/anderssonjohan/49f07e33fc5cb2420515a8ac76dc0c95#file-build-pendulum-wheels-yml-L39-L53) for an example usage of `wheel tags`.
|
||||||
|
|
||||||
|
|
||||||
## Windows
|
## Windows {: #windows}
|
||||||
|
|
||||||
### System requirements
|
### System requirements
|
||||||
|
|
||||||
@@ -160,15 +160,23 @@ By default, `ARM64` is not enabled when running on non-ARM64 runners. Use [`CIBW
|
|||||||
|
|
||||||
Pyodide is offered as an experimental feature in cibuildwheel.
|
Pyodide is offered as an experimental feature in cibuildwheel.
|
||||||
|
|
||||||
### Prerequisites
|
### System requirements
|
||||||
|
|
||||||
You need to have a matching host version of Python (unlike all other cibuildwheel platforms). Linux host highly recommended; macOS hosts may work (e.g. invoking `pytest` directly in [`CIBW_TEST_COMMAND`](options.md#test-command) is [currently failing](https://github.com/pyodide/pyodide/issues/4802)) and Windows hosts will not work.
|
Pyodide builds require a Linux or macOS machine.
|
||||||
|
|
||||||
### Specifying a pyodide build
|
### Specifying a pyodide build
|
||||||
|
|
||||||
You must target pyodide with `--platform pyodide` (or use `--only` on the identifier).
|
You must target pyodide with `--platform pyodide` (or use `--only` on the identifier).
|
||||||
|
|
||||||
## iOS
|
### Choosing a Pyodide version {: #pyodide-choosing-a-version}
|
||||||
|
|
||||||
|
It is also possible to target a specific Pyodide version by setting the `CIBW_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.
|
||||||
|
|
||||||
|
### Running tests
|
||||||
|
|
||||||
|
Currently, it's recommended to run tests using a `python -m` entrypoint, rather than a command line entrypoint, or a shell script. This is because custom entrypoints have some issues in the Pyodide virtual environment. For example, `pytest` may not work as a command line entrypoint, but will work as a `python -m pytest` entrypoint.
|
||||||
|
|
||||||
|
## iOS {: #ios}
|
||||||
|
|
||||||
### System requirements
|
### System requirements
|
||||||
|
|
||||||
|
|||||||
+21
-9
@@ -68,17 +68,20 @@ def update_constraints(session: nox.Session) -> None:
|
|||||||
Update the dependencies inplace.
|
Update the dependencies inplace.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
session.install("-e.", "click")
|
||||||
|
|
||||||
resources = Path("cibuildwheel/resources")
|
resources = Path("cibuildwheel/resources")
|
||||||
|
|
||||||
if session.venv_backend != "uv":
|
if session.venv_backend != "uv":
|
||||||
session.install("uv>=0.1.23")
|
session.install("uv>=0.1.23")
|
||||||
|
|
||||||
|
# CUSTOM_COMPILE_COMMAND is a pip-compile option that tells users how to
|
||||||
|
# regenerate the constraints files
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["UV_CUSTOM_COMPILE_COMMAND"] = f"nox -s {session.name}"
|
||||||
|
|
||||||
for minor_version in range(8, 15):
|
for minor_version in range(8, 15):
|
||||||
python_version = f"3.{minor_version}"
|
python_version = f"3.{minor_version}"
|
||||||
env = os.environ.copy()
|
|
||||||
# CUSTOM_COMPILE_COMMAND is a pip-compile option that tells users how to
|
|
||||||
# regenerate the constraints files
|
|
||||||
env["UV_CUSTOM_COMPILE_COMMAND"] = f"nox -s {session.name}"
|
|
||||||
output_file = resources / f"constraints-python{python_version.replace('.', '')}.txt"
|
output_file = resources / f"constraints-python{python_version.replace('.', '')}.txt"
|
||||||
session.run(
|
session.run(
|
||||||
"uv",
|
"uv",
|
||||||
@@ -100,12 +103,19 @@ def update_constraints(session: nox.Session) -> None:
|
|||||||
pyodides = build_platforms["pyodide"]["python_configurations"]
|
pyodides = build_platforms["pyodide"]["python_configurations"]
|
||||||
for pyodide in pyodides:
|
for pyodide in pyodides:
|
||||||
python_version = ".".join(pyodide["version"].split(".")[:2])
|
python_version = ".".join(pyodide["version"].split(".")[:2])
|
||||||
pyodide_build_version = pyodide["pyodide_build_version"]
|
pyodide_version = pyodide["default_pyodide_version"]
|
||||||
output_file = resources / f"constraints-pyodide{python_version.replace('.', '')}.txt"
|
|
||||||
tmp_file = Path(session.create_tmp()) / "constraints-pyodide.in"
|
tmp_file = Path(session.create_tmp()) / "constraints-pyodide.in"
|
||||||
tmp_file.write_text(
|
|
||||||
f"pip\nbuild[virtualenv]\npyodide-build=={pyodide_build_version}\nclick<8.2"
|
session.run(
|
||||||
|
"python",
|
||||||
|
"bin/generate_pyodide_constraints.py",
|
||||||
|
"--output-file",
|
||||||
|
tmp_file,
|
||||||
|
pyodide_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
output_file = resources / f"constraints-pyodide{python_version.replace('.', '')}.txt"
|
||||||
session.run(
|
session.run(
|
||||||
"uv",
|
"uv",
|
||||||
"pip",
|
"pip",
|
||||||
@@ -121,7 +131,8 @@ def update_constraints(session: nox.Session) -> None:
|
|||||||
@nox.session(default=False, tags=["update"])
|
@nox.session(default=False, tags=["update"])
|
||||||
def update_pins(session: nox.Session) -> None:
|
def update_pins(session: nox.Session) -> None:
|
||||||
"""
|
"""
|
||||||
Update the python, docker and virtualenv pins version inplace.
|
Update the python, docker, virtualenv, node, and python-build-standalone
|
||||||
|
version pins inplace.
|
||||||
"""
|
"""
|
||||||
pyproject = nox.project.load_toml()
|
pyproject = nox.project.load_toml()
|
||||||
session.install("-e.", *nox.project.dependency_groups(pyproject, "bin"))
|
session.install("-e.", *nox.project.dependency_groups(pyproject, "bin"))
|
||||||
@@ -129,6 +140,7 @@ def update_pins(session: nox.Session) -> None:
|
|||||||
session.run("python", "bin/update_docker.py")
|
session.run("python", "bin/update_docker.py")
|
||||||
session.run("python", "bin/update_virtualenv.py", "--force")
|
session.run("python", "bin/update_virtualenv.py", "--force")
|
||||||
session.run("python", "bin/update_nodejs.py", "--force")
|
session.run("python", "bin/update_nodejs.py", "--force")
|
||||||
|
session.run("python", "bin/update_python_build_standalone.py")
|
||||||
|
|
||||||
|
|
||||||
@nox.session(default=False, reuse_venv=True, tags=["update"])
|
@nox.session(default=False, reuse_venv=True, tags=["update"])
|
||||||
|
|||||||
@@ -48,8 +48,13 @@ def test_abi3(tmp_path):
|
|||||||
|
|
||||||
# check that the expected wheels are produced
|
# check that the expected wheels are produced
|
||||||
if utils.get_platform() == "pyodide":
|
if utils.get_platform() == "pyodide":
|
||||||
# there's only 1 possible configuration for pyodide, cp312
|
# there's only 1 possible configuration for pyodide, cp312. It builds
|
||||||
expected_wheels = utils.expected_wheels("spam", "0.1.0", python_abi_tags=["cp310-abi3"])
|
# a wheel that is tagged abi3, compatible back to 3.10
|
||||||
|
expected_wheels = utils.expected_wheels(
|
||||||
|
"spam",
|
||||||
|
"0.1.0",
|
||||||
|
python_abi_tags=["cp310-abi3"],
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
expected_wheels = utils.expected_wheels(
|
expected_wheels = utils.expected_wheels(
|
||||||
"spam",
|
"spam",
|
||||||
@@ -189,15 +194,17 @@ def test_abi_none(tmp_path, capfd):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# check that the expected wheels are produced
|
|
||||||
expected_wheels = utils.expected_wheels("ctypesexample", "1.0.0", python_abi_tags=["py3-none"])
|
expected_wheels = utils.expected_wheels("ctypesexample", "1.0.0", python_abi_tags=["py3-none"])
|
||||||
|
# check that the expected wheels are produced
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
# check that each wheel was built once, and reused
|
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
assert "Building wheel..." in captured.out
|
|
||||||
if utils.get_platform() == "pyodide":
|
if utils.get_platform() == "pyodide":
|
||||||
# there's only 1 possible configuration for pyodide, we won't see the message expected on following builds
|
# pyodide builds a different platform tag for each python version, so
|
||||||
|
# wheels are not reused
|
||||||
assert "Found previously built wheel" not in captured.out
|
assert "Found previously built wheel" not in captured.out
|
||||||
else:
|
else:
|
||||||
|
# check that each wheel was built once, and reused
|
||||||
|
assert "Building wheel..." in captured.out
|
||||||
assert "Found previously built wheel" in captured.out
|
assert "Found previously built wheel" in captured.out
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ from pathlib import Path
|
|||||||
wheel = Path(sys.argv[1])
|
wheel = Path(sys.argv[1])
|
||||||
dest_dir = Path(sys.argv[2])
|
dest_dir = Path(sys.argv[2])
|
||||||
platform = wheel.stem.split("-")[-1]
|
platform = wheel.stem.split("-")[-1]
|
||||||
|
if platform.startswith("pyodide"):
|
||||||
|
# for the sake of this test, munge the pyodide platforms into one, it's
|
||||||
|
# not valid, but it does activate the uniqueness check
|
||||||
|
platform = "pyodide"
|
||||||
|
|
||||||
name = f"spam-0.1.0-py2-none-{platform}.whl"
|
name = f"spam-0.1.0-py2-none-{platform}.whl"
|
||||||
dest = dest_dir / name
|
dest = dest_dir / name
|
||||||
dest_dir.mkdir(parents=True, exist_ok=True)
|
dest_dir.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -48,11 +53,6 @@ def test(tmp_path, capfd):
|
|||||||
assert "Build failed because a wheel named" in captured.err
|
assert "Build failed because a wheel named" in captured.err
|
||||||
assert exc_info.value.returncode == 6
|
assert exc_info.value.returncode == 6
|
||||||
else:
|
else:
|
||||||
# We only produced one wheel (currently Pyodide)
|
# We only produced one wheel (perhaps Pyodide)
|
||||||
# check that it has the right name
|
# check that it has the right name
|
||||||
#
|
|
||||||
# As far as I can tell, this is the only full test coverage for
|
|
||||||
# CIBW_REPAIR_WHEEL_COMMAND so this is useful even in the case when no
|
|
||||||
# error is raised
|
|
||||||
assert "spam-0.1.0-py2-none-pyodide" in captured.out
|
|
||||||
assert result[0].startswith("spam-0.1.0-py2-none-")
|
assert result[0].startswith("spam-0.1.0-py2-none-")
|
||||||
|
|||||||
@@ -70,7 +70,10 @@ def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv):
|
|||||||
version_no_dot = python_version.replace(".", "")
|
version_no_dot = python_version.replace(".", "")
|
||||||
build_environment = {}
|
build_environment = {}
|
||||||
build_pattern = f"[cp]p{version_no_dot}-*"
|
build_pattern = f"[cp]p{version_no_dot}-*"
|
||||||
constraint_filename = f"constraints-python{version_no_dot}.txt"
|
if utils.get_platform() == "pyodide":
|
||||||
|
constraint_filename = f"constraints-pyodide{version_no_dot}.txt"
|
||||||
|
else:
|
||||||
|
constraint_filename = f"constraints-python{version_no_dot}.txt"
|
||||||
constraint_file = resources.PATH / constraint_filename
|
constraint_file = resources.PATH / constraint_filename
|
||||||
constraint_versions = get_versions_from_constraint_file(constraint_file)
|
constraint_versions = get_versions_from_constraint_file(constraint_file)
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,12 @@ def test_overridden_path(tmp_path, capfd):
|
|||||||
"build_frontend",
|
"build_frontend",
|
||||||
[
|
[
|
||||||
pytest.param("pip", marks=utils.skip_if_pyodide("No pip for pyodide")),
|
pytest.param("pip", marks=utils.skip_if_pyodide("No pip for pyodide")),
|
||||||
"build",
|
pytest.param(
|
||||||
|
"build",
|
||||||
|
marks=utils.skip_if_pyodide(
|
||||||
|
"pyodide doesn't support multiple values for PIP_CONSTRAINT"
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_overridden_pip_constraint(tmp_path, build_frontend):
|
def test_overridden_pip_constraint(tmp_path, build_frontend):
|
||||||
|
|||||||
+10
-3
@@ -60,12 +60,19 @@ def test_pep518(tmp_path, build_frontend_env):
|
|||||||
assert not (project_dir / "42").exists()
|
assert not (project_dir / "42").exists()
|
||||||
assert not (project_dir / "4.1.2").exists()
|
assert not (project_dir / "4.1.2").exists()
|
||||||
|
|
||||||
# pypa/build creates a "build" folder & a "*.egg-info" folder for the wheel being built,
|
# pypa/build creates a "build" folder & a "*.egg-info" folder for the
|
||||||
# this should be harmless so remove them
|
# wheel being built, this should be harmless so remove them. pyodide-build
|
||||||
|
# creates a ".pyodide_build" folder, but this is gitignored with a
|
||||||
|
# .gitignore file inside.
|
||||||
contents = [
|
contents = [
|
||||||
item
|
item
|
||||||
for item in project_dir.iterdir()
|
for item in project_dir.iterdir()
|
||||||
if item.name != "build" and not item.name.endswith(".egg-info")
|
if item.name != "build"
|
||||||
|
and not item.name.endswith(".egg-info")
|
||||||
|
and item.name != ".pyodide_build"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
print("Project contents after build:")
|
||||||
|
print("\n".join(f" {f}" for f in contents))
|
||||||
|
|
||||||
assert len(contents) == len(basic_project.files)
|
assert len(contents) == len(basic_project.files)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import shutil
|
import contextlib
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from cibuildwheel.ci import CIProvider, detect_ci_provider
|
|
||||||
from cibuildwheel.util.file import CIBW_CACHE_PATH
|
from cibuildwheel.util.file import CIBW_CACHE_PATH
|
||||||
|
|
||||||
from . import test_projects, utils
|
from . import test_projects, utils
|
||||||
@@ -43,13 +43,7 @@ if __name__ == "__main__":
|
|||||||
@pytest.mark.parametrize("use_pyproject_toml", [True, False])
|
@pytest.mark.parametrize("use_pyproject_toml", [True, False])
|
||||||
def test_pyodide_build(tmp_path, use_pyproject_toml):
|
def test_pyodide_build(tmp_path, use_pyproject_toml):
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
pytest.skip("emsdk doesn't work correctly on Windows")
|
pytest.skip("pyodide-build doesn't work correctly on Windows")
|
||||||
|
|
||||||
if not shutil.which("python3.12"):
|
|
||||||
pytest.skip("Python 3.12 not installed")
|
|
||||||
|
|
||||||
if detect_ci_provider() == CIProvider.travis_ci:
|
|
||||||
pytest.skip("Python 3.12 is just a non-working pyenv shim")
|
|
||||||
|
|
||||||
if use_pyproject_toml:
|
if use_pyproject_toml:
|
||||||
basic_project.files["pyproject.toml"] = textwrap.dedent(
|
basic_project.files["pyproject.toml"] = textwrap.dedent(
|
||||||
@@ -84,3 +78,64 @@ def test_pyodide_build(tmp_path, use_pyproject_toml):
|
|||||||
print("expected_wheels", expected_wheels)
|
print("expected_wheels", expected_wheels)
|
||||||
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pyodide_version_incompatible(tmp_path, capfd):
|
||||||
|
if sys.platform == "win32":
|
||||||
|
pytest.skip("pyodide-build doesn't work correctly on Windows")
|
||||||
|
|
||||||
|
basic_project.generate(tmp_path)
|
||||||
|
|
||||||
|
with pytest.raises(subprocess.CalledProcessError):
|
||||||
|
utils.cibuildwheel_run(
|
||||||
|
tmp_path,
|
||||||
|
add_args=["--platform", "pyodide"],
|
||||||
|
add_env={
|
||||||
|
"CIBW_DEPENDENCY_VERSIONS": "packages: pyodide-build==0.29.3",
|
||||||
|
"CIBW_PYODIDE_VERSION": "0.26.0a6",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
|
||||||
|
assert "is not compatible with the pyodide-build version" in err
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expect_failure", [True, False])
|
||||||
|
def test_pyodide_build_and_test(tmp_path, expect_failure):
|
||||||
|
if sys.platform == "win32":
|
||||||
|
pytest.skip("pyodide-build doesn't work correctly on Windows")
|
||||||
|
|
||||||
|
if expect_failure:
|
||||||
|
basic_project.files["test/spam_test.py"] = textwrap.dedent(r"""
|
||||||
|
def test_filter():
|
||||||
|
assert 0 == 1
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
basic_project.files["test/spam_test.py"] = textwrap.dedent(r"""
|
||||||
|
import spam
|
||||||
|
def test_filter():
|
||||||
|
assert spam.filter("spam") == 0
|
||||||
|
""")
|
||||||
|
basic_project.generate(tmp_path)
|
||||||
|
|
||||||
|
context = (
|
||||||
|
pytest.raises(subprocess.CalledProcessError) if expect_failure else contextlib.nullcontext()
|
||||||
|
)
|
||||||
|
with context:
|
||||||
|
# build the wheels
|
||||||
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
|
tmp_path,
|
||||||
|
add_args=["--platform", "pyodide"],
|
||||||
|
add_env={
|
||||||
|
"CIBW_TEST_REQUIRES": "pytest",
|
||||||
|
"CIBW_TEST_COMMAND": "python -m pytest",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
# check that the expected wheels are produced
|
||||||
|
expected_wheels = [
|
||||||
|
"spam-0.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl",
|
||||||
|
]
|
||||||
|
print("actual_wheels", actual_wheels)
|
||||||
|
print("expected_wheels", expected_wheels)
|
||||||
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
@@ -224,10 +224,10 @@ def test_test_sources(tmp_path):
|
|||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_TEST_REQUIRES": "pytest",
|
"CIBW_TEST_REQUIRES": "pytest",
|
||||||
"CIBW_TEST_COMMAND": "pytest",
|
|
||||||
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
|
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
|
||||||
# until https://github.com/oracle/graalpython/issues/490 is fixed
|
# until https://github.com/oracle/graalpython/issues/490 is fixed
|
||||||
"CIBW_TEST_COMMAND_WINDOWS": "where graalpy || pytest",
|
"CIBW_TEST_COMMAND_WINDOWS": "where graalpy || pytest",
|
||||||
|
"CIBW_TEST_COMMAND": utils.invoke_pytest(),
|
||||||
"CIBW_TEST_SOURCES": "test",
|
"CIBW_TEST_SOURCES": "test",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
+10
-2
@@ -382,7 +382,15 @@ def _expected_wheels(
|
|||||||
raise Exception(msg)
|
raise Exception(msg)
|
||||||
|
|
||||||
elif platform == "pyodide":
|
elif platform == "pyodide":
|
||||||
platform_tags = ["pyodide_2024_0_wasm32"]
|
platform_tags = {
|
||||||
|
"cp312-cp312": ["pyodide_2024_0_wasm32"],
|
||||||
|
"cp313-cp313": ["pyodide_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"]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
msg = f"Unsupported platform {platform!r}"
|
msg = f"Unsupported platform {platform!r}"
|
||||||
@@ -425,7 +433,7 @@ def skip_if_pyodide(reason: str) -> Any:
|
|||||||
|
|
||||||
def invoke_pytest() -> str:
|
def invoke_pytest() -> str:
|
||||||
# see https://github.com/pyodide/pyodide/issues/4802
|
# see https://github.com/pyodide/pyodide/issues/4802
|
||||||
if get_platform() == "pyodide" and sys.platform.startswith("darwin"):
|
if get_platform() == "pyodide":
|
||||||
return "python -m pytest"
|
return "python -m pytest"
|
||||||
return "pytest"
|
return "pytest"
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ manylinux-x86_64-image = "manylinux_2_28"
|
|||||||
|
|
||||||
environment-pass = ["EXAMPLE_ENV"]
|
environment-pass = ["EXAMPLE_ENV"]
|
||||||
|
|
||||||
|
pyodide-version = "0.27.6"
|
||||||
|
|
||||||
[tool.cibuildwheel.macos]
|
[tool.cibuildwheel.macos]
|
||||||
test-requires = "else"
|
test-requires = "else"
|
||||||
|
|
||||||
@@ -88,6 +90,9 @@ def test_options_1(tmp_path, monkeypatch):
|
|||||||
assert local.test_sources == ["test", "other dir"]
|
assert local.test_sources == ["test", "other dir"]
|
||||||
assert local.manylinux_images["x86_64"] == pinned_x86_64_container_image["manylinux_2_34"]
|
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.27.6"
|
||||||
|
|
||||||
|
|
||||||
def test_passthrough(tmp_path, monkeypatch):
|
def test_passthrough(tmp_path, monkeypatch):
|
||||||
with tmp_path.joinpath("pyproject.toml").open("w") as f:
|
with tmp_path.joinpath("pyproject.toml").open("w") as f:
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ from cibuildwheel.util.helpers import (
|
|||||||
format_safe,
|
format_safe,
|
||||||
parse_key_value_string,
|
parse_key_value_string,
|
||||||
prepare_command,
|
prepare_command,
|
||||||
|
unwrap,
|
||||||
|
unwrap_preserving_paragraphs,
|
||||||
)
|
)
|
||||||
from cibuildwheel.util.packaging import find_compatible_wheel
|
from cibuildwheel.util.packaging import find_compatible_wheel
|
||||||
|
|
||||||
@@ -363,3 +365,33 @@ def test_copy_test_sources_alternate_copy_into(sample_project):
|
|||||||
],
|
],
|
||||||
any_order=True,
|
any_order=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_unwrap():
|
||||||
|
assert (
|
||||||
|
unwrap("""
|
||||||
|
This is a
|
||||||
|
multiline
|
||||||
|
string
|
||||||
|
""")
|
||||||
|
== "This is a multiline string"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_unwrap_preserving_paragraphs():
|
||||||
|
assert (
|
||||||
|
unwrap("""
|
||||||
|
This is a
|
||||||
|
multiline
|
||||||
|
string
|
||||||
|
""")
|
||||||
|
== "This is a multiline string"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
unwrap_preserving_paragraphs("""
|
||||||
|
paragraph one
|
||||||
|
|
||||||
|
paragraph two
|
||||||
|
""")
|
||||||
|
== "paragraph one\n\nparagraph two"
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user