fix: load every script under the 3.9 floor

A module-level alias written with a PEP 604 union compiled under 3.9 and
raised TypeError when check_release_assets.py, and check_release.py
through it, were loaded. The floor test now imports every module under
scripts/ with a real 3.9 interpreter, which CI gives pyyaml and
jsonschema.
This commit is contained in:
Abdessamad Derraz committed 2026-10-21 09:53:34 +02:00
1 parent 0242dc77ee
commit 8721dafd2a
3 files changed
+56 -22

No files matched your search

+34 -13
View File
@@ -110,11 +110,12 @@ class ReadmeRegressions(unittest.TestCase):
self.assertEqual(proc.returncode, 1)
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."""
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.
Compiling only checks the grammar: a module-level alias such as
`tuple[int, int | None]` compiles under 3.9 and raises TypeError
when the module loads."""
import shutil # noqa: PLC0415
floor = re.search(
@@ -128,21 +129,41 @@ class ReadmeRegressions(unittest.TestCase):
self.fail(f"CI must provide {name}")
self.skipTest(f"no {name} on PATH")
check = (
"import pathlib, sys\n"
"bad = []\n"
"import importlib, json, pathlib, sys\n"
"sys.path.insert(0, '.')\n"
"failed = {}\n"
"for p in sorted(pathlib.Path('scripts').rglob('*.py')):\n"
" if '__pycache__' in p.parts:\n"
" continue\n"
" parts = p.with_suffix('').parts\n"
" if parts[-1] == '__init__':\n"
" parts = parts[:-1]\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"
" importlib.import_module('.'.join(parts))\n"
" except BaseException as e:\n"
" failed[str(p)] = [type(e).__name__, getattr(e, 'name', None), str(e)]\n"
"print(json.dumps(failed))\n"
)
proc = subprocess.run(
[interpreter, "-I", "-c", check], cwd=ROOT, capture_output=True,
text=True, timeout=300, check=False,
text=True, timeout=600, check=False,
env={**os.environ, "RETROBIOS_OFFLINE": "1"},
)
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
failed = json.loads(proc.stdout.strip().splitlines()[-1])
# pyyaml for every build script, jsonschema for validate_schemas:
# without them the floor interpreter cannot load the modules, which
# proves nothing either way.
absent = sorted({
err[1] for err in failed.values()
if err[0] == "ModuleNotFoundError" and err[1] in ("yaml", "jsonschema")
})
if absent:
message = f"{name} lacks {', '.join(absent)}"
if os.environ.get("CI"):
self.fail(message)
self.skipTest(message)
self.assertEqual(failed, {})
class ReleaseSigningRegressions(unittest.TestCase):