fix: lower the pipeline floor to Python 3.9

The 3.12 guard rested on generate_readme f-strings that have since been
rewritten. Every script compiles under CPython 3.9.25, 3.10 and 3.11, and
only generate_pack's parenthesized context managers fail under 3.8. Under
3.9 the offline pipeline (--skip-packs) completed with no change to the
committed artifacts, the 15 manifests matched 3.12 byte for byte, and the
RomM pack was identical. CI now compiles every script under a real 3.9.
This commit is contained in:
Abdessamad Derraz committed 2026-10-21 05:32:50 +02:00
1 parent 309231afc2
commit bdcc8f0fb6
9 files changed
+54 -17

No files matched your search

+4 -2
View File
@@ -165,12 +165,14 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
# install.py stays on Python 3.8: the suite runs it end to end under a
# real 3.8 interpreter, which import-only and grammar checks miss. The
# last version listed is the default python.
# real 3.8 interpreter, which import-only and grammar checks miss. 3.9
# is the floor pipeline.py states for the build scripts, compiled under
# a real 3.9. The last version listed is the default python.
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
with:
python-version: |
3.8
3.9
3.12
# markdown: the site validation test renders a wiki line to prove the
+2 -2
View File
@@ -131,7 +131,7 @@ python scripts/verify.py --emulator flycast
python scripts/verify.py --platform retroarch --verbose # emulator ground truth
```
Requires Python 3.12 and `pyyaml`. The one-line installer alone runs on Python 3.8.
Requires Python 3.9 or newer and `pyyaml`. The one-line installer alone runs on Python 3.8.
## Documentation site
@@ -180,4 +180,4 @@ The scripts and tooling are released under the [MIT License](LICENSE).
The BIOS and firmware files are not covered by that license: they are third-party system software, preserved and provided for personal backup, archival, and interoperability with emulation software. [NOTICE](NOTICE) sets out their status and how to ask for a file to be removed.
The reasoning, and where it is weakest, is in the [FAQ](https://abdess.github.io/retrobios/wiki/faq/#is-this-legal).
*Auto-generated on 2026-10-20T20:53:07Z*
*Auto-generated on 2026-10-21T03:32:18Z*
+2 -3
View File
@@ -4,9 +4,8 @@ version = "1.0.0"
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/ use syntax
# CPython 3.12 introduced, which is the version CI pins and the version a
# contributor needs to run the pipeline or the test suite.
# 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.
requires-python = ">=3.8"
dependencies = [
"pyyaml",
+1 -1
View File
@@ -582,7 +582,7 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
"python scripts/verify.py --platform retroarch --verbose # emulator ground truth",
"```",
"",
"Requires Python 3.12 and `pyyaml`. The one-line installer alone runs on Python 3.8.",
"Requires Python 3.9 or newer and `pyyaml`. The one-line installer alone runs on Python 3.8.",
"",
"## Documentation site",
"",
+7 -5
View File
@@ -51,11 +51,13 @@ import sys
import time
from pathlib import Path
# The build scripts use syntax CPython 3.12 introduced (generate_readme's
# f-strings, generate_pack's parenthesized context managers). On an older
# interpreter the run got through the packs and failed hours in, at step 7.
if sys.version_info < (3, 12):
sys.exit(f"pipeline.py needs Python 3.12 or newer, this is {sys.version.split()[0]}")
# generate_pack's parenthesized context managers do not compile before
# CPython 3.9, which builds the same database, manifests and packs as 3.12.
# On an older interpreter the run got through the first steps and failed in
# the packs, so it stops before step 0. A test compiles every script under
# this floor.
if sys.version_info < (3, 9):
sys.exit(f"pipeline.py needs Python 3.9 or newer, this is {sys.version.split()[0]}")
sys.path.insert(0, str(Path(__file__).parent))
from common import (
+35 -1
View File
@@ -108,7 +108,41 @@ class ReadmeRegressions(unittest.TestCase):
cwd=ROOT, capture_output=True, text=True, timeout=60, check=False,
)
self.assertEqual(proc.returncode, 1)
self.assertIn("needs Python 3.12", proc.stderr)
self.assertIn("needs Python 3.9", proc.stderr)
def test_the_floor_interpreter_compiles_every_script(self):
"""The floor said 3.12 for a reason the code no longer carried: every
script compiled under 3.9, and only the guard refused it. Checked
with a real interpreter of the floor version, as the installer's 3.8
floor is."""
import shutil # noqa: PLC0415
floor = re.search(
r"sys\.version_info < \((\d+), (\d+)\)",
(ROOT / "scripts" / "pipeline.py").read_text(encoding="utf-8"),
)
name = f"python{floor.group(1)}.{floor.group(2)}"
interpreter = shutil.which(name)
if interpreter is None:
if os.environ.get("CI"):
self.fail(f"CI must provide {name}")
self.skipTest(f"no {name} on PATH")
check = (
"import pathlib, sys\n"
"bad = []\n"
"for p in sorted(pathlib.Path('scripts').rglob('*.py')):\n"
" try:\n"
" compile(p.read_text(encoding='utf-8'), str(p), 'exec')\n"
" except SyntaxError as e:\n"
" bad.append(f'{p}:{e.lineno}')\n"
"print(bad)\n"
"sys.exit(1 if bad else 0)\n"
)
proc = subprocess.run(
[interpreter, "-I", "-c", check], cwd=ROOT, capture_output=True,
text=True, timeout=300, check=False,
)
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
class ReleaseSigningRegressions(unittest.TestCase):
+1 -1
View File
@@ -471,7 +471,7 @@ followed.
RetroPie image, so it stays on Python 3.8 and the standard library alone.
Tests refuse any 3.9 syntax or API, and one runs the installer end to end under
a real 3.8 interpreter, which CI installs beside 3.12 so the check cannot skip.
The build scripts need 3.12 and are not bound by this.
The build scripts need 3.9 and are not bound by this.
Every change to `install.py` recomputes the SHA-256 pinned in `install.sh` and
`install.ps1` in the same commit. The tests compare the pins with the file.
+1 -1
View File
@@ -24,7 +24,7 @@ python -m unittest tests.test_install tests.test_install_cores -v
The table below says which module covers what.
Running the build needs Python 3.12 and `pyyaml` alone, and so does most of the suite. The
Running the build needs Python 3.9 or newer and `pyyaml` alone. CI runs the suite on 3.12. The
schema contract tests also need `jsonschema[format-nongpl]`, and one site test
renders a wiki line with `markdown`. The CI installs both: without them those
tests are reported as skipped, so install them before a pull request
+1 -1
View File
@@ -1,6 +1,6 @@
# Tools
All tools are Python scripts in `scripts/`. They need Python 3.12 and `pyyaml`,
All tools are Python scripts in `scripts/`. They need Python 3.9 or newer and `pyyaml`,
and only `validate_schemas.py` also needs `jsonschema[format-nongpl]`. `install.py`
alone runs on Python 3.8.