mirror of
https://github.com/python/cpython.git
synced 2025-12-07 13:50:06 +00:00
gh-141691: Apply ruff rules to Apple folder. (#141694)
Add ruff configuration to run over the Apple build tooling and testbed script.
This commit is contained in:
parent
4cfa695c95
commit
17636ba48c
4 changed files with 126 additions and 91 deletions
|
|
@ -2,6 +2,10 @@ repos:
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.13.2
|
rev: v0.13.2
|
||||||
hooks:
|
hooks:
|
||||||
|
- id: ruff-check
|
||||||
|
name: Run Ruff (lint) on Apple/
|
||||||
|
args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml]
|
||||||
|
files: ^Apple/
|
||||||
- id: ruff-check
|
- id: ruff-check
|
||||||
name: Run Ruff (lint) on Doc/
|
name: Run Ruff (lint) on Doc/
|
||||||
args: [--exit-non-zero-on-fix]
|
args: [--exit-non-zero-on-fix]
|
||||||
|
|
@ -30,6 +34,10 @@ repos:
|
||||||
name: Run Ruff (lint) on Tools/wasm/
|
name: Run Ruff (lint) on Tools/wasm/
|
||||||
args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml]
|
args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml]
|
||||||
files: ^Tools/wasm/
|
files: ^Tools/wasm/
|
||||||
|
- id: ruff-format
|
||||||
|
name: Run Ruff (format) on Apple/
|
||||||
|
args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml]
|
||||||
|
files: ^Apple
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
name: Run Ruff (format) on Doc/
|
name: Run Ruff (format) on Doc/
|
||||||
args: [--check]
|
args: [--check]
|
||||||
|
|
|
||||||
22
Apple/.ruff.toml
Normal file
22
Apple/.ruff.toml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
extend = "../.ruff.toml" # Inherit the project-wide settings
|
||||||
|
|
||||||
|
[format]
|
||||||
|
preview = true
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
|
[lint]
|
||||||
|
select = [
|
||||||
|
"C4", # flake8-comprehensions
|
||||||
|
"E", # pycodestyle
|
||||||
|
"F", # pyflakes
|
||||||
|
"I", # isort
|
||||||
|
"ISC", # flake8-implicit-str-concat
|
||||||
|
"LOG", # flake8-logging
|
||||||
|
"PGH", # pygrep-hooks
|
||||||
|
"PT", # flake8-pytest-style
|
||||||
|
"PYI", # flake8-pyi
|
||||||
|
"RUF100", # Ban unused `# noqa` comments
|
||||||
|
"UP", # pyupgrade
|
||||||
|
"W", # pycodestyle
|
||||||
|
"YTT", # flake8-2020
|
||||||
|
]
|
||||||
|
|
@ -46,13 +46,12 @@
|
||||||
import sys
|
import sys
|
||||||
import sysconfig
|
import sysconfig
|
||||||
import time
|
import time
|
||||||
from collections.abc import Sequence
|
from collections.abc import Callable, Sequence
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from os.path import basename, relpath
|
from os.path import basename, relpath
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from subprocess import CalledProcessError
|
from subprocess import CalledProcessError
|
||||||
from typing import Callable
|
|
||||||
|
|
||||||
EnvironmentT = dict[str, str]
|
EnvironmentT = dict[str, str]
|
||||||
ArgsT = Sequence[str | Path]
|
ArgsT = Sequence[str | Path]
|
||||||
|
|
@ -140,17 +139,15 @@ def print_env(env: EnvironmentT) -> None:
|
||||||
def apple_env(host: str) -> EnvironmentT:
|
def apple_env(host: str) -> EnvironmentT:
|
||||||
"""Construct an Apple development environment for the given host."""
|
"""Construct an Apple development environment for the given host."""
|
||||||
env = {
|
env = {
|
||||||
"PATH": ":".join(
|
"PATH": ":".join([
|
||||||
[
|
str(PYTHON_DIR / "Apple/iOS/Resources/bin"),
|
||||||
str(PYTHON_DIR / "Apple/iOS/Resources/bin"),
|
str(subdir(host) / "prefix"),
|
||||||
str(subdir(host) / "prefix"),
|
"/usr/bin",
|
||||||
"/usr/bin",
|
"/bin",
|
||||||
"/bin",
|
"/usr/sbin",
|
||||||
"/usr/sbin",
|
"/sbin",
|
||||||
"/sbin",
|
"/Library/Apple/usr/bin",
|
||||||
"/Library/Apple/usr/bin",
|
]),
|
||||||
]
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return env
|
return env
|
||||||
|
|
@ -196,14 +193,10 @@ def clean(context: argparse.Namespace, target: str = "all") -> None:
|
||||||
paths.append(target)
|
paths.append(target)
|
||||||
|
|
||||||
if target in {"all", "hosts", "test"}:
|
if target in {"all", "hosts", "test"}:
|
||||||
paths.extend(
|
paths.extend([
|
||||||
[
|
path.name
|
||||||
path.name
|
for path in CROSS_BUILD_DIR.glob(f"{context.platform}-testbed.*")
|
||||||
for path in CROSS_BUILD_DIR.glob(
|
])
|
||||||
f"{context.platform}-testbed.*"
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
delete_path(path)
|
delete_path(path)
|
||||||
|
|
@ -352,18 +345,16 @@ def download(url: str, target_dir: Path) -> Path:
|
||||||
|
|
||||||
out_path = target_path / basename(url)
|
out_path = target_path / basename(url)
|
||||||
if not Path(out_path).is_file():
|
if not Path(out_path).is_file():
|
||||||
run(
|
run([
|
||||||
[
|
"curl",
|
||||||
"curl",
|
"-Lf",
|
||||||
"-Lf",
|
"--retry",
|
||||||
"--retry",
|
"5",
|
||||||
"5",
|
"--retry-all-errors",
|
||||||
"--retry-all-errors",
|
"-o",
|
||||||
"-o",
|
out_path,
|
||||||
out_path,
|
url,
|
||||||
url,
|
])
|
||||||
]
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
print(f"Using cached version of {basename(url)}")
|
print(f"Using cached version of {basename(url)}")
|
||||||
return out_path
|
return out_path
|
||||||
|
|
@ -468,8 +459,7 @@ def package_version(prefix_path: Path) -> str:
|
||||||
|
|
||||||
|
|
||||||
def lib_platform_files(dirname, names):
|
def lib_platform_files(dirname, names):
|
||||||
"""A file filter that ignores platform-specific files in the lib directory.
|
"""A file filter that ignores platform-specific files in lib."""
|
||||||
"""
|
|
||||||
path = Path(dirname)
|
path = Path(dirname)
|
||||||
if (
|
if (
|
||||||
path.parts[-3] == "lib"
|
path.parts[-3] == "lib"
|
||||||
|
|
@ -478,7 +468,7 @@ def lib_platform_files(dirname, names):
|
||||||
):
|
):
|
||||||
return names
|
return names
|
||||||
elif path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
|
elif path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
|
||||||
ignored_names = set(
|
ignored_names = {
|
||||||
name
|
name
|
||||||
for name in names
|
for name in names
|
||||||
if (
|
if (
|
||||||
|
|
@ -486,7 +476,7 @@ def lib_platform_files(dirname, names):
|
||||||
or name.startswith("_sysconfig_vars_")
|
or name.startswith("_sysconfig_vars_")
|
||||||
or name == "build-details.json"
|
or name == "build-details.json"
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
else:
|
else:
|
||||||
ignored_names = set()
|
ignored_names = set()
|
||||||
|
|
||||||
|
|
@ -499,7 +489,9 @@ def lib_non_platform_files(dirname, names):
|
||||||
"""
|
"""
|
||||||
path = Path(dirname)
|
path = Path(dirname)
|
||||||
if path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
|
if path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
|
||||||
return set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
|
return (
|
||||||
|
set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
|
|
@ -514,7 +506,8 @@ def create_xcframework(platform: str) -> str:
|
||||||
package_path.mkdir()
|
package_path.mkdir()
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"{platform} XCframework already exists; do you need to run with --clean?"
|
f"{platform} XCframework already exists; do you need to run "
|
||||||
|
"with --clean?"
|
||||||
) from None
|
) from None
|
||||||
|
|
||||||
frameworks = []
|
frameworks = []
|
||||||
|
|
@ -607,7 +600,7 @@ def create_xcframework(platform: str) -> str:
|
||||||
print(f" - {slice_name} binaries")
|
print(f" - {slice_name} binaries")
|
||||||
shutil.copytree(first_path / "bin", slice_path / "bin")
|
shutil.copytree(first_path / "bin", slice_path / "bin")
|
||||||
|
|
||||||
# Copy the include path (this will be a symlink to the framework headers)
|
# Copy the include path (a symlink to the framework headers)
|
||||||
print(f" - {slice_name} include files")
|
print(f" - {slice_name} include files")
|
||||||
shutil.copytree(
|
shutil.copytree(
|
||||||
first_path / "include",
|
first_path / "include",
|
||||||
|
|
@ -659,7 +652,8 @@ def create_xcframework(platform: str) -> str:
|
||||||
# statically link those libraries into a Framework, you become
|
# statically link those libraries into a Framework, you become
|
||||||
# responsible for providing a privacy manifest for that framework.
|
# responsible for providing a privacy manifest for that framework.
|
||||||
xcprivacy_file = {
|
xcprivacy_file = {
|
||||||
"OpenSSL": subdir(host_triple) / "prefix/share/OpenSSL.xcprivacy"
|
"OpenSSL": subdir(host_triple)
|
||||||
|
/ "prefix/share/OpenSSL.xcprivacy"
|
||||||
}
|
}
|
||||||
print(f" - {multiarch} xcprivacy files")
|
print(f" - {multiarch} xcprivacy files")
|
||||||
for module, lib in [
|
for module, lib in [
|
||||||
|
|
@ -669,7 +663,8 @@ def create_xcframework(platform: str) -> str:
|
||||||
shutil.copy(
|
shutil.copy(
|
||||||
xcprivacy_file[lib],
|
xcprivacy_file[lib],
|
||||||
slice_path
|
slice_path
|
||||||
/ f"lib-{arch}/python{version_tag}/lib-dynload/{module}.xcprivacy",
|
/ f"lib-{arch}/python{version_tag}"
|
||||||
|
/ f"lib-dynload/{module}.xcprivacy",
|
||||||
)
|
)
|
||||||
|
|
||||||
print(" - build tools")
|
print(" - build tools")
|
||||||
|
|
@ -692,18 +687,16 @@ def package(context: argparse.Namespace) -> None:
|
||||||
|
|
||||||
# Clone testbed
|
# Clone testbed
|
||||||
print()
|
print()
|
||||||
run(
|
run([
|
||||||
[
|
sys.executable,
|
||||||
sys.executable,
|
"Apple/testbed",
|
||||||
"Apple/testbed",
|
"clone",
|
||||||
"clone",
|
"--platform",
|
||||||
"--platform",
|
context.platform,
|
||||||
context.platform,
|
"--framework",
|
||||||
"--framework",
|
CROSS_BUILD_DIR / context.platform / "Python.xcframework",
|
||||||
CROSS_BUILD_DIR / context.platform / "Python.xcframework",
|
CROSS_BUILD_DIR / context.platform / "testbed",
|
||||||
CROSS_BUILD_DIR / context.platform / "testbed",
|
])
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Build the final archive
|
# Build the final archive
|
||||||
archive_name = (
|
archive_name = (
|
||||||
|
|
@ -757,7 +750,7 @@ def build(context: argparse.Namespace, host: str | None = None) -> None:
|
||||||
package(context)
|
package(context)
|
||||||
|
|
||||||
|
|
||||||
def test(context: argparse.Namespace, host: str | None = None) -> None:
|
def test(context: argparse.Namespace, host: str | None = None) -> None: # noqa: PT028
|
||||||
"""The implementation of the "test" command."""
|
"""The implementation of the "test" command."""
|
||||||
if host is None:
|
if host is None:
|
||||||
host = context.host
|
host = context.host
|
||||||
|
|
@ -795,18 +788,16 @@ def test(context: argparse.Namespace, host: str | None = None) -> None:
|
||||||
/ f"Frameworks/{apple_multiarch(host)}"
|
/ f"Frameworks/{apple_multiarch(host)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
run(
|
run([
|
||||||
[
|
sys.executable,
|
||||||
sys.executable,
|
"Apple/testbed",
|
||||||
"Apple/testbed",
|
"clone",
|
||||||
"clone",
|
"--platform",
|
||||||
"--platform",
|
context.platform,
|
||||||
context.platform,
|
"--framework",
|
||||||
"--framework",
|
framework_path,
|
||||||
framework_path,
|
testbed_dir,
|
||||||
testbed_dir,
|
])
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
run(
|
run(
|
||||||
[
|
[
|
||||||
|
|
@ -840,7 +831,7 @@ def apple_sim_host(platform_name: str) -> str:
|
||||||
"""Determine the native simulator target for this platform."""
|
"""Determine the native simulator target for this platform."""
|
||||||
for _, slice_parts in HOSTS[platform_name].items():
|
for _, slice_parts in HOSTS[platform_name].items():
|
||||||
for host_triple in slice_parts:
|
for host_triple in slice_parts:
|
||||||
parts = host_triple.split('-')
|
parts = host_triple.split("-")
|
||||||
if parts[0] == platform.machine() and parts[-1] == "simulator":
|
if parts[0] == platform.machine() and parts[-1] == "simulator":
|
||||||
return host_triple
|
return host_triple
|
||||||
|
|
||||||
|
|
@ -968,20 +959,29 @@ def parse_args() -> argparse.Namespace:
|
||||||
cmd.add_argument(
|
cmd.add_argument(
|
||||||
"--simulator",
|
"--simulator",
|
||||||
help=(
|
help=(
|
||||||
"The name of the simulator to use (eg: 'iPhone 16e'). Defaults to "
|
"The name of the simulator to use (eg: 'iPhone 16e'). "
|
||||||
"the most recently released 'entry level' iPhone device. Device "
|
"Defaults to the most recently released 'entry level' "
|
||||||
"architecture and OS version can also be specified; e.g., "
|
"iPhone device. Device architecture and OS version can also "
|
||||||
"`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would run on "
|
"be specified; e.g., "
|
||||||
"an ARM64 iPhone 16 Pro simulator running iOS 26.0."
|
"`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would "
|
||||||
|
"run on an ARM64 iPhone 16 Pro simulator running iOS 26.0."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
group = cmd.add_mutually_exclusive_group()
|
group = cmd.add_mutually_exclusive_group()
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--fast-ci", action="store_const", dest="ci_mode", const="fast",
|
"--fast-ci",
|
||||||
help="Add test arguments for GitHub Actions")
|
action="store_const",
|
||||||
|
dest="ci_mode",
|
||||||
|
const="fast",
|
||||||
|
help="Add test arguments for GitHub Actions",
|
||||||
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--slow-ci", action="store_const", dest="ci_mode", const="slow",
|
"--slow-ci",
|
||||||
help="Add test arguments for buildbots")
|
action="store_const",
|
||||||
|
dest="ci_mode",
|
||||||
|
const="slow",
|
||||||
|
help="Add test arguments for buildbots",
|
||||||
|
)
|
||||||
|
|
||||||
for subcommand in [configure_build, configure_host, build, ci]:
|
for subcommand in [configure_build, configure_host, build, ci]:
|
||||||
subcommand.add_argument(
|
subcommand.add_argument(
|
||||||
|
|
|
||||||
|
|
@ -32,15 +32,15 @@ def select_simulator_device(platform):
|
||||||
json_data = json.loads(raw_json)
|
json_data = json.loads(raw_json)
|
||||||
|
|
||||||
if platform == "iOS":
|
if platform == "iOS":
|
||||||
# Any iOS device will do; we'll look for "SE" devices - but the name isn't
|
# Any iOS device will do; we'll look for "SE" devices - but the name
|
||||||
# consistent over time. Older Xcode versions will use "iPhone SE (Nth
|
# isn't consistent over time. Older Xcode versions will use "iPhone SE
|
||||||
# generation)"; As of 2025, they've started using "iPhone 16e".
|
# (Nth generation)"; As of 2025, they've started using "iPhone 16e".
|
||||||
#
|
#
|
||||||
# When Xcode is updated after a new release, new devices will be available
|
# When Xcode is updated after a new release, new devices will be
|
||||||
# and old ones will be dropped from the set available on the latest iOS
|
# available and old ones will be dropped from the set available on the
|
||||||
# version. Select the one with the highest minimum runtime version - this
|
# latest iOS version. Select the one with the highest minimum runtime
|
||||||
# is an indicator of the "newest" released device, which should always be
|
# version - this is an indicator of the "newest" released device, which
|
||||||
# supported on the "most recent" iOS version.
|
# should always be supported on the "most recent" iOS version.
|
||||||
se_simulators = sorted(
|
se_simulators = sorted(
|
||||||
(devicetype["minRuntimeVersion"], devicetype["name"])
|
(devicetype["minRuntimeVersion"], devicetype["name"])
|
||||||
for devicetype in json_data["devicetypes"]
|
for devicetype in json_data["devicetypes"]
|
||||||
|
|
@ -295,7 +295,8 @@ def main():
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description=(
|
description=(
|
||||||
"Manages the process of testing an Apple Python project through Xcode."
|
"Manages the process of testing an Apple Python project "
|
||||||
|
"through Xcode."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -336,7 +337,10 @@ def main():
|
||||||
|
|
||||||
run = subcommands.add_parser(
|
run = subcommands.add_parser(
|
||||||
"run",
|
"run",
|
||||||
usage="%(prog)s [-h] [--simulator SIMULATOR] -- <test arg> [<test arg> ...]",
|
usage=(
|
||||||
|
"%(prog)s [-h] [--simulator SIMULATOR] -- "
|
||||||
|
"<test arg> [<test arg> ...]"
|
||||||
|
),
|
||||||
description=(
|
description=(
|
||||||
"Run a testbed project. The arguments provided after `--` will be "
|
"Run a testbed project. The arguments provided after `--` will be "
|
||||||
"passed to the running iOS process as if they were arguments to "
|
"passed to the running iOS process as if they were arguments to "
|
||||||
|
|
@ -397,9 +401,9 @@ def main():
|
||||||
/ "bin"
|
/ "bin"
|
||||||
).is_dir():
|
).is_dir():
|
||||||
print(
|
print(
|
||||||
f"Testbed does not contain a compiled Python framework. Use "
|
"Testbed does not contain a compiled Python framework. "
|
||||||
f"`python {sys.argv[0]} clone ...` to create a runnable "
|
f"Use `python {sys.argv[0]} clone ...` to create a "
|
||||||
f"clone of this testbed."
|
"runnable clone of this testbed."
|
||||||
)
|
)
|
||||||
sys.exit(20)
|
sys.exit(20)
|
||||||
|
|
||||||
|
|
@ -411,7 +415,8 @@ def main():
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
f"Must specify test arguments (e.g., {sys.argv[0]} run -- test)"
|
"Must specify test arguments "
|
||||||
|
f"(e.g., {sys.argv[0]} run -- test)"
|
||||||
)
|
)
|
||||||
print()
|
print()
|
||||||
parser.print_help(sys.stderr)
|
parser.print_help(sys.stderr)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue