feat: add support for building iOS wheels. (#2286)
* Add support for building iOS wheels. * Replace use of system() in test binary module. * Restored the 'minimal' approach of the minimal examples. * Split out platform details into standalone pages, and expand iOS platform details. * More doc corrections. * Bump support package to include fix for python/cpython#130292 * Ensure iOS tests are all run on the same xdist worker. * More iOS documentation tweaks. * Factor out common xcode version test utility. * Simplify iOS to a single platform with an expanded interpretation of arch. * I guess I should update the iOS tests as well... * Additional safety for missing iOS test output. * Remove DYLD_LIBRARY_PATH from the iOS environment. * Make test-sources mandatory for iOS builds. * Updates and clarifications to documentation. * Clarify what a slice is. * Normalize use of underscores in platform name. * Modify auto target to be matching CPU only. * Use consistent ordering of platforms in examples. * Use consistent naming in iOS archiectures. * Placate the linter. * Miscellaneous cleanups picked up by @joerick's review. * Correct the list of expected wheels. * Correct which 'native' we're actually checking. * Correct the docs links so they're all relative. * Correct the identification of free threaded builds. * Use target instead of host to describe the platform we're building for. * Rework iOS test to remove issue with log completeness. * Convert errors to FatalError Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com> Co-authored-by: Joe Rickerby <joerick@mac.com> * Removed a repeated check for a valid python. * Update bin/update_pythons.py to update iOS support packages. * Document that iOS CI is available on other platforms. * Restore a comment needed for some platforms. * Small cleanups identified in code review Co-authored-by: Joe Rickerby <joerick@mac.com> * Simplify logic to appease linter. * Modify dependency constraint handling to use new API. * Cosmetic change to trigger a CI rebuild. --------- Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com> Co-authored-by: Joe Rickerby <joerick@mac.com>
This commit is contained in:
co-authored by
Matthieu Darbois
Joe Rickerby
parent
eefd48e266
commit
26e12290b5
+55
-6
@@ -44,13 +44,13 @@ class ConfigWinPP(TypedDict):
|
||||
url: str
|
||||
|
||||
|
||||
class ConfigMacOS(TypedDict):
|
||||
class ConfigApple(TypedDict):
|
||||
identifier: str
|
||||
version: str
|
||||
url: str
|
||||
|
||||
|
||||
AnyConfig = ConfigWinCP | ConfigWinPP | ConfigMacOS
|
||||
AnyConfig = ConfigWinCP | ConfigWinPP | ConfigApple
|
||||
|
||||
|
||||
# The following set of "Versions" classes allow the initial call to the APIs to
|
||||
@@ -154,7 +154,7 @@ class PyPyVersions:
|
||||
url=url,
|
||||
)
|
||||
|
||||
def update_version_macos(self, spec: Specifier) -> ConfigMacOS:
|
||||
def update_version_macos(self, spec: Specifier) -> ConfigApple:
|
||||
if self.arch not in {"64", "ARM64"}:
|
||||
msg = f"'{self.arch}' arch not supported yet on macOS"
|
||||
raise RuntimeError(msg)
|
||||
@@ -178,7 +178,7 @@ class PyPyVersions:
|
||||
if "" in rf["platform"] == "darwin" and rf["arch"] == arch
|
||||
)
|
||||
|
||||
return ConfigMacOS(
|
||||
return ConfigApple(
|
||||
identifier=identifier,
|
||||
version=f"{version.major}.{version.minor}",
|
||||
url=url,
|
||||
@@ -204,7 +204,7 @@ class CPythonVersions:
|
||||
|
||||
def update_version_macos(
|
||||
self, identifier: str, version: Version, spec: Specifier
|
||||
) -> ConfigMacOS | None:
|
||||
) -> ConfigApple | None:
|
||||
# see note above on Specifier.filter
|
||||
unsorted_versions = spec.filter(self.versions_dict)
|
||||
sorted_versions = sorted(unsorted_versions, reverse=True)
|
||||
@@ -223,7 +223,7 @@ class CPythonVersions:
|
||||
|
||||
urls = [rf["url"] for rf in file_info if file_ident in rf["url"]]
|
||||
if urls:
|
||||
return ConfigMacOS(
|
||||
return ConfigApple(
|
||||
identifier=identifier,
|
||||
version=f"{new_version.major}.{new_version.minor}",
|
||||
url=urls[0],
|
||||
@@ -232,6 +232,48 @@ class CPythonVersions:
|
||||
return None
|
||||
|
||||
|
||||
class CPythonIOSVersions:
|
||||
def __init__(self) -> None:
|
||||
response = requests.get(
|
||||
"https://api.github.com/repos/beeware/Python-Apple-support/releases",
|
||||
headers={
|
||||
"Accept": "application/vnd.github+json",
|
||||
"X-Github-Api-Version": "2022-11-28",
|
||||
},
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
releases_info = response.json()
|
||||
self.versions_dict: dict[Version, dict[int, str]] = {}
|
||||
|
||||
# Each release has a name like "3.13-b4"
|
||||
for release in releases_info:
|
||||
py_version, build = release["name"].split("-")
|
||||
version = Version(py_version)
|
||||
self.versions_dict.setdefault(version, {})
|
||||
|
||||
# There are several release assets associated with each release;
|
||||
# The name of the asset will be something like
|
||||
# "Python-3.11-iOS-support.b4.tar.gz". Store all builds that are
|
||||
# "-iOS-support" builds, retaining the download URL.
|
||||
for asset in release["assets"]:
|
||||
filename, build, _, _ = asset["name"].rsplit(".", 3)
|
||||
if filename.endswith("-iOS-support"):
|
||||
self.versions_dict[version][int(build[1:])] = asset["browser_download_url"]
|
||||
|
||||
def update_version_ios(self, identifier: str, version: Version) -> ConfigApple | None:
|
||||
# Return a config using the highest build number for the given version.
|
||||
urls = [url for _, url in sorted(self.versions_dict.get(version, {}).items())]
|
||||
if urls:
|
||||
return ConfigApple(
|
||||
identifier=identifier,
|
||||
version=str(version),
|
||||
url=urls[-1],
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# This is a universal interface to all the above Versions classes. Given an
|
||||
# identifier, it updates a config dict.
|
||||
|
||||
@@ -250,6 +292,8 @@ class AllVersions:
|
||||
self.macos_pypy = PyPyVersions("64")
|
||||
self.macos_pypy_arm64 = PyPyVersions("ARM64")
|
||||
|
||||
self.ios_cpython = CPythonIOSVersions()
|
||||
|
||||
def update_config(self, config: MutableMapping[str, str]) -> None:
|
||||
identifier = config["identifier"]
|
||||
version = Version(config["version"])
|
||||
@@ -282,6 +326,8 @@ class AllVersions:
|
||||
config_update = self.windows_t_arm64.update_version_windows(spec)
|
||||
elif "win_arm64" in identifier and identifier.startswith("cp"):
|
||||
config_update = self.windows_arm64.update_version_windows(spec)
|
||||
elif "ios" in identifier:
|
||||
config_update = self.ios_cpython.update_version_ios(identifier, version)
|
||||
|
||||
assert config_update is not None, f"{identifier} not found!"
|
||||
config.update(**config_update)
|
||||
@@ -317,6 +363,9 @@ def update_pythons(force: bool, level: str) -> None:
|
||||
for config in configs["macos"]["python_configurations"]:
|
||||
all_versions.update_config(config)
|
||||
|
||||
for config in configs["ios"]["python_configurations"]:
|
||||
all_versions.update_config(config)
|
||||
|
||||
result_toml = dump_python_configurations(configs)
|
||||
|
||||
rich.print() # spacer
|
||||
|
||||
Reference in New Issue
Block a user