feat: support GraalPy (#1538)
* Properly close files used for testing * Add support for GraalPy * Help GraalPy discover build tools on Windows * Expect manylinux-interpreters ensure graalpy* warning in pip * Workaround GraalPy bugs on Windows * Workaround oracle/graalpython#491 also when uv is not available * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update azure-pipelines.yml * Update azure-pipelines.yml * refacotor: use pathlib.write_text Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * Include GraalPy in docker_warmup and remove workaround for installing it late --------- Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
This commit is contained in:
co-authored by
pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Henry Schreiner
parent
5f8d06ff55
commit
020a91baa8
@@ -80,7 +80,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CIBW_ARCHS_MACOS: x86_64 universal2 arm64
|
CIBW_ARCHS_MACOS: x86_64 universal2 arm64
|
||||||
CIBW_BUILD_FRONTEND: 'build[uv]'
|
CIBW_BUILD_FRONTEND: 'build[uv]'
|
||||||
CIBW_ENABLE: "cpython-prerelease cpython-freethreading pypy"
|
CIBW_ENABLE: "cpython-prerelease cpython-freethreading pypy graalpy"
|
||||||
|
|
||||||
- name: Run a sample build (GitHub Action, only)
|
- name: Run a sample build (GitHub Action, only)
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|||||||
@@ -36,14 +36,15 @@ While cibuildwheel itself requires a recent Python version to run (we support th
|
|||||||
| PyPy 3.9 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A |
|
| PyPy 3.9 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A |
|
||||||
| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A |
|
| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A |
|
||||||
| PyPy 3.11 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A |
|
| PyPy 3.11 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A | N/A | N/A |
|
||||||
|
| GraalPy 24.2 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | N/A | ✅¹ | N/A | N/A | N/A | N/A | N/A |
|
||||||
|
|
||||||
<sup>¹ PyPy is only supported for manylinux wheels.</sup><br>
|
<sup>¹ PyPy & GraalPy are only supported for manylinux wheels.</sup><br>
|
||||||
<sup>² Windows arm64 support is experimental.</sup><br>
|
<sup>² Windows arm64 support is experimental.</sup><br>
|
||||||
<sup>³ Free-threaded mode requires opt-in using [`CIBW_ENABLE`](https://cibuildwheel.pypa.io/en/stable/options/#enable).</sup><br>
|
<sup>³ Free-threaded mode requires opt-in using [`CIBW_ENABLE`](https://cibuildwheel.pypa.io/en/stable/options/#enable).</sup><br>
|
||||||
<sup>⁴ Experimental, not yet supported on PyPI, but can be used directly in web deployment. Use `--platform pyodide` to build.</sup><br>
|
<sup>⁴ Experimental, not yet supported on PyPI, but can be used directly in web deployment. Use `--platform pyodide` to build.</sup><br>
|
||||||
<sup>⁵ manylinux armv7l support is experimental. As there are no RHEL based image for this architecture, it's using an Ubuntu based image instead.</sup><br>
|
<sup>⁵ manylinux armv7l support is experimental. As there are no RHEL based image for this architecture, it's using an Ubuntu based image instead.</sup><br>
|
||||||
|
|
||||||
- Builds manylinux, musllinux, macOS 10.9+ (10.13+ for Python 3.12+), and Windows wheels for CPython and PyPy
|
- Builds manylinux, musllinux, macOS 10.9+ (10.13+ for Python 3.12+), and Windows wheels for CPython, PyPy, and GraalPy
|
||||||
- Works on GitHub Actions, Azure Pipelines, Travis CI, AppVeyor, CircleCI, GitLab CI, and Cirrus CI
|
- Works on GitHub Actions, Azure Pipelines, Travis CI, AppVeyor, CircleCI, GitLab CI, and Cirrus CI
|
||||||
- Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate)
|
- Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate)
|
||||||
- Runs your library's tests against the wheel-installed version of your library
|
- Runs your library's tests against the wheel-installed version of your library
|
||||||
|
|||||||
+2
-1
@@ -6,7 +6,7 @@ pr:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
- job: linux_311
|
- job: linux_311
|
||||||
timeoutInMinutes: 120
|
timeoutInMinutes: 180
|
||||||
pool: {vmImage: 'Ubuntu-22.04'}
|
pool: {vmImage: 'Ubuntu-22.04'}
|
||||||
steps:
|
steps:
|
||||||
- task: UsePythonVersion@0
|
- task: UsePythonVersion@0
|
||||||
@@ -20,6 +20,7 @@ jobs:
|
|||||||
|
|
||||||
- job: macos_311
|
- job: macos_311
|
||||||
pool: {vmImage: 'macOS-13'}
|
pool: {vmImage: 'macOS-13'}
|
||||||
|
timeoutInMinutes: 120
|
||||||
steps:
|
steps:
|
||||||
- task: UsePythonVersion@0
|
- task: UsePythonVersion@0
|
||||||
inputs:
|
inputs:
|
||||||
|
|||||||
+80
-1
@@ -5,6 +5,7 @@ import copy
|
|||||||
import difflib
|
import difflib
|
||||||
import logging
|
import logging
|
||||||
import operator
|
import operator
|
||||||
|
import re
|
||||||
import tomllib
|
import tomllib
|
||||||
from collections.abc import Mapping, MutableMapping
|
from collections.abc import Mapping, MutableMapping
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -44,13 +45,19 @@ class ConfigWinPP(TypedDict):
|
|||||||
url: str
|
url: str
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigWinGP(TypedDict):
|
||||||
|
identifier: str
|
||||||
|
version: str
|
||||||
|
url: str
|
||||||
|
|
||||||
|
|
||||||
class ConfigApple(TypedDict):
|
class ConfigApple(TypedDict):
|
||||||
identifier: str
|
identifier: str
|
||||||
version: str
|
version: str
|
||||||
url: str
|
url: str
|
||||||
|
|
||||||
|
|
||||||
AnyConfig = ConfigWinCP | ConfigWinPP | ConfigApple
|
AnyConfig = ConfigWinCP | ConfigWinPP | ConfigWinGP | ConfigApple
|
||||||
|
|
||||||
|
|
||||||
# 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
|
||||||
@@ -106,6 +113,72 @@ class WindowsVersions:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class GraalPyVersions:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
response = requests.get("https://api.github.com/repos/oracle/graalpython/releases")
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
releases = response.json()
|
||||||
|
gp_version_re = re.compile(r"-(\d+\.\d+\.\d+)$")
|
||||||
|
cp_version_re = re.compile(r"Python (\d+\.\d+(?:\.\d+)?)")
|
||||||
|
for release in releases:
|
||||||
|
m = gp_version_re.search(release["tag_name"])
|
||||||
|
if m:
|
||||||
|
release["graalpy_version"] = Version(m.group(1))
|
||||||
|
m = cp_version_re.search(release["body"])
|
||||||
|
if m:
|
||||||
|
release["python_version"] = Version(m.group(1))
|
||||||
|
|
||||||
|
self.releases = [r for r in releases if "graalpy_version" in r and "python_version" in r]
|
||||||
|
|
||||||
|
def update_version(self, identifier: str, spec: Specifier) -> AnyConfig:
|
||||||
|
if "x86_64" in identifier or "amd64" in identifier:
|
||||||
|
arch = "x86_64"
|
||||||
|
elif "arm64" in identifier or "aarch64" in identifier:
|
||||||
|
arch = "aarch64"
|
||||||
|
else:
|
||||||
|
msg = f"{identifier} not supported yet on GraalPy"
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
releases = [r for r in self.releases if spec.contains(r["python_version"])]
|
||||||
|
releases = sorted(releases, key=lambda r: r["graalpy_version"])
|
||||||
|
|
||||||
|
if not releases:
|
||||||
|
msg = f"GraalPy {arch} not found for {spec}!"
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
release = releases[-1]
|
||||||
|
version = release["python_version"]
|
||||||
|
gpversion = release["graalpy_version"]
|
||||||
|
|
||||||
|
if "macosx" in identifier:
|
||||||
|
arch = "x86_64" if "x86_64" in identifier else "arm64"
|
||||||
|
config = ConfigApple
|
||||||
|
platform = "macos"
|
||||||
|
elif "win" in identifier:
|
||||||
|
arch = "aarch64" if "arm64" in identifier else "x86_64"
|
||||||
|
config = ConfigWinGP
|
||||||
|
platform = "windows"
|
||||||
|
else:
|
||||||
|
msg = "GraalPy provides downloads for macOS and Windows and is included for manylinux"
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
arch = "amd64" if arch == "x86_64" else "aarch64"
|
||||||
|
ext = "zip" if "win" in identifier else "tar.gz"
|
||||||
|
(url,) = (
|
||||||
|
rf["browser_download_url"]
|
||||||
|
for rf in release["assets"]
|
||||||
|
if rf["name"].endswith(f"{platform}-{arch}.{ext}")
|
||||||
|
and rf["name"].startswith(f"graalpy-{gpversion.major}")
|
||||||
|
)
|
||||||
|
|
||||||
|
return config(
|
||||||
|
identifier=identifier,
|
||||||
|
version=f"{version.major}.{version.minor}",
|
||||||
|
url=url,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PyPyVersions:
|
class PyPyVersions:
|
||||||
def __init__(self, arch_str: ArchStr):
|
def __init__(self, arch_str: ArchStr):
|
||||||
response = requests.get("https://downloads.python.org/pypy/versions.json")
|
response = requests.get("https://downloads.python.org/pypy/versions.json")
|
||||||
@@ -294,6 +367,8 @@ class AllVersions:
|
|||||||
|
|
||||||
self.ios_cpython = CPythonIOSVersions()
|
self.ios_cpython = CPythonIOSVersions()
|
||||||
|
|
||||||
|
self.graalpy = GraalPyVersions()
|
||||||
|
|
||||||
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"])
|
||||||
@@ -311,6 +386,8 @@ class AllVersions:
|
|||||||
config_update = self.macos_pypy.update_version_macos(spec)
|
config_update = self.macos_pypy.update_version_macos(spec)
|
||||||
elif "macosx_arm64" in identifier:
|
elif "macosx_arm64" in identifier:
|
||||||
config_update = self.macos_pypy_arm64.update_version_macos(spec)
|
config_update = self.macos_pypy_arm64.update_version_macos(spec)
|
||||||
|
elif identifier.startswith("gp"):
|
||||||
|
config_update = self.graalpy.update_version(identifier, spec)
|
||||||
elif "t-win32" in identifier and identifier.startswith("cp"):
|
elif "t-win32" in identifier and identifier.startswith("cp"):
|
||||||
config_update = self.windows_t_32.update_version_windows(spec)
|
config_update = self.windows_t_32.update_version_windows(spec)
|
||||||
elif "win32" in identifier and identifier.startswith("cp"):
|
elif "win32" in identifier and identifier.startswith("cp"):
|
||||||
@@ -322,6 +399,8 @@ class AllVersions:
|
|||||||
config_update = self.windows_64.update_version_windows(spec)
|
config_update = self.windows_64.update_version_windows(spec)
|
||||||
elif identifier.startswith("pp"):
|
elif identifier.startswith("pp"):
|
||||||
config_update = self.windows_pypy_64.update_version_windows(spec)
|
config_update = self.windows_pypy_64.update_version_windows(spec)
|
||||||
|
elif identifier.startswith("gp"):
|
||||||
|
config_update = self.graalpy.update_version(identifier, spec)
|
||||||
elif "t-win_arm64" in identifier and identifier.startswith("cp"):
|
elif "t-win_arm64" in identifier and identifier.startswith("cp"):
|
||||||
config_update = self.windows_t_arm64.update_version_windows(spec)
|
config_update = self.windows_t_arm64.update_version_windows(spec)
|
||||||
elif "win_arm64" in identifier and identifier.startswith("cp"):
|
elif "win_arm64" in identifier and identifier.startswith("cp"):
|
||||||
|
|||||||
@@ -243,6 +243,8 @@ def build_description_from_identifier(identifier: str) -> str:
|
|||||||
build_description += "CPython"
|
build_description += "CPython"
|
||||||
elif python_interpreter == "pp":
|
elif python_interpreter == "pp":
|
||||||
build_description += "PyPy"
|
build_description += "PyPy"
|
||||||
|
elif python_interpreter == "gp":
|
||||||
|
build_description += "GraalPy"
|
||||||
else:
|
else:
|
||||||
msg = f"unknown python {python_interpreter!r}"
|
msg = f"unknown python {python_interpreter!r}"
|
||||||
raise Exception(msg)
|
raise Exception(msg)
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ def get_python_configurations(
|
|||||||
# skip builds as required by BUILD/SKIP
|
# skip builds as required by BUILD/SKIP
|
||||||
python_configurations = [c for c in python_configurations if build_selector(c.identifier)]
|
python_configurations = [c for c in python_configurations if build_selector(c.identifier)]
|
||||||
|
|
||||||
# filter-out some cross-compilation configs with PyPy:
|
# filter-out some cross-compilation configs with PyPy and GraalPy:
|
||||||
# can't build arm64 on x86_64
|
# can't build arm64 on x86_64
|
||||||
# rosetta allows to build x86_64 on arm64
|
# rosetta allows to build x86_64 on arm64
|
||||||
if platform.machine() == "x86_64":
|
if platform.machine() == "x86_64":
|
||||||
@@ -111,7 +111,7 @@ def get_python_configurations(
|
|||||||
python_configurations = [
|
python_configurations = [
|
||||||
c
|
c
|
||||||
for c in python_configurations
|
for c in python_configurations
|
||||||
if not (c.identifier.startswith("pp") and c.identifier.endswith("arm64"))
|
if not (c.identifier.startswith(("pp", "gp")) and c.identifier.endswith("arm64"))
|
||||||
]
|
]
|
||||||
removed_elements = python_configurations_before - set(python_configurations)
|
removed_elements = python_configurations_before - set(python_configurations)
|
||||||
if removed_elements:
|
if removed_elements:
|
||||||
@@ -191,6 +191,22 @@ def install_pypy(tmp: Path, url: str) -> Path:
|
|||||||
return installation_path / "bin" / "pypy3"
|
return installation_path / "bin" / "pypy3"
|
||||||
|
|
||||||
|
|
||||||
|
def install_graalpy(tmp: Path, url: str) -> Path:
|
||||||
|
graalpy_archive = url.rsplit("/", 1)[-1]
|
||||||
|
extension = ".tar.gz"
|
||||||
|
assert graalpy_archive.endswith(extension)
|
||||||
|
installation_path = CIBW_CACHE_PATH / graalpy_archive[: -len(extension)]
|
||||||
|
with FileLock(str(installation_path) + ".lock"):
|
||||||
|
if not installation_path.exists():
|
||||||
|
downloaded_archive = tmp / graalpy_archive
|
||||||
|
download(url, downloaded_archive)
|
||||||
|
installation_path.mkdir(parents=True)
|
||||||
|
# GraalPy top-folder name is inconsistent with archive name
|
||||||
|
call("tar", "-C", installation_path, "--strip-components=1", "-xzf", downloaded_archive)
|
||||||
|
downloaded_archive.unlink()
|
||||||
|
return installation_path / "bin" / "graalpy"
|
||||||
|
|
||||||
|
|
||||||
def setup_python(
|
def setup_python(
|
||||||
tmp: Path,
|
tmp: Path,
|
||||||
python_configuration: PythonConfiguration,
|
python_configuration: PythonConfiguration,
|
||||||
@@ -212,6 +228,8 @@ def setup_python(
|
|||||||
|
|
||||||
elif implementation_id.startswith("pp"):
|
elif implementation_id.startswith("pp"):
|
||||||
base_python = install_pypy(tmp, python_configuration.url)
|
base_python = install_pypy(tmp, python_configuration.url)
|
||||||
|
elif implementation_id.startswith("gp"):
|
||||||
|
base_python = install_graalpy(tmp, python_configuration.url)
|
||||||
else:
|
else:
|
||||||
msg = "Unknown Python implementation"
|
msg = "Unknown Python implementation"
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|||||||
@@ -123,6 +123,20 @@ def install_pypy(tmp: Path, arch: str, url: str) -> Path:
|
|||||||
return installation_path / "python.exe"
|
return installation_path / "python.exe"
|
||||||
|
|
||||||
|
|
||||||
|
def install_graalpy(tmp: Path, url: str) -> Path:
|
||||||
|
zip_filename = url.rsplit("/", 1)[-1]
|
||||||
|
extension = ".zip"
|
||||||
|
assert zip_filename.endswith(extension)
|
||||||
|
installation_path = CIBW_CACHE_PATH / zip_filename[: -len(extension)]
|
||||||
|
with FileLock(str(installation_path) + ".lock"):
|
||||||
|
if not installation_path.exists():
|
||||||
|
graalpy_zip = tmp / zip_filename
|
||||||
|
download(url, graalpy_zip)
|
||||||
|
# Extract to the parent directory because the zip file still contains a directory
|
||||||
|
extract_zip(graalpy_zip, installation_path.parent)
|
||||||
|
return installation_path / "bin" / "graalpy.exe"
|
||||||
|
|
||||||
|
|
||||||
def setup_setuptools_cross_compile(
|
def setup_setuptools_cross_compile(
|
||||||
tmp: Path,
|
tmp: Path,
|
||||||
python_configuration: PythonConfiguration,
|
python_configuration: PythonConfiguration,
|
||||||
@@ -239,6 +253,8 @@ def setup_python(
|
|||||||
elif implementation_id.startswith("pp"):
|
elif implementation_id.startswith("pp"):
|
||||||
assert python_configuration.url is not None
|
assert python_configuration.url is not None
|
||||||
base_python = install_pypy(tmp, python_configuration.arch, python_configuration.url)
|
base_python = install_pypy(tmp, python_configuration.arch, python_configuration.url)
|
||||||
|
elif implementation_id.startswith("gp"):
|
||||||
|
base_python = install_graalpy(tmp, python_configuration.url or "")
|
||||||
else:
|
else:
|
||||||
msg = "Unknown Python implementation"
|
msg = "Unknown Python implementation"
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
@@ -314,6 +330,49 @@ def setup_python(
|
|||||||
setup_setuptools_cross_compile(tmp, python_configuration, python_libs_base, env)
|
setup_setuptools_cross_compile(tmp, python_configuration, python_libs_base, env)
|
||||||
setup_rust_cross_compile(tmp, python_configuration, python_libs_base, env)
|
setup_rust_cross_compile(tmp, python_configuration, python_libs_base, env)
|
||||||
|
|
||||||
|
if implementation_id.startswith("gp"):
|
||||||
|
# GraalPy fails to discover compilers, setup the relevant environment
|
||||||
|
# variables. Adapted from
|
||||||
|
# https://github.com/microsoft/vswhere/wiki/Start-Developer-Command-Prompt
|
||||||
|
# Remove when https://github.com/oracle/graalpython/issues/492 is fixed.
|
||||||
|
vcpath = subprocess.check_output(
|
||||||
|
[
|
||||||
|
Path(os.environ["PROGRAMFILES(X86)"])
|
||||||
|
/ "Microsoft Visual Studio"
|
||||||
|
/ "Installer"
|
||||||
|
/ "vswhere.exe",
|
||||||
|
"-products",
|
||||||
|
"*",
|
||||||
|
"-latest",
|
||||||
|
"-property",
|
||||||
|
"installationPath",
|
||||||
|
],
|
||||||
|
text=True,
|
||||||
|
).strip()
|
||||||
|
log.notice(f"Discovering Visual Studio for GraalPy at {vcpath}")
|
||||||
|
env.update(
|
||||||
|
dict(
|
||||||
|
[
|
||||||
|
envvar.strip().split("=", 1)
|
||||||
|
for envvar in subprocess.check_output(
|
||||||
|
[
|
||||||
|
f"{vcpath}\\Common7\\Tools\\vsdevcmd.bat",
|
||||||
|
"-no_logo",
|
||||||
|
"-arch=amd64",
|
||||||
|
"-host_arch=amd64",
|
||||||
|
"&&",
|
||||||
|
"set",
|
||||||
|
],
|
||||||
|
shell=True,
|
||||||
|
text=True,
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
.strip()
|
||||||
|
.split("\n")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return base_python, env
|
return base_python, env
|
||||||
|
|
||||||
|
|
||||||
@@ -342,6 +401,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
for config in python_configurations:
|
for config in python_configurations:
|
||||||
build_options = options.build_options(config.identifier)
|
build_options = options.build_options(config.identifier)
|
||||||
build_frontend = build_options.build_frontend or BuildFrontendConfig("build")
|
build_frontend = build_options.build_frontend or BuildFrontendConfig("build")
|
||||||
|
|
||||||
use_uv = build_frontend.name == "build[uv]" and can_use_uv(config)
|
use_uv = build_frontend.name == "build[uv]" and can_use_uv(config)
|
||||||
log.build_start(config.identifier)
|
log.build_start(config.identifier)
|
||||||
|
|
||||||
@@ -390,6 +450,22 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
build_frontend, build_options.build_verbosity, build_options.config_settings
|
build_frontend, build_options.build_verbosity, build_options.config_settings
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
config.identifier.startswith("gp")
|
||||||
|
and build_frontend.name == "build"
|
||||||
|
and "--no-isolation" not in extra_flags
|
||||||
|
and "-n" not in extra_flags
|
||||||
|
):
|
||||||
|
# GraalPy fails to discover its standard library when a venv is created
|
||||||
|
# from a virtualenv seeded executable. See
|
||||||
|
# https://github.com/oracle/graalpython/issues/491 and remove this once
|
||||||
|
# fixed upstream.
|
||||||
|
log.notice(
|
||||||
|
"Disabling build isolation to workaround GraalPy bug. If the build fails, consider using pip or build[uv] as build frontend."
|
||||||
|
)
|
||||||
|
shell("graalpy -m pip install setuptools wheel", env=env)
|
||||||
|
extra_flags = [*extra_flags, "-n"]
|
||||||
|
|
||||||
build_env = env.copy()
|
build_env = env.copy()
|
||||||
if pip_version is not None:
|
if pip_version is not None:
|
||||||
build_env["VIRTUALENV_PIP"] = pip_version
|
build_env["VIRTUALENV_PIP"] = pip_version
|
||||||
@@ -414,6 +490,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
elif build_frontend.name == "build" or build_frontend.name == "build[uv]":
|
elif build_frontend.name == "build" or build_frontend.name == "build[uv]":
|
||||||
if use_uv and "--no-isolation" not in extra_flags and "-n" not in extra_flags:
|
if use_uv and "--no-isolation" not in extra_flags and "-n" not in extra_flags:
|
||||||
extra_flags.append("--installer=uv")
|
extra_flags.append("--installer=uv")
|
||||||
|
|
||||||
call(
|
call(
|
||||||
"python",
|
"python",
|
||||||
"-m",
|
"-m",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ python_configurations = [
|
|||||||
{ identifier = "pp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
{ identifier = "pp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
||||||
{ identifier = "pp310-manylinux_x86_64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
|
{ identifier = "pp310-manylinux_x86_64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
|
||||||
{ identifier = "pp311-manylinux_x86_64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" },
|
{ identifier = "pp311-manylinux_x86_64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" },
|
||||||
|
{ identifier = "gp242-manylinux_x86_64", version = "3.11", path_str = "/opt/python/graalpy311-graalpy242_311_native" },
|
||||||
{ identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
{ identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||||
{ identifier = "cp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
|
{ identifier = "cp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
|
||||||
{ identifier = "cp310-manylinux_aarch64", version = "3.10", path_str = "/opt/python/cp310-cp310" },
|
{ identifier = "cp310-manylinux_aarch64", version = "3.10", path_str = "/opt/python/cp310-cp310" },
|
||||||
@@ -57,6 +58,7 @@ python_configurations = [
|
|||||||
{ identifier = "pp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
{ identifier = "pp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
||||||
{ identifier = "pp310-manylinux_aarch64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
|
{ identifier = "pp310-manylinux_aarch64", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
|
||||||
{ identifier = "pp311-manylinux_aarch64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" },
|
{ identifier = "pp311-manylinux_aarch64", version = "3.11", path_str = "/opt/python/pp311-pypy311_pp73" },
|
||||||
|
{ identifier = "gp242-manylinux_aarch64", version = "3.11", path_str = "/opt/python/graalpy311-graalpy242_311_native" },
|
||||||
{ identifier = "pp38-manylinux_i686", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
|
{ identifier = "pp38-manylinux_i686", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
|
||||||
{ identifier = "pp39-manylinux_i686", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
{ identifier = "pp39-manylinux_i686", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
||||||
{ identifier = "pp310-manylinux_i686", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
|
{ identifier = "pp310-manylinux_i686", version = "3.10", path_str = "/opt/python/pp310-pypy310_pp73" },
|
||||||
@@ -143,6 +145,8 @@ python_configurations = [
|
|||||||
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_arm64.tar.bz2" },
|
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_arm64.tar.bz2" },
|
||||||
{ identifier = "pp311-macosx_x86_64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.19-macos_x86_64.tar.bz2" },
|
{ identifier = "pp311-macosx_x86_64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.19-macos_x86_64.tar.bz2" },
|
||||||
{ identifier = "pp311-macosx_arm64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.19-macos_arm64.tar.bz2" },
|
{ identifier = "pp311-macosx_arm64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.19-macos_arm64.tar.bz2" },
|
||||||
|
{ identifier = "gp242-macosx_x86_64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.0/graalpy-24.2.0-macos-amd64.tar.gz" },
|
||||||
|
{ identifier = "gp242-macosx_arm64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.0/graalpy-24.2.0-macos-aarch64.tar.gz" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[windows]
|
[windows]
|
||||||
@@ -171,6 +175,7 @@ python_configurations = [
|
|||||||
{ identifier = "pp39-win_amd64", version = "3.9", arch = "64", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" },
|
{ identifier = "pp39-win_amd64", version = "3.9", arch = "64", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" },
|
||||||
{ identifier = "pp310-win_amd64", version = "3.10", arch = "64", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip" },
|
{ identifier = "pp310-win_amd64", version = "3.10", arch = "64", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip" },
|
||||||
{ identifier = "pp311-win_amd64", version = "3.11", arch = "64", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.19-win64.zip" },
|
{ identifier = "pp311-win_amd64", version = "3.11", arch = "64", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.19-win64.zip" },
|
||||||
|
{ identifier = "gp242-win_amd64", version = "3.11", arch = "64", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.0/graalpy-24.2.0-windows-amd64.zip" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[pyodide]
|
[pyodide]
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class EnableGroup(StrEnum):
|
|||||||
CPythonPrerelease = "cpython-prerelease"
|
CPythonPrerelease = "cpython-prerelease"
|
||||||
PyPy = "pypy"
|
PyPy = "pypy"
|
||||||
CPythonExperimentalRiscV64 = "cpython-experimental-riscv64"
|
CPythonExperimentalRiscV64 = "cpython-experimental-riscv64"
|
||||||
|
GraalPy = "graalpy"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def all_groups(cls) -> frozenset["EnableGroup"]:
|
def all_groups(cls) -> frozenset["EnableGroup"]:
|
||||||
@@ -75,6 +76,8 @@ class BuildSelector:
|
|||||||
build_id, "*_riscv64"
|
build_id, "*_riscv64"
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
|
if EnableGroup.GraalPy not in self.enable and fnmatch(build_id, "gp*"):
|
||||||
|
return False
|
||||||
|
|
||||||
should_build = selector_matches(self.build_config, build_id)
|
should_build = selector_matches(self.build_config, build_id)
|
||||||
should_skip = selector_matches(self.skip_config, build_id)
|
should_skip = selector_matches(self.skip_config, build_id)
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ values are:
|
|||||||
- `cpython-experimental-riscv64`: Enable experimental riscv64 builds. Those builds
|
- `cpython-experimental-riscv64`: Enable experimental riscv64 builds. Those builds
|
||||||
are disabled by default as they can't be uploaded to PyPI and a PEP will most likely
|
are disabled by default as they can't be uploaded to PyPI and a PEP will most likely
|
||||||
be required before this can happen.
|
be required before this can happen.
|
||||||
|
- `graalpy`: Enable GraalPy.
|
||||||
|
|
||||||
|
|
||||||
!!! caution
|
!!! caution
|
||||||
|
|||||||
+1
-2
@@ -56,9 +56,8 @@ def docker_warmup(request: pytest.FixtureRequest) -> None:
|
|||||||
images = [build_options.manylinux_images[arch] for arch in archs] + [
|
images = [build_options.manylinux_images[arch] for arch in archs] + [
|
||||||
build_options.musllinux_images[arch] for arch in archs
|
build_options.musllinux_images[arch] for arch in archs
|
||||||
]
|
]
|
||||||
# exclude GraalPy as it's not a target for cibuildwheel
|
|
||||||
command = (
|
command = (
|
||||||
"manylinux-interpreters ensure $(manylinux-interpreters list 2>/dev/null | grep -v graalpy) &&"
|
"manylinux-interpreters ensure-all &&"
|
||||||
"cpython3.13 -m pip download -d /tmp setuptools wheel pytest"
|
"cpython3.13 -m pip download -d /tmp setuptools wheel pytest"
|
||||||
)
|
)
|
||||||
for image in images:
|
for image in images:
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ def test_abi3(tmp_path):
|
|||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
# free_threaded and PyPy do not have a Py_LIMITED_API equivalent, just build one of those
|
# free_threaded, GraalPy, and PyPy do not have a Py_LIMITED_API equivalent, just build one of those
|
||||||
# also limit the number of builds for test performance reasons
|
# also limit the number of builds for test performance reasons
|
||||||
"CIBW_BUILD": f"cp39-* cp310-* pp310-* {single_python_tag}-* cp313t-*"
|
"CIBW_BUILD": f"cp39-* cp310-* pp310-* gp242-* {single_python_tag}-* cp313t-*"
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,7 +59,11 @@ def test_abi3(tmp_path):
|
|||||||
expected_wheels = [
|
expected_wheels = [
|
||||||
w.replace("cp310-cp310", "cp310-abi3")
|
w.replace("cp310-cp310", "cp310-abi3")
|
||||||
for w in expected_wheels
|
for w in expected_wheels
|
||||||
if "-cp39" in w or "-cp310" in w or "-pp310" in w or "-cp313t" in w
|
if "-cp39" in w
|
||||||
|
or "-cp310" in w
|
||||||
|
or "-pp310" in w
|
||||||
|
or "-graalpy242" in w
|
||||||
|
or "-cp313t" in w
|
||||||
]
|
]
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ def test(tmp_path):
|
|||||||
|
|
||||||
# build the wheels
|
# build the wheels
|
||||||
before_all_command = (
|
before_all_command = (
|
||||||
"""python -c "import os, sys;open('{project}/text_info.txt', 'w').write('sample text '+os.environ.get('TEST_VAL', ''))" && """
|
"""python -c "import os, pathlib, sys; pathlib.Path('{project}/text_info.txt').write_text('sample text '+os.environ.get('TEST_VAL', ''))" && """
|
||||||
'''python -c "import sys; open('{project}/python_prefix.txt', 'w').write(sys.prefix)"'''
|
'''python -c "import pathlib, sys; pathlib.Path('{project}/python_prefix.txt').write_text(sys.prefix)"'''
|
||||||
)
|
)
|
||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ def test(tmp_path):
|
|||||||
project_with_before_build_asserts.generate(project_dir)
|
project_with_before_build_asserts.generate(project_dir)
|
||||||
|
|
||||||
before_build = (
|
before_build = (
|
||||||
"""python -c "import sys; open('{project}/pythonversion_bb.txt', 'w').write(sys.version)" && """
|
"""python -c "import pathlib, sys; pathlib.Path('{project}/pythonversion_bb.txt').write_text(sys.version)" && """
|
||||||
f'''python -c "import sys; open('{{project}}/pythonprefix_bb.txt', 'w').write({SYS_PREFIX})"'''
|
f'''python -c "import pathlib, sys; pathlib.Path('{{project}}/pythonprefix_bb.txt').write_text({SYS_PREFIX})"'''
|
||||||
)
|
)
|
||||||
frontend = "build"
|
frontend = "build"
|
||||||
if utils.platform != "pyodide":
|
if utils.platform != "pyodide":
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import os
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
PROJECT_DIR = Path(__file__).joinpath("..", "..").resolve()
|
PROJECT_DIR = Path(__file__).parent.parent.resolve()
|
||||||
|
|
||||||
|
|
||||||
class TestBeforeTest(TestCase):
|
class TestBeforeTest(TestCase):
|
||||||
@@ -39,8 +39,8 @@ def test(tmp_path, build_frontend_env):
|
|||||||
test_projects.new_c_project().generate(test_project_dir)
|
test_projects.new_c_project().generate(test_project_dir)
|
||||||
|
|
||||||
before_test_steps = [
|
before_test_steps = [
|
||||||
'''python -c "import os, sys; open('{project}/pythonversion_bt.txt', 'w').write(sys.version)"''',
|
'''python -c "import pathlib, sys; pathlib.Path('{project}/pythonversion_bt.txt').write_text(sys.version)"''',
|
||||||
'''python -c "import os, sys; open('{project}/pythonprefix_bt.txt', 'w').write(sys.prefix)"''',
|
'''python -c "import pathlib, sys; pathlib.Path('{project}/pythonprefix_bt.txt').write_text(sys.prefix)"''',
|
||||||
]
|
]
|
||||||
|
|
||||||
if utils.platform == "pyodide":
|
if utils.platform == "pyodide":
|
||||||
@@ -63,7 +63,9 @@ def test(tmp_path, build_frontend_env):
|
|||||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||||
# mac/linux.
|
# mac/linux.
|
||||||
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} ./test",
|
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} ./test",
|
||||||
"CIBW_TEST_COMMAND_WINDOWS": "pytest ./test",
|
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
|
||||||
|
# until https://github.com/oracle/graalpython/issues/490 is fixed
|
||||||
|
"CIBW_TEST_COMMAND_WINDOWS": "where graalpy || pytest ./test",
|
||||||
**build_frontend_env,
|
**build_frontend_env,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -128,6 +128,17 @@ def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv):
|
|||||||
|
|
||||||
build_environment = {}
|
build_environment = {}
|
||||||
|
|
||||||
|
if (
|
||||||
|
utils.platform == "windows"
|
||||||
|
and method == "file"
|
||||||
|
and build_frontend_env_nouv["CIBW_BUILD_FRONTEND"] == "build"
|
||||||
|
):
|
||||||
|
# GraalPy fails to discover its standard library when a venv is created
|
||||||
|
# from a virtualenv seeded executable. See
|
||||||
|
# https://github.com/oracle/graalpython/issues/491 and remove this once
|
||||||
|
# fixed upstream.
|
||||||
|
build_frontend_env_nouv["CIBW_SKIP"] = "gp*"
|
||||||
|
|
||||||
for package_name, version in tool_versions.items():
|
for package_name, version in tool_versions.items():
|
||||||
env_name = f"EXPECTED_{package_name.upper()}_VERSION"
|
env_name = f"EXPECTED_{package_name.upper()}_VERSION"
|
||||||
build_environment[env_name] = version
|
build_environment[env_name] = version
|
||||||
@@ -147,4 +158,13 @@ def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv):
|
|||||||
# also check that we got the right wheels
|
# also check that we got the right wheels
|
||||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||||
|
|
||||||
|
if (
|
||||||
|
utils.platform == "windows"
|
||||||
|
and method == "file"
|
||||||
|
and build_frontend_env_nouv["CIBW_BUILD_FRONTEND"] == "build"
|
||||||
|
):
|
||||||
|
# See reference to https://github.com/oracle/graalpython/issues/491
|
||||||
|
# above
|
||||||
|
expected_wheels = [w for w in expected_wheels if "graalpy" not in w]
|
||||||
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|||||||
@@ -33,11 +33,26 @@ def test_pep518(tmp_path, build_frontend_env):
|
|||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
basic_project.generate(project_dir)
|
basic_project.generate(project_dir)
|
||||||
|
|
||||||
|
# GraalPy fails to discover its standard library when a venv is created
|
||||||
|
# from a virtualenv seeded executable. See
|
||||||
|
# https://github.com/oracle/graalpython/issues/491 and remove this once
|
||||||
|
# fixed upstream.
|
||||||
|
if build_frontend_env["CIBW_BUILD_FRONTEND"] == "build" and utils.platform == "windows":
|
||||||
|
build_frontend_env["CIBW_SKIP"] = "gp*"
|
||||||
|
|
||||||
# build the wheels
|
# build the wheels
|
||||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=build_frontend_env)
|
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=build_frontend_env)
|
||||||
|
|
||||||
# check that the expected wheels are produced
|
# check that the expected wheels are produced
|
||||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||||
|
|
||||||
|
# GraalPy fails to discover its standard library when a venv is created
|
||||||
|
# from a virtualenv seeded executable. See
|
||||||
|
# https://github.com/oracle/graalpython/issues/491 and remove this once
|
||||||
|
# fixed upstream.
|
||||||
|
if build_frontend_env["CIBW_BUILD_FRONTEND"] == "build" and utils.platform == "windows":
|
||||||
|
expected_wheels = [w for w in expected_wheels if "graalpy" not in w]
|
||||||
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
# These checks ensure an extra file is not created when using custom
|
# These checks ensure an extra file is not created when using custom
|
||||||
|
|||||||
+15
-5
@@ -81,7 +81,9 @@ def test(tmp_path):
|
|||||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||||
# mac/linux.
|
# mac/linux.
|
||||||
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} ./test",
|
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} ./test",
|
||||||
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest ./test",
|
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
|
||||||
|
# until https://github.com/oracle/graalpython/issues/490 is fixed
|
||||||
|
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || where graalpy || pytest ./test",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -102,7 +104,9 @@ def test_extras_require(tmp_path):
|
|||||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||||
# mac/linux.
|
# mac/linux.
|
||||||
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} ./test",
|
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} ./test",
|
||||||
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest ./test",
|
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
|
||||||
|
# until https://github.com/oracle/graalpython/issues/490 is fixed
|
||||||
|
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || where graalpy || pytest ./test",
|
||||||
},
|
},
|
||||||
single_python=True,
|
single_python=True,
|
||||||
)
|
)
|
||||||
@@ -134,7 +138,9 @@ def test_dependency_groups(tmp_path):
|
|||||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||||
# mac/linux.
|
# mac/linux.
|
||||||
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} ./test",
|
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} ./test",
|
||||||
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest ./test",
|
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
|
||||||
|
# until https://github.com/oracle/graalpython/issues/490 is fixed
|
||||||
|
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || where graalpy || pytest ./test",
|
||||||
},
|
},
|
||||||
single_python=True,
|
single_python=True,
|
||||||
)
|
)
|
||||||
@@ -189,7 +195,9 @@ def test_bare_pytest_invocation(tmp_path: Path, test_runner: str) -> None:
|
|||||||
add_env={
|
add_env={
|
||||||
"CIBW_TEST_REQUIRES": "pytest" if test_runner == "pytest" else "",
|
"CIBW_TEST_REQUIRES": "pytest" if test_runner == "pytest" else "",
|
||||||
"CIBW_TEST_COMMAND": (
|
"CIBW_TEST_COMMAND": (
|
||||||
"python -m pytest"
|
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
|
||||||
|
# until https://github.com/oracle/graalpython/issues/490 fixed
|
||||||
|
"graalpy.exe -c 1 || python -m pytest"
|
||||||
if test_runner == "pytest"
|
if test_runner == "pytest"
|
||||||
else "python -m unittest discover test spam_test.py"
|
else "python -m unittest discover test spam_test.py"
|
||||||
),
|
),
|
||||||
@@ -211,7 +219,9 @@ def test_test_sources(tmp_path):
|
|||||||
add_env={
|
add_env={
|
||||||
"CIBW_TEST_REQUIRES": "pytest",
|
"CIBW_TEST_REQUIRES": "pytest",
|
||||||
"CIBW_TEST_COMMAND": "pytest",
|
"CIBW_TEST_COMMAND": "pytest",
|
||||||
"CIBW_TEST_COMMAND_WINDOWS": "pytest",
|
# pytest fails on GraalPy 24.2.0 on Windows so we skip it there
|
||||||
|
# until https://github.com/oracle/graalpython/issues/490 is fixed
|
||||||
|
"CIBW_TEST_COMMAND_WINDOWS": "where graalpy || pytest",
|
||||||
"CIBW_TEST_SOURCES": "test",
|
"CIBW_TEST_SOURCES": "test",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
+6
-2
@@ -55,7 +55,7 @@ def cibuildwheel_get_build_identifiers(
|
|||||||
cmd = [sys.executable, "-m", "cibuildwheel", "--print-build-identifiers", str(project_path)]
|
cmd = [sys.executable, "-m", "cibuildwheel", "--print-build-identifiers", str(project_path)]
|
||||||
if env is None:
|
if env is None:
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["CIBW_ENABLE"] = "cpython-freethreading pypy"
|
env["CIBW_ENABLE"] = "cpython-freethreading pypy graalpy"
|
||||||
if prerelease_pythons:
|
if prerelease_pythons:
|
||||||
env["CIBW_ENABLE"] += " cpython-prerelease"
|
env["CIBW_ENABLE"] += " cpython-prerelease"
|
||||||
|
|
||||||
@@ -257,6 +257,10 @@ def _expected_wheels(
|
|||||||
"pp310-pypy310_pp73",
|
"pp310-pypy310_pp73",
|
||||||
"pp311-pypy311_pp73",
|
"pp311-pypy311_pp73",
|
||||||
]
|
]
|
||||||
|
if machine_arch in ["x86_64", "AMD64", "aarch64", "arm64"]:
|
||||||
|
python_abi_tags += [
|
||||||
|
"graalpy311-graalpy242_311_native",
|
||||||
|
]
|
||||||
|
|
||||||
if single_python:
|
if single_python:
|
||||||
python_tag = "cp{}{}-".format(*SINGLE_PYTHON_VERSION)
|
python_tag = "cp{}{}-".format(*SINGLE_PYTHON_VERSION)
|
||||||
@@ -286,7 +290,7 @@ def _expected_wheels(
|
|||||||
for manylinux_version in manylinux_versions
|
for manylinux_version in manylinux_versions
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
if len(musllinux_versions) > 0 and not python_abi_tag.startswith("pp"):
|
if len(musllinux_versions) > 0 and not python_abi_tag.startswith(("pp", "graalpy")):
|
||||||
platform_tags.append(
|
platform_tags.append(
|
||||||
".".join(
|
".".join(
|
||||||
f"{musllinux_version}_{machine_arch}"
|
f"{musllinux_version}_{machine_arch}"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ def test_linux_container_split(tmp_path: Path, monkeypatch: pytest.MonkeyPatch)
|
|||||||
manylinux-x86_64-image = "normal_container_image"
|
manylinux-x86_64-image = "normal_container_image"
|
||||||
manylinux-i686-image = "normal_container_image"
|
manylinux-i686-image = "normal_container_image"
|
||||||
build = "*-manylinux_x86_64"
|
build = "*-manylinux_x86_64"
|
||||||
skip = "pp*"
|
skip = "[gp]p*"
|
||||||
archs = "x86_64 i686"
|
archs = "x86_64 i686"
|
||||||
|
|
||||||
[[tool.cibuildwheel.overrides]]
|
[[tool.cibuildwheel.overrides]]
|
||||||
|
|||||||
@@ -423,9 +423,9 @@ def test_debug_traceback(monkeypatch, method, capfd):
|
|||||||
@pytest.mark.parametrize("method", ["unset", "command_line", "env_var"])
|
@pytest.mark.parametrize("method", ["unset", "command_line", "env_var"])
|
||||||
def test_enable(method, intercepted_build_args, monkeypatch):
|
def test_enable(method, intercepted_build_args, monkeypatch):
|
||||||
if method == "command_line":
|
if method == "command_line":
|
||||||
monkeypatch.setattr(sys, "argv", [*sys.argv, "--enable", "pypy"])
|
monkeypatch.setattr(sys, "argv", [*sys.argv, "--enable", "pypy", "--enable", "graalpy"])
|
||||||
elif method == "env_var":
|
elif method == "env_var":
|
||||||
monkeypatch.setenv("CIBW_ENABLE", "pypy")
|
monkeypatch.setenv("CIBW_ENABLE", "pypy graalpy")
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
||||||
@@ -434,18 +434,20 @@ def test_enable(method, intercepted_build_args, monkeypatch):
|
|||||||
if method == "unset":
|
if method == "unset":
|
||||||
assert enable_groups == frozenset()
|
assert enable_groups == frozenset()
|
||||||
else:
|
else:
|
||||||
assert enable_groups == frozenset([EnableGroup.PyPy])
|
assert enable_groups == frozenset([EnableGroup.PyPy, EnableGroup.GraalPy])
|
||||||
|
|
||||||
|
|
||||||
def test_enable_arg_inherits(intercepted_build_args, monkeypatch):
|
def test_enable_arg_inherits(intercepted_build_args, monkeypatch):
|
||||||
monkeypatch.setenv("CIBW_ENABLE", "pypy")
|
monkeypatch.setenv("CIBW_ENABLE", "pypy graalpy")
|
||||||
monkeypatch.setattr(sys, "argv", [*sys.argv, "--enable", "cpython-prerelease"])
|
monkeypatch.setattr(sys, "argv", [*sys.argv, "--enable", "cpython-prerelease"])
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
||||||
enable_groups = intercepted_build_args.args[0].globals.build_selector.enable
|
enable_groups = intercepted_build_args.args[0].globals.build_selector.enable
|
||||||
|
|
||||||
assert enable_groups == frozenset((EnableGroup.PyPy, EnableGroup.CPythonPrerelease))
|
assert enable_groups == frozenset(
|
||||||
|
(EnableGroup.PyPy, EnableGroup.GraalPy, EnableGroup.CPythonPrerelease)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_enable_arg_error_message(monkeypatch, capsys):
|
def test_enable_arg_error_message(monkeypatch, capsys):
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from cibuildwheel.oci_container import OCIPlatform
|
|||||||
from cibuildwheel.util import file
|
from cibuildwheel.util import file
|
||||||
|
|
||||||
DEFAULT_IDS = {"cp38", "cp39", "cp310", "cp311", "cp312", "cp313"}
|
DEFAULT_IDS = {"cp38", "cp39", "cp310", "cp311", "cp312", "cp313"}
|
||||||
ALL_IDS = DEFAULT_IDS | {"cp313t", "pp38", "pp39", "pp310", "pp311"}
|
ALL_IDS = DEFAULT_IDS | {"cp313t", "pp38", "pp39", "pp310", "pp311", "gp242"}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -103,7 +103,7 @@ def test_build_with_override_launches(monkeypatch, tmp_path):
|
|||||||
[tool.cibuildwheel]
|
[tool.cibuildwheel]
|
||||||
manylinux-x86_64-image = "manylinux_2_28"
|
manylinux-x86_64-image = "manylinux_2_28"
|
||||||
musllinux-x86_64-image = "musllinux_1_2"
|
musllinux-x86_64-image = "musllinux_1_2"
|
||||||
enable = ["pypy", "cpython-freethreading"]
|
enable = ["pypy", "graalpy", "cpython-freethreading"]
|
||||||
|
|
||||||
# Before Python 3.10, use manylinux2014
|
# Before Python 3.10, use manylinux2014
|
||||||
[[tool.cibuildwheel.overrides]]
|
[[tool.cibuildwheel.overrides]]
|
||||||
@@ -155,6 +155,7 @@ before-all = "true"
|
|||||||
"pp39",
|
"pp39",
|
||||||
"pp310",
|
"pp310",
|
||||||
"pp311",
|
"pp311",
|
||||||
|
"gp242",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert kwargs["options"].build_options("cp39-manylinux_x86_64").before_all == ""
|
assert kwargs["options"].build_options("cp39-manylinux_x86_64").before_all == ""
|
||||||
@@ -176,6 +177,7 @@ before-all = "true"
|
|||||||
"pp39",
|
"pp39",
|
||||||
"pp310",
|
"pp310",
|
||||||
"pp311",
|
"pp311",
|
||||||
|
"gp242",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,14 +187,16 @@ before-all = "true"
|
|||||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
|
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
|
||||||
|
|
||||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||||
assert identifiers == {f"{x}-manylinux_i686" for x in ALL_IDS}
|
assert identifiers == {f"{x}-manylinux_i686" for x in ALL_IDS if "gp" not in x}
|
||||||
|
|
||||||
kwargs = build_in_container.call_args_list[4][1]
|
kwargs = build_in_container.call_args_list[4][1]
|
||||||
assert "quay.io/pypa/musllinux_1_2_x86_64" in kwargs["container"]["image"]
|
assert "quay.io/pypa/musllinux_1_2_x86_64" in kwargs["container"]["image"]
|
||||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
|
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
|
||||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||||
assert identifiers == {f"{x}-musllinux_x86_64" for x in ALL_IDS if "pp" not in x}
|
assert identifiers == {
|
||||||
|
f"{x}-musllinux_x86_64" for x in ALL_IDS if "pp" not in x and "gp" not in x
|
||||||
|
}
|
||||||
|
|
||||||
kwargs = build_in_container.call_args_list[5][1]
|
kwargs = build_in_container.call_args_list[5][1]
|
||||||
assert "quay.io/pypa/musllinux_1_2_i686" in kwargs["container"]["image"]
|
assert "quay.io/pypa/musllinux_1_2_i686" in kwargs["container"]["image"]
|
||||||
@@ -200,4 +204,6 @@ before-all = "true"
|
|||||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
|
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
|
||||||
|
|
||||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||||
assert identifiers == {f"{x}-musllinux_i686" for x in ALL_IDS if "pp" not in x}
|
assert identifiers == {
|
||||||
|
f"{x}-musllinux_i686" for x in ALL_IDS if "pp" not in x and "gp" not in x
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user