fix: type the code written today for mypy

Every error outside mypy-baseline.txt is fixed in the code:
- common.py: the CRC32 step reused found, the name the layout branch
  gives a resolution tuple, for its list of matches. It now has its own
  name. bindings_of annotates its systems.
- launchers.py, retropie_launchers.py, install.py: an Optional value
  read before its None check.
- recalbox_launchers.py, rocknix_launchers.py: Launcher calls take
  typed keywords, a partial or named parameters, instead of a
  dict[str, object] spread. end_lineno falls back to lineno.
- retrobat_launchers.py: the StageRomKey match no longer reuses the
  str key, and record values are checked before they are iterated.
- batocera_launchers.py: the value of an assignment is read on an
  Assign or AnnAssign only, and the launcher list is annotated.
- emuelec_launchers.py, emuelec_scraper.py, rocknix_scraper.py: import
  fallbacks no importer reaches are dropped, a reused name renamed.
- batocera_targets_scraper.py: a submodule answer without a commit is
  refused.
The baseline loses the 30 entries these fixes resolved and gains
none.
This commit is contained in:
Abdessamad Derraz committed 2026-11-10 04:41:44 +01:00
1 parent b6129310e5
commit 13e60386be
16 files changed
+83 -119

No files matched your search

+3 -3
View File
@@ -113,9 +113,9 @@ def configs_root(cg: Configgen) -> dict[str, str]:
spans = []
for node in reversed(src.tree.body):
name = _assigned_name(node)
if name in wanted:
if name in wanted and isinstance(node, (ast.Assign, ast.AnnAssign)) and node.value:
spans.append((node.lineno, node.end_lineno or node.lineno))
wanted |= {n.id for n in ast.walk(node.value) if isinstance(n, ast.Name)} # type: ignore[union-attr]
wanted |= {n.id for n in ast.walk(node.value) if isinstance(n, ast.Name)}
return {
"path": cg.paths["CONFIGS"],
"from_bios": posixpath.relpath(cg.paths["CONFIGS"], cg.bios),
@@ -943,7 +943,7 @@ def config_directories(
"""file.write("<line naming a BIOS directory>") and settings.save(key, <BIOS directory>)."""
prefix = cg.bios.rstrip("/")
inside = re.compile(rf"{re.escape(prefix)}(?:/[^\s\"';]*)?")
launchers = []
launchers: list[Launcher] = []
for module in modules:
src = cg.generator(module)
constants = dict(cg.paths)
+16 -30
View File
@@ -17,32 +17,18 @@ import re
from collections.abc import Callable
from dataclasses import dataclass, field
try:
from .configgen_launchers import Launcher
from .rocknix_launchers import fixed_paths
from .shell_launchers import (
LauncherPatternMissing,
Link,
RepoTree,
Script,
describe_keys,
settings,
source_ref,
words,
)
except ImportError:
from configgen_launchers import Launcher
from rocknix_launchers import fixed_paths
from shell_launchers import (
LauncherPatternMissing,
Link,
RepoTree,
Script,
describe_keys,
settings,
source_ref,
words,
)
from .configgen_launchers import Launcher
from .rocknix_launchers import fixed_paths
from .shell_launchers import (
LauncherPatternMissing,
Link,
RepoTree,
Script,
describe_keys,
settings,
source_ref,
words,
)
SX05RE = "packages/sx05re"
BIN = f"{SX05RE}/emuelec/bin"
@@ -515,11 +501,11 @@ def advancemame(tree: RepoTree, runs: Runs) -> list[Launcher]:
by_value: dict[tuple[tuple[str, str], ...], list[tuple[str, set[int], int]]] = {}
for mk_line, file in installs:
path = f"{package}/config/{file}"
found = [s for s in settings(tree.read(path), separator=" ") if _under(s.value)]
if not found:
keys = [s for s in settings(tree.read(path), separator=" ") if _under(s.value)]
if not keys:
raise LauncherPatternMissing(path, f"key naming a folder under {BIOS_ROOT}")
value = tuple((s.key, s.value) for s in found)
by_value.setdefault(value, []).append((path, {s.line for s in found}, mk_line))
value = tuple((s.key, s.value) for s in keys)
by_value.setdefault(value, []).append((path, {s.line for s in keys}, mk_line))
if len(by_value) != 1:
raise mk.missing("one set of BIOS folders for every device")
((value, configs),) = by_value.items()
+1 -4
View File
@@ -249,10 +249,7 @@ class Scraper(BaseScraper):
engines depend on emuelec-ports, which no package of an image
depends on, and flycast-dojo is in no device list (UNBUILT there).
"""
try:
from .targets.emuelec_targets_scraper import Scraper as DeviceTargets
except ImportError:
from scraper.targets.emuelec_targets_scraper import Scraper as DeviceTargets
from .targets.emuelec_targets_scraper import Scraper as DeviceTargets
targets = DeviceTargets().device_targets(self.tag)["targets"]
return {name for entry in targets.values() for name in entry["cores"]}
+16 -18
View File
@@ -17,6 +17,7 @@ import ast
import posixpath
import re
from collections.abc import Callable, Mapping
from functools import partial
from typing import Any
from .configgen_launchers import (
@@ -849,22 +850,21 @@ def amiberry(cg: Configgen) -> list[Launcher]:
types = ", ".join(ast.unparse(t).removeprefix("RomType.") for t in entry.elts[0].elts)
names = kick.literal(entry.elts[1], "kickstart names")
ref = f"{kick.ref([kick.span(entry), *tail])}, {config_ref}"
common = dict(emulator=emulator, build="standalone", slot=system,
case_insensitive=False, search_dir=search_dir,
depends_on_option=f"rom type {types}", source_ref=ref)
make = partial(Launcher, emulator=emulator, build="standalone", slot=system,
case_insensitive=False, search_dir=search_dir,
depends_on_option=f"rom type {types}", source_ref=ref)
if any("|" in name for name in names):
if len(names) != 1:
kick.fail(f"line {entry.lineno}: several kickstart pairs are not read")
launchers.append(Launcher(
launchers.append(make(
kind="fixed_name", names=names[0].split("|"),
passes_to=f"{rom_key}, {ext_key}",
fails_when_missing=", ".join(messages), **common,
fails_when_missing=", ".join(messages),
))
else:
launchers.append(Launcher(
launchers.append(make(
kind="names_searched", names=names, passes_to=rom_key,
fails_when_missing=False if system in computers else messages[0],
**common,
))
launchers.append(Launcher(
emulator=emulator, build="standalone", kind="fixed_name", slot=", ".join(computers),
@@ -956,30 +956,28 @@ def pcsx2(cg: Configgen) -> list[Launcher]:
if _assigned_name(n) in {c for c in constants.values()}]
ref = src.ref([(min(names_lines), max(names_lines)), (chooser.lineno, chooser.end_lineno),
(writes[0].lineno, writes[0].end_lineno)])
common = dict(emulator=cg.emulator(PCSX2), build="standalone", case_insensitive=False,
search_dir=search_dir, passes_to=f"[{section}] {key}",
fails_when_missing=False, source_ref=ref)
make = partial(Launcher, emulator=cg.emulator(PCSX2), build="standalone",
case_insensitive=False, search_dir=search_dir,
passes_to=f"[{section}] {key}", fails_when_missing=False, source_ref=ref)
launchers = []
for (given, tested), tokens in groups.items():
slot = constants.get(given, given).removeprefix("BIOS_")
depends = f"rom name contains {', '.join(tokens)}"
if tested == given:
launchers.append(Launcher(
launchers.append(make(
kind="names_searched", slot=slot,
names=list(dict.fromkeys([given, *fallback])),
depends_on_option=depends, **common,
depends_on_option=depends,
))
else:
# The name written is not the one tested: no search, one name.
launchers.append(Launcher(
launchers.append(make(
kind="fixed_name", slot=slot, names=[given],
depends_on_option=f"{depends} and {tested} is present",
**common,
))
launchers.append(Launcher(
launchers.append(make(
kind="names_searched", slot="default", names=fallback,
depends_on_option="rom name with no region token, or its BIOS absent",
**common,
))
return launchers
@@ -1180,7 +1178,7 @@ def core_file_options(cg: Configgen, directories: list[Launcher]) -> list[Launch
names=[call.args[1].value.strip('"')], search_dir=directory.search_dir,
passes_to=f"core option {option}",
depends_on_option=f"system {', '.join(systems)}",
source_ref=f"{src.ref([(function.lineno, function.end_lineno), *spans])}, "
source_ref=f"{src.ref([(function.lineno, function.end_lineno or function.lineno), *spans])}, "
f"{directory.source_ref}",
))
found = {str(launcher.passes_to).split()[-1] for launcher in launchers}
@@ -1210,7 +1208,7 @@ def xroar(cg: Configgen) -> list[Launcher]:
return [Launcher(
emulator=cg.emulator(XROAR), build="standalone", kind="passes_path", names=[],
search_dir=directory, passes_to="command line -rompath",
source_ref=src.ref([(flag.lineno, value.end_lineno)]),
source_ref=src.ref([(flag.lineno, value.end_lineno or value.lineno)]),
)]
+10 -6
View File
@@ -845,8 +845,8 @@ def amiberry(sources: dict[str, Source]) -> list[Record]:
depends_on_option="first name found, the target is absent, smaller or older",
)
)
key = src.find(r"private void StageRomKey\(\)", "StageRomKey")
key_body = src.block_at(key.end())
stage_key = src.find(r"private void StageRomKey\(\)", "StageRomKey")
key_body = src.block_at(stage_key.end())
key_text = src.text[key_body[0]:key_body[1]]
named = re.search(r'FindBios\(new\[\] \{ "([^"]+)" \}\)', key_text)
if not named or not re.search(
@@ -861,7 +861,7 @@ def amiberry(sources: dict[str, Source]) -> list[Record]:
"copies",
[named.group(1)],
source_ref((src.path, [head, src.lines(roms.start(), roms.end()),
(src.line(key.start()), src.lines(*key_body)[1]), method_span])),
(src.line(stage_key.start()), src.lines(*key_body)[1]), method_span])),
case_insensitive=True,
search_dir=search,
passes_to=f"{home}/{roms.group(2)}/{named.group(1)}",
@@ -3386,11 +3386,12 @@ def xroar(sources: dict[str, Source]) -> list[Record]:
# runs a CoCo 3 for coco, so its ROMs are read from that system's folder.
features = sources[FEATURES]
for record in records:
if not record.get("systems"):
systems = record.get("systems")
if not isinstance(systems, list) or not systems:
continue
machines: list[str] = []
lines = []
for system in record["systems"]:
for system in systems:
choices, span = system_feature_choices(features, "xroar", "xroar_machine", system)
machines += [m for m in choices if m not in machines]
lines.append(span)
@@ -3441,11 +3442,14 @@ def _per_system(src: Source, record: Record) -> list[Record]:
return [record]
default, chosen, system = branch.groups()
flag = str(record["passes_to"]).removesuffix(rendered).strip()
names = record["names"]
if not isinstance(names, list):
raise LauncherPatternMissing(src.path, "names of a directory choice")
out = []
for directory, systems in ((default, None), (chosen, [system])):
split = {k: v for k, v in record.items() if k != "source_ref"}
split.update(
names=list(record["names"]), search_dir=directory, passes_to=f"{flag} {directory}"
names=list(names), search_dir=directory, passes_to=f"{flag} {directory}"
)
if systems:
split["systems"] = systems
+1 -1
View File
@@ -840,7 +840,7 @@ class PackageReader:
"""
suffix = " is a symlink to it"
linked = [
record.passes_to.removesuffix(suffix).rstrip("/")
(record.passes_to or "").removesuffix(suffix).rstrip("/")
for record in self.records
if record.kind == "links" and not record.names
and (record.passes_to or "").endswith(suffix)
+11 -4
View File
@@ -192,7 +192,7 @@ def config_records(
package: str,
file: str,
passes_to_suffix: str = "",
**fields: object,
depends_on_option: str | None = None,
) -> list[Launcher]:
"""fixed_name records for the bios paths of a config installed per device."""
configs = device_configs(tree, package, file)
@@ -218,7 +218,7 @@ def config_records(
(described + passes_to_suffix) if value.names else f"{described} left empty"
),
device=device,
**fields,
depends_on_option=depends_on_option,
)
)
return records
@@ -335,7 +335,13 @@ def amiberry(tree: RepoTree) -> list[Launcher]:
return records
def link_record(emulator: str, script: Script, link: Link, **fields: object) -> Launcher:
def link_record(
emulator: str,
script: Script,
link: Link,
case_insensitive: bool | None = None,
fails_when_missing: bool | str = False,
) -> Launcher:
return Launcher(
emulator=emulator,
build="standalone",
@@ -345,7 +351,8 @@ def link_record(emulator: str, script: Script, link: Link, **fields: object) ->
expands=link.expands or None,
search_dir=link.bios_side,
passes_to=f"symlink {link.link} -> {link.target}",
**fields,
case_insensitive=case_insensitive,
fails_when_missing=fails_when_missing,
)
+1 -4
View File
@@ -199,10 +199,7 @@ class Scraper(BaseScraper):
the targets scraper, where every libretro profile counted before. A
standalone package no device carries is not run either.
"""
try:
from .targets.rocknix_targets_scraper import Scraper as DeviceTargets
except ImportError:
from scraper.targets.rocknix_targets_scraper import Scraper as DeviceTargets
from .targets.rocknix_targets_scraper import Scraper as DeviceTargets
builds = DeviceTargets().device_builds(self.tag or launcher_revision(self.url))
libretro = sorted({core for _arch, lr, _sa in builds.values() for core in lr})
carried = set(standalone_emulators(sorted({p for *_rest, sa in builds.values() for p in sa})))
@@ -559,6 +559,8 @@ class Scraper(BaseTargetScraper):
repos = [("", self.REPO, self.tag)]
for prefix, repo in self.SUBMODULES.items():
pin = _fetch_json(self._api(prefix.rstrip("/")))
if not isinstance(pin, dict) or not isinstance(pin.get("sha"), str):
raise RuntimeError(f"no submodule commit for {prefix} at {self.tag}")
repos.append((prefix, repo, pin["sha"]))
found: dict[str, str] = {}
for prefix, repo, ref in repos: