Skip to content

Commit 5d1f8f2

Browse files
committed
Merge branch 'main' of https://github.com/python/cpython
2 parents dbbf4b2 + 92c5de7 commit 5d1f8f2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+4299
-3504
lines changed

.pre-commit-config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
33
rev: v0.13.2
44
hooks:
5+
- id: ruff-check
6+
name: Run Ruff (lint) on Apple/
7+
args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml]
8+
files: ^Apple/
59
- id: ruff-check
610
name: Run Ruff (lint) on Doc/
711
args: [--exit-non-zero-on-fix]
@@ -30,6 +34,10 @@ repos:
3034
name: Run Ruff (lint) on Tools/wasm/
3135
args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml]
3236
files: ^Tools/wasm/
37+
- id: ruff-format
38+
name: Run Ruff (format) on Apple/
39+
args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml]
40+
files: ^Apple
3341
- id: ruff-format
3442
name: Run Ruff (format) on Doc/
3543
args: [--check]

Apple/.ruff.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
extend = "../.ruff.toml" # Inherit the project-wide settings
2+
3+
[format]
4+
preview = true
5+
docstring-code-format = true
6+
7+
[lint]
8+
select = [
9+
"C4", # flake8-comprehensions
10+
"E", # pycodestyle
11+
"F", # pyflakes
12+
"I", # isort
13+
"ISC", # flake8-implicit-str-concat
14+
"LOG", # flake8-logging
15+
"PGH", # pygrep-hooks
16+
"PT", # flake8-pytest-style
17+
"PYI", # flake8-pyi
18+
"RUF100", # Ban unused `# noqa` comments
19+
"UP", # pyupgrade
20+
"W", # pycodestyle
21+
"YTT", # flake8-2020
22+
]

Apple/__main__.py

Lines changed: 91 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,12 @@
4646
import sys
4747
import sysconfig
4848
import time
49-
from collections.abc import Sequence
49+
from collections.abc import Callable, Sequence
5050
from contextlib import contextmanager
5151
from datetime import datetime, timezone
5252
from os.path import basename, relpath
5353
from pathlib import Path
5454
from subprocess import CalledProcessError
55-
from typing import Callable
5655

5756
EnvironmentT = dict[str, str]
5857
ArgsT = Sequence[str | Path]
@@ -140,17 +139,15 @@ def print_env(env: EnvironmentT) -> None:
140139
def apple_env(host: str) -> EnvironmentT:
141140
"""Construct an Apple development environment for the given host."""
142141
env = {
143-
"PATH": ":".join(
144-
[
145-
str(PYTHON_DIR / "Apple/iOS/Resources/bin"),
146-
str(subdir(host) / "prefix"),
147-
"/usr/bin",
148-
"/bin",
149-
"/usr/sbin",
150-
"/sbin",
151-
"/Library/Apple/usr/bin",
152-
]
153-
),
142+
"PATH": ":".join([
143+
str(PYTHON_DIR / "Apple/iOS/Resources/bin"),
144+
str(subdir(host) / "prefix"),
145+
"/usr/bin",
146+
"/bin",
147+
"/usr/sbin",
148+
"/sbin",
149+
"/Library/Apple/usr/bin",
150+
]),
154151
}
155152

156153
return env
@@ -196,14 +193,10 @@ def clean(context: argparse.Namespace, target: str = "all") -> None:
196193
paths.append(target)
197194

198195
if target in {"all", "hosts", "test"}:
199-
paths.extend(
200-
[
201-
path.name
202-
for path in CROSS_BUILD_DIR.glob(
203-
f"{context.platform}-testbed.*"
204-
)
205-
]
206-
)
196+
paths.extend([
197+
path.name
198+
for path in CROSS_BUILD_DIR.glob(f"{context.platform}-testbed.*")
199+
])
207200

208201
for path in paths:
209202
delete_path(path)
@@ -352,18 +345,16 @@ def download(url: str, target_dir: Path) -> Path:
352345

353346
out_path = target_path / basename(url)
354347
if not Path(out_path).is_file():
355-
run(
356-
[
357-
"curl",
358-
"-Lf",
359-
"--retry",
360-
"5",
361-
"--retry-all-errors",
362-
"-o",
363-
out_path,
364-
url,
365-
]
366-
)
348+
run([
349+
"curl",
350+
"-Lf",
351+
"--retry",
352+
"5",
353+
"--retry-all-errors",
354+
"-o",
355+
out_path,
356+
url,
357+
])
367358
else:
368359
print(f"Using cached version of {basename(url)}")
369360
return out_path
@@ -468,8 +459,7 @@ def package_version(prefix_path: Path) -> str:
468459

469460

470461
def lib_platform_files(dirname, names):
471-
"""A file filter that ignores platform-specific files in the lib directory.
472-
"""
462+
"""A file filter that ignores platform-specific files in lib."""
473463
path = Path(dirname)
474464
if (
475465
path.parts[-3] == "lib"
@@ -478,15 +468,21 @@ def lib_platform_files(dirname, names):
478468
):
479469
return names
480470
elif path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
481-
ignored_names = set(
471+
ignored_names = {
482472
name
483473
for name in names
484474
if (
485475
name.startswith("_sysconfigdata_")
486476
or name.startswith("_sysconfig_vars_")
487477
or name == "build-details.json"
488478
)
489-
)
479+
}
480+
elif path.parts[-1] == "lib":
481+
ignored_names = {
482+
name
483+
for name in names
484+
if name.startswith("libpython") and name.endswith(".dylib")
485+
}
490486
else:
491487
ignored_names = set()
492488

@@ -499,7 +495,9 @@ def lib_non_platform_files(dirname, names):
499495
"""
500496
path = Path(dirname)
501497
if path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
502-
return set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
498+
return (
499+
set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
500+
)
503501
else:
504502
return set()
505503

@@ -514,7 +512,8 @@ def create_xcframework(platform: str) -> str:
514512
package_path.mkdir()
515513
except FileExistsError:
516514
raise RuntimeError(
517-
f"{platform} XCframework already exists; do you need to run with --clean?"
515+
f"{platform} XCframework already exists; do you need to run "
516+
"with --clean?"
518517
) from None
519518

520519
frameworks = []
@@ -607,7 +606,7 @@ def create_xcframework(platform: str) -> str:
607606
print(f" - {slice_name} binaries")
608607
shutil.copytree(first_path / "bin", slice_path / "bin")
609608

610-
# Copy the include path (this will be a symlink to the framework headers)
609+
# Copy the include path (a symlink to the framework headers)
611610
print(f" - {slice_name} include files")
612611
shutil.copytree(
613612
first_path / "include",
@@ -621,6 +620,12 @@ def create_xcframework(platform: str) -> str:
621620
slice_framework / "Headers/pyconfig.h",
622621
)
623622

623+
print(f" - {slice_name} shared library")
624+
# Create a simlink for the fat library
625+
shared_lib = slice_path / f"lib/libpython{version_tag}.dylib"
626+
shared_lib.parent.mkdir()
627+
shared_lib.symlink_to("../Python.framework/Python")
628+
624629
print(f" - {slice_name} architecture-specific files")
625630
for host_triple, multiarch in slice_parts.items():
626631
print(f" - {multiarch} standard library")
@@ -632,13 +637,15 @@ def create_xcframework(platform: str) -> str:
632637
framework_path(host_triple, multiarch) / "lib",
633638
package_path / "Python.xcframework/lib",
634639
ignore=lib_platform_files,
640+
symlinks=True,
635641
)
636642
has_common_stdlib = True
637643

638644
shutil.copytree(
639645
framework_path(host_triple, multiarch) / "lib",
640646
slice_path / f"lib-{arch}",
641647
ignore=lib_non_platform_files,
648+
symlinks=True,
642649
)
643650

644651
# Copy the host's pyconfig.h to an architecture-specific name.
@@ -659,7 +666,8 @@ def create_xcframework(platform: str) -> str:
659666
# statically link those libraries into a Framework, you become
660667
# responsible for providing a privacy manifest for that framework.
661668
xcprivacy_file = {
662-
"OpenSSL": subdir(host_triple) / "prefix/share/OpenSSL.xcprivacy"
669+
"OpenSSL": subdir(host_triple)
670+
/ "prefix/share/OpenSSL.xcprivacy"
663671
}
664672
print(f" - {multiarch} xcprivacy files")
665673
for module, lib in [
@@ -669,7 +677,8 @@ def create_xcframework(platform: str) -> str:
669677
shutil.copy(
670678
xcprivacy_file[lib],
671679
slice_path
672-
/ f"lib-{arch}/python{version_tag}/lib-dynload/{module}.xcprivacy",
680+
/ f"lib-{arch}/python{version_tag}"
681+
/ f"lib-dynload/{module}.xcprivacy",
673682
)
674683

675684
print(" - build tools")
@@ -692,18 +701,16 @@ def package(context: argparse.Namespace) -> None:
692701

693702
# Clone testbed
694703
print()
695-
run(
696-
[
697-
sys.executable,
698-
"Apple/testbed",
699-
"clone",
700-
"--platform",
701-
context.platform,
702-
"--framework",
703-
CROSS_BUILD_DIR / context.platform / "Python.xcframework",
704-
CROSS_BUILD_DIR / context.platform / "testbed",
705-
]
706-
)
704+
run([
705+
sys.executable,
706+
"Apple/testbed",
707+
"clone",
708+
"--platform",
709+
context.platform,
710+
"--framework",
711+
CROSS_BUILD_DIR / context.platform / "Python.xcframework",
712+
CROSS_BUILD_DIR / context.platform / "testbed",
713+
])
707714

708715
# Build the final archive
709716
archive_name = (
@@ -757,7 +764,7 @@ def build(context: argparse.Namespace, host: str | None = None) -> None:
757764
package(context)
758765

759766

760-
def test(context: argparse.Namespace, host: str | None = None) -> None:
767+
def test(context: argparse.Namespace, host: str | None = None) -> None: # noqa: PT028
761768
"""The implementation of the "test" command."""
762769
if host is None:
763770
host = context.host
@@ -795,18 +802,16 @@ def test(context: argparse.Namespace, host: str | None = None) -> None:
795802
/ f"Frameworks/{apple_multiarch(host)}"
796803
)
797804

798-
run(
799-
[
800-
sys.executable,
801-
"Apple/testbed",
802-
"clone",
803-
"--platform",
804-
context.platform,
805-
"--framework",
806-
framework_path,
807-
testbed_dir,
808-
]
809-
)
805+
run([
806+
sys.executable,
807+
"Apple/testbed",
808+
"clone",
809+
"--platform",
810+
context.platform,
811+
"--framework",
812+
framework_path,
813+
testbed_dir,
814+
])
810815

811816
run(
812817
[
@@ -840,7 +845,7 @@ def apple_sim_host(platform_name: str) -> str:
840845
"""Determine the native simulator target for this platform."""
841846
for _, slice_parts in HOSTS[platform_name].items():
842847
for host_triple in slice_parts:
843-
parts = host_triple.split('-')
848+
parts = host_triple.split("-")
844849
if parts[0] == platform.machine() and parts[-1] == "simulator":
845850
return host_triple
846851

@@ -968,20 +973,29 @@ def parse_args() -> argparse.Namespace:
968973
cmd.add_argument(
969974
"--simulator",
970975
help=(
971-
"The name of the simulator to use (eg: 'iPhone 16e'). Defaults to "
972-
"the most recently released 'entry level' iPhone device. Device "
973-
"architecture and OS version can also be specified; e.g., "
974-
"`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would run on "
975-
"an ARM64 iPhone 16 Pro simulator running iOS 26.0."
976+
"The name of the simulator to use (eg: 'iPhone 16e'). "
977+
"Defaults to the most recently released 'entry level' "
978+
"iPhone device. Device architecture and OS version can also "
979+
"be specified; e.g., "
980+
"`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would "
981+
"run on an ARM64 iPhone 16 Pro simulator running iOS 26.0."
976982
),
977983
)
978984
group = cmd.add_mutually_exclusive_group()
979985
group.add_argument(
980-
"--fast-ci", action="store_const", dest="ci_mode", const="fast",
981-
help="Add test arguments for GitHub Actions")
986+
"--fast-ci",
987+
action="store_const",
988+
dest="ci_mode",
989+
const="fast",
990+
help="Add test arguments for GitHub Actions",
991+
)
982992
group.add_argument(
983-
"--slow-ci", action="store_const", dest="ci_mode", const="slow",
984-
help="Add test arguments for buildbots")
993+
"--slow-ci",
994+
action="store_const",
995+
dest="ci_mode",
996+
const="slow",
997+
help="Add test arguments for buildbots",
998+
)
985999

9861000
for subcommand in [configure_build, configure_host, build, ci]:
9871001
subcommand.add_argument(

Apple/testbed/Python.xcframework/build/utils.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ install_stdlib() {
4646
rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
4747
rsync -au "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib-$ARCHS/" "$CODESIGNING_FOLDER_PATH/python/lib/"
4848
else
49-
rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
49+
# A single-arch framework will have a libpython symlink; that can't be included at runtime
50+
rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" --exclude 'libpython*.dylib'
5051
fi
5152
}
5253

0 commit comments

Comments
 (0)