Skip to content

Commit 9543c2e

Browse files
[3.14] gh-141691: Apply ruff rules to Apple folder. (GH-141694) (#141728)
Add ruff configuration to run over the Apple build tooling and testbed script. (cherry picked from commit 17636ba) Co-authored-by: Russell Keith-Magee <russell@keith-magee.com>
1 parent ed5c854 commit 9543c2e

File tree

4 files changed

+126
-91
lines changed

4 files changed

+126
-91
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: 77 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,15 @@ 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+
}
490480
else:
491481
ignored_names = set()
492482

@@ -499,7 +489,9 @@ def lib_non_platform_files(dirname, names):
499489
"""
500490
path = Path(dirname)
501491
if path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
502-
return set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
492+
return (
493+
set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
494+
)
503495
else:
504496
return set()
505497

@@ -514,7 +506,8 @@ def create_xcframework(platform: str) -> str:
514506
package_path.mkdir()
515507
except FileExistsError:
516508
raise RuntimeError(
517-
f"{platform} XCframework already exists; do you need to run with --clean?"
509+
f"{platform} XCframework already exists; do you need to run "
510+
"with --clean?"
518511
) from None
519512

520513
frameworks = []
@@ -607,7 +600,7 @@ def create_xcframework(platform: str) -> str:
607600
print(f" - {slice_name} binaries")
608601
shutil.copytree(first_path / "bin", slice_path / "bin")
609602

610-
# Copy the include path (this will be a symlink to the framework headers)
603+
# Copy the include path (a symlink to the framework headers)
611604
print(f" - {slice_name} include files")
612605
shutil.copytree(
613606
first_path / "include",
@@ -659,7 +652,8 @@ def create_xcframework(platform: str) -> str:
659652
# statically link those libraries into a Framework, you become
660653
# responsible for providing a privacy manifest for that framework.
661654
xcprivacy_file = {
662-
"OpenSSL": subdir(host_triple) / "prefix/share/OpenSSL.xcprivacy"
655+
"OpenSSL": subdir(host_triple)
656+
/ "prefix/share/OpenSSL.xcprivacy"
663657
}
664658
print(f" - {multiarch} xcprivacy files")
665659
for module, lib in [
@@ -669,7 +663,8 @@ def create_xcframework(platform: str) -> str:
669663
shutil.copy(
670664
xcprivacy_file[lib],
671665
slice_path
672-
/ f"lib-{arch}/python{version_tag}/lib-dynload/{module}.xcprivacy",
666+
/ f"lib-{arch}/python{version_tag}"
667+
/ f"lib-dynload/{module}.xcprivacy",
673668
)
674669

675670
print(" - build tools")
@@ -692,18 +687,16 @@ def package(context: argparse.Namespace) -> None:
692687

693688
# Clone testbed
694689
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-
)
690+
run([
691+
sys.executable,
692+
"Apple/testbed",
693+
"clone",
694+
"--platform",
695+
context.platform,
696+
"--framework",
697+
CROSS_BUILD_DIR / context.platform / "Python.xcframework",
698+
CROSS_BUILD_DIR / context.platform / "testbed",
699+
])
707700

708701
# Build the final archive
709702
archive_name = (
@@ -757,7 +750,7 @@ def build(context: argparse.Namespace, host: str | None = None) -> None:
757750
package(context)
758751

759752

760-
def test(context: argparse.Namespace, host: str | None = None) -> None:
753+
def test(context: argparse.Namespace, host: str | None = None) -> None: # noqa: PT028
761754
"""The implementation of the "test" command."""
762755
if host is None:
763756
host = context.host
@@ -795,18 +788,16 @@ def test(context: argparse.Namespace, host: str | None = None) -> None:
795788
/ f"Frameworks/{apple_multiarch(host)}"
796789
)
797790

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-
)
791+
run([
792+
sys.executable,
793+
"Apple/testbed",
794+
"clone",
795+
"--platform",
796+
context.platform,
797+
"--framework",
798+
framework_path,
799+
testbed_dir,
800+
])
810801

811802
run(
812803
[
@@ -840,7 +831,7 @@ def apple_sim_host(platform_name: str) -> str:
840831
"""Determine the native simulator target for this platform."""
841832
for _, slice_parts in HOSTS[platform_name].items():
842833
for host_triple in slice_parts:
843-
parts = host_triple.split('-')
834+
parts = host_triple.split("-")
844835
if parts[0] == platform.machine() and parts[-1] == "simulator":
845836
return host_triple
846837

@@ -968,20 +959,29 @@ def parse_args() -> argparse.Namespace:
968959
cmd.add_argument(
969960
"--simulator",
970961
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."
962+
"The name of the simulator to use (eg: 'iPhone 16e'). "
963+
"Defaults to the most recently released 'entry level' "
964+
"iPhone device. Device architecture and OS version can also "
965+
"be specified; e.g., "
966+
"`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would "
967+
"run on an ARM64 iPhone 16 Pro simulator running iOS 26.0."
976968
),
977969
)
978970
group = cmd.add_mutually_exclusive_group()
979971
group.add_argument(
980-
"--fast-ci", action="store_const", dest="ci_mode", const="fast",
981-
help="Add test arguments for GitHub Actions")
972+
"--fast-ci",
973+
action="store_const",
974+
dest="ci_mode",
975+
const="fast",
976+
help="Add test arguments for GitHub Actions",
977+
)
982978
group.add_argument(
983-
"--slow-ci", action="store_const", dest="ci_mode", const="slow",
984-
help="Add test arguments for buildbots")
979+
"--slow-ci",
980+
action="store_const",
981+
dest="ci_mode",
982+
const="slow",
983+
help="Add test arguments for buildbots",
984+
)
985985

986986
for subcommand in [configure_build, configure_host, build, ci]:
987987
subcommand.add_argument(

Apple/testbed/__main__.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ def select_simulator_device(platform):
3232
json_data = json.loads(raw_json)
3333

3434
if platform == "iOS":
35-
# Any iOS device will do; we'll look for "SE" devices - but the name isn't
36-
# consistent over time. Older Xcode versions will use "iPhone SE (Nth
37-
# generation)"; As of 2025, they've started using "iPhone 16e".
35+
# Any iOS device will do; we'll look for "SE" devices - but the name
36+
# isn't consistent over time. Older Xcode versions will use "iPhone SE
37+
# (Nth generation)"; As of 2025, they've started using "iPhone 16e".
3838
#
39-
# When Xcode is updated after a new release, new devices will be available
40-
# and old ones will be dropped from the set available on the latest iOS
41-
# version. Select the one with the highest minimum runtime version - this
42-
# is an indicator of the "newest" released device, which should always be
43-
# supported on the "most recent" iOS version.
39+
# When Xcode is updated after a new release, new devices will be
40+
# available and old ones will be dropped from the set available on the
41+
# latest iOS version. Select the one with the highest minimum runtime
42+
# version - this is an indicator of the "newest" released device, which
43+
# should always be supported on the "most recent" iOS version.
4444
se_simulators = sorted(
4545
(devicetype["minRuntimeVersion"], devicetype["name"])
4646
for devicetype in json_data["devicetypes"]
@@ -295,7 +295,8 @@ def main():
295295

296296
parser = argparse.ArgumentParser(
297297
description=(
298-
"Manages the process of testing an Apple Python project through Xcode."
298+
"Manages the process of testing an Apple Python project "
299+
"through Xcode."
299300
),
300301
)
301302

@@ -336,7 +337,10 @@ def main():
336337

337338
run = subcommands.add_parser(
338339
"run",
339-
usage="%(prog)s [-h] [--simulator SIMULATOR] -- <test arg> [<test arg> ...]",
340+
usage=(
341+
"%(prog)s [-h] [--simulator SIMULATOR] -- "
342+
"<test arg> [<test arg> ...]"
343+
),
340344
description=(
341345
"Run a testbed project. The arguments provided after `--` will be "
342346
"passed to the running iOS process as if they were arguments to "
@@ -397,9 +401,9 @@ def main():
397401
/ "bin"
398402
).is_dir():
399403
print(
400-
f"Testbed does not contain a compiled Python framework. Use "
401-
f"`python {sys.argv[0]} clone ...` to create a runnable "
402-
f"clone of this testbed."
404+
"Testbed does not contain a compiled Python framework. "
405+
f"Use `python {sys.argv[0]} clone ...` to create a "
406+
"runnable clone of this testbed."
403407
)
404408
sys.exit(20)
405409

@@ -411,7 +415,8 @@ def main():
411415
)
412416
else:
413417
print(
414-
f"Must specify test arguments (e.g., {sys.argv[0]} run -- test)"
418+
"Must specify test arguments "
419+
f"(e.g., {sys.argv[0]} run -- test)"
415420
)
416421
print()
417422
parser.print_help(sys.stderr)

0 commit comments

Comments
 (0)