fix: refuse Python 3.8 in every build script

Only generate_pack.py and pipeline.py checked the interpreter. verify.py,
slots.py, validate_pr.py, cross_reference.py and the probe tools started
under 3.8 and stopped halfway on a str.removeprefix AttributeError. The
check now lives in common.py, which every build script imports, and in
core_probe.py and region_check.py, which do not. generate_site.py imports
common before siterender, which raised a TypeError at load under 3.8.
This commit is contained in:
Abdessamad Derraz committed 2026-11-06 14:52:50 +01:00
1 parent c4ae8d9c6e
commit 82bccd9dae
7 files changed
+69 -5

No files matched your search

+2 -1
View File
@@ -16,7 +16,8 @@ description = "BIOS collection manager for retrogaming platforms"
# install.py is the only entry point a user runs before cloning, and both
# bootstraps accept 3.8, so the floor stays where the bootstraps put it. That
# floor covers install.py alone: the build scripts under scripts/ need 3.9
# (pipeline.py checks it), and CI runs the test suite on 3.12.
# (common.py, which every build script imports, checks it), and CI runs the
# test suite on 3.12.
requires-python = ">=3.8"
dependencies = [
"pyyaml",
+6 -3
View File
@@ -83,14 +83,17 @@ from collections.abc import Callable, Iterator, Sequence
from dataclasses import dataclass, field
from pathlib import Path
import yaml
sys.path.insert(0, str(Path(__file__).resolve().parent))
# First: core_probe stops an interpreter older than 3.9 before anything else
# fails on it.
import core_probe
import yaml
import autorun
import campaign_profiles
import campaign_rules as rules
import core_probe
import measurement_records as mr
ROOT = Path(__file__).resolve().parent.parent
+9
View File
@@ -20,6 +20,15 @@ import sys
import zipfile
from pathlib import Path
# Every build script imports this module. verify.py, slots.py, validate_pr.py
# and cross_reference.py started under 3.8 and stopped halfway on a
# str.removeprefix AttributeError, which named no version.
if sys.version_info < (3, 9):
sys.exit(
f"{Path(sys.argv[0]).name} needs Python 3.9 or newer, "
f"this is {sys.version.split()[0]}"
)
try:
import yaml
+8
View File
@@ -40,6 +40,14 @@ from collections.abc import Iterable, Iterator, Sequence
from dataclasses import dataclass, field
from pathlib import Path
# The probe tools do not import common.py, which states the 3.9 floor for the
# other scripts. Under 3.8 they stopped on a str.removesuffix AttributeError.
if sys.version_info < (3, 9):
sys.exit(
f"{Path(sys.argv[0]).name} needs Python 3.9 or newer, "
f"this is {sys.version.split()[0]}"
)
ROOT = Path(__file__).resolve().parent.parent
MIN_BENCH_REPETITIONS = 5
DEFAULT_WORK_DIR = ROOT / "tmp" / "core_probe"
+1 -1
View File
@@ -14,7 +14,6 @@ Usage:
from __future__ import annotations
from siterender import SECTION_LABELS, WIKI_SRC_DIR
import argparse
import csv
import hashlib
@@ -64,6 +63,7 @@ from common import (
unique_emulator_profiles,
yaml_load,
)
from siterender import SECTION_LABELS, WIKI_SRC_DIR
from artifacts import ArtifactLockBusy, artifact_lock
from artifacts import json_text as _json_text
from cross_reference import FileConsumers, entry_target, held_copy
+8
View File
@@ -36,6 +36,14 @@ import urllib.request
from collections.abc import Callable, Iterable
from pathlib import Path
# The probe tools do not import common.py, which states the 3.9 floor for the
# other scripts. Under 3.8 they stopped on a str.removesuffix AttributeError.
if sys.version_info < (3, 9):
sys.exit(
f"{Path(sys.argv[0]).name} needs Python 3.9 or newer, "
f"this is {sys.version.split()[0]}"
)
sys.path.insert(0, str(Path(__file__).resolve().parent))
import yaml # noqa: E402
+35
View File
@@ -136,6 +136,41 @@ class ReadmeRegressions(unittest.TestCase):
self.assertNotIn("SyntaxError", proc.stderr)
self.assertIn("generate_pack.py needs Python 3.9", proc.stderr)
def test_every_script_names_the_floor_under_an_older_interpreter(self):
"""Only generate_pack.py and pipeline.py checked the version. verify.py,
slots.py, validate_pr.py and cross_reference.py started under 3.8 and
stopped halfway on a str.removeprefix AttributeError."""
import shutil # noqa: PLC0415
python38 = shutil.which("python3.8")
if python38 is None:
if os.environ.get("CI"):
self.fail("CI must provide python3.8")
self.skipTest("no python3.8 on PATH")
commands = (
["verify.py", "--emulator", "handy"],
["verify.py", "--platform", "batocera"],
["validate_pr.py", "--json", "README.md"],
["cross_reference.py", "--emulator", "handy"],
["slots.py"],
["identity.py"],
["generate_site.py", "--help"],
["campaign.py", "--help"],
["region_check.py", "--help"],
)
for command in commands:
with self.subTest(command=" ".join(command)):
# -E -s rather than -I: -I drops the script's folder from
# sys.path, so the imports would fail before any check.
proc = subprocess.run(
[python38, "-E", "-s", f"scripts/{command[0]}", *command[1:]],
cwd=ROOT, capture_output=True, text=True, timeout=60,
check=False,
)
self.assertEqual(proc.returncode, 1, proc.stderr)
self.assertNotIn("Traceback", proc.stderr)
self.assertIn(f"{command[0]} needs Python 3.9", proc.stderr)
def test_the_floor_interpreter_imports_every_script(self):
"""Every module under scripts/ is loaded by a real interpreter of the
floor version, as the installer's 3.8 floor is proven by running it.