From 71b59eb2a36a3c8750035e0c2df73d807f55ecc4 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Tue, 20 Oct 2026 09:17:10 +0200 Subject: [PATCH] docs: rewrite half-dash asides in comments Dropping the double-dash asides left 72 comments and docstrings with half a dash glued to the next word ("shape -a size or a size range -is all"). They now read as a colon, a comma or parentheses, and a prose style test names any that comes back. --- CONTRIBUTING.md | 2 +- scripts/artifacts.py | 4 +- scripts/common.py | 6 +-- scripts/crypto_verify.py | 2 +- scripts/dedup.py | 8 ++-- scripts/generate_pack.py | 4 +- scripts/generate_readme.py | 2 +- scripts/packresolve.py | 2 +- scripts/scraper/libretro_scraper.py | 40 +++++++++---------- scripts/scraper/retrodeck_scraper.py | 6 +-- .../targets/batocera_targets_scraper.py | 2 +- .../targets/emudeck_targets_scraper.py | 4 +- .../targets/retroarch_targets_scraper.py | 2 +- scripts/sect233r1.py | 4 +- scripts/truth.py | 4 +- scripts/validation.py | 10 ++--- scripts/verify.py | 8 ++-- tests/test_deterministic_zip.py | 2 +- tests/test_e2e.py | 24 +++++------ tests/test_native_mode.py | 2 +- tests/test_prose_style.py | 18 +++++++++ wiki/adding-a-platform.md | 4 +- 22 files changed, 89 insertions(+), 71 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f92f3942..7762dba8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ 1. Fork this repository 2. Place the file in `bios/Manufacturer/Console/filename` 3. Variants (alternate hashes for the same file): `bios/Manufacturer/Console/.variants/` -4. Open a Pull Request - hashes are verified automatically and reported as a comment +4. Open a pull request. Its hashes are checked automatically and reported in a comment The [dump provenance](https://abdess.github.io/retrobios/provenance/) page lists catalogued dumps still missing from the collection, with their hashes. A file matching one of those is diff --git a/scripts/artifacts.py b/scripts/artifacts.py index c280e9cd..b233bb2e 100644 --- a/scripts/artifacts.py +++ b/scripts/artifacts.py @@ -31,8 +31,8 @@ def write_if_changed( Compares new and existing content after stripping timestamp lines. Returns True if the file was written, False if skipped (unchanged). - A caller that writes a file in two passes -a body, then the same body - wrapped in front matter -passes ``normalize`` to reduce both sides to the + A caller that writes a file in two passes (a body, then the same body + wrapped in front matter) passes ``normalize`` to reduce both sides to the part it owns. Without it the second pass always sees a difference, the file is rewritten, and the fresh timestamp defeats the comparison. """ diff --git a/scripts/common.py b/scripts/common.py index 28a818f5..5a656e75 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -847,7 +847,7 @@ def _resolve_agnostic( """Any file of the right shape under the declared prefix. Some cores accept whatever filename sits in their BIOS directory, so the - shape -a size or a size range -is all that identifies a candidate. A + shape (a size or a size range) is all that identifies a candidate. A declared hash outranks that, and stops this step being reached. """ if not file_entry.get("agnostic") or has_strong_hash: @@ -1557,7 +1557,7 @@ def resolve_local_file( if valid: primary = [c[0] for c in valid if "/.variants/" not in c[0]] return (primary[0] if primary else valid[0][0]), "hash_mismatch" - # No candidate contains the zipped_file -fall through to step 5 + # No candidate contains the zipped_file: fall through to step 5 elif not unsourceable: ordered = _by_affinity([c[0] for c in candidates], file_entry, dest_hint) primary = [c for c in ordered if "/.variants/" not in c] @@ -2557,7 +2557,7 @@ import re -# Validation and mode filtering -extracted to validation.py for SoC. +# Validation and mode filtering: extracted to validation.py for SoC. # Re-exported below for backward compatibility. diff --git a/scripts/crypto_verify.py b/scripts/crypto_verify.py index a9b5312e..081ee2b5 100644 --- a/scripts/crypto_verify.py +++ b/scripts/crypto_verify.py @@ -75,7 +75,7 @@ def _rsa_verify_pkcs1v15_sha256( ) -> bool: """Verify RSA-2048 PKCS#1 v1.5 with SHA-256. - Pure Python -uses Python's native int for modular exponentiation. + Pure Python: uses Python's native int for modular exponentiation. Reproduces CryptoPP::RSASS::Verifier. """ n = int.from_bytes(modulus, "big") diff --git a/scripts/dedup.py b/scripts/dedup.py index 5259e20d..deee40b1 100644 --- a/scripts/dedup.py +++ b/scripts/dedup.py @@ -122,7 +122,7 @@ def _plan_group_removals( Records clone groups in *mame_clones* and returns the paths to remove. """ true_dupes_to_remove: list[str] = [] - # Separate by filename -same name = true duplicate, different name = clone + # Separate by filename: same name = true duplicate, different name = clone by_name: dict[str, list[str]] = defaultdict(list) for p in paths: by_name[os.path.basename(p)].append(p) @@ -147,7 +147,7 @@ def _plan_group_removals( ] true_dupes_to_remove.extend(p for p in variants if p not in holders) - # Different filenames, same content -need special handling + # Different filenames, same content: need special handling unique_names = sorted(by_name.keys()) if len(unique_names) > 1: # Check if these are all in MAME/Arcade dirs AND all ZIPs @@ -171,7 +171,7 @@ def _plan_group_removals( true_dupes_to_remove.append(p) else: # Non-MAME different names (e.g., 64DD_IPL_US.n64 vs IPL_USA.n64) - # Keep ALL -each name may be needed by a different emulator + # Keep ALL: each name may be needed by a different emulator # Only remove true duplicates (same name in multiple dirs) pass @@ -223,7 +223,7 @@ def deduplicate(bios_dir: str, dry_run: bool = False) -> dict: # Find the best canonical across all paths all_paths = [p for p in paths if p not in true_dupes_to_remove] if not all_paths: - # All copies were marked for removal -keep the best one + # All copies were marked for removal: keep the best one all_paths_sorted = sorted(paths, key=path_priority) all_paths = [all_paths_sorted[0]] true_dupes_to_remove = [p for p in paths if p != all_paths[0]] diff --git a/scripts/generate_pack.py b/scripts/generate_pack.py index 6c6b666d..355a1d51 100644 --- a/scripts/generate_pack.py +++ b/scripts/generate_pack.py @@ -994,7 +994,7 @@ def generate_pack( # Emulator-level validation: informational only for platform packs. # Platform verification (existence/md5) is the authority for pack status. - # Emulator checks are supplementary -logged but don't downgrade. + # Emulator checks are supplementary: logged but don't downgrade. # When a discrepancy is found, try to find a file satisfying both. if file_status.get(dedup_key) == "ok": local_path, disagreement = validated_choice( @@ -1145,7 +1145,7 @@ def generate_pack( seen_parents, ) - # README.txt for users -personalized step-by-step per platform + # README.txt for users: personalized step-by-step per platform num_systems = len(pack_systems) _registry_path = Path(platforms_dir) / "_registry.yml" _pack_registry: dict = {} diff --git a/scripts/generate_readme.py b/scripts/generate_readme.py index d2414498..b56ddebe 100644 --- a/scripts/generate_readme.py +++ b/scripts/generate_readme.py @@ -689,7 +689,7 @@ def contributing_text( 1. Fork this repository 2. Place the file in `bios/Manufacturer/Console/filename` 3. Variants (alternate hashes for the same file): `bios/Manufacturer/Console/.variants/` -4. Open a Pull Request - hashes are verified automatically and reported as a comment +4. Open a pull request. Its hashes are checked automatically and reported in a comment The [dump provenance]({link("provenance")}) page lists catalogued dumps still missing from the collection, with their hashes. A file matching one of those is diff --git a/scripts/packresolve.py b/scripts/packresolve.py index be71f409..33fe9e62 100644 --- a/scripts/packresolve.py +++ b/scripts/packresolve.py @@ -212,7 +212,7 @@ def resolve_file( if path and status != "hash_mismatch": return path, status - # Large files from GitHub release assets -tried when local file is + # Large files from GitHub release assets: tried when local file is # missing OR has a hash mismatch (wrong variant on disk) name = file_entry.get("name", "") if file_entry.get("type") == "directory" or name.endswith("/"): diff --git a/scripts/scraper/libretro_scraper.py b/scripts/scraper/libretro_scraper.py index 846c2234..1e2a8c59 100644 --- a/scripts/scraper/libretro_scraper.py +++ b/scripts/scraper/libretro_scraper.py @@ -30,12 +30,12 @@ SOURCE_URL = ( # Libretro cores that expect BIOS files in a subdirectory of system/. # System.dat lists filenames flat, and the scraper prepends the prefix. -# ref: each core's libretro.c or equivalent -see platforms/README.md +# ref: each core's libretro.c or equivalent: see platforms/README.md CORE_SUBDIR_MAP = { "nec-pc-98": "np2kai", # libretro-np2kai/sdl/libretro.c "sharp-x68000": "keropi", # px68k/libretro/libretro.c "sega-dreamcast": "dc", # flycast/shell/libretro/libretro.cpp - "sega-dreamcast-arcade": "dc", # flycast -same subfolder + "sega-dreamcast-arcade": "dc", # flycast: same subfolder } SYSTEM_SLUG_MAP = { @@ -252,11 +252,11 @@ class Scraper(BaseScraper): systems[req.system]["files"].append(requirement_entry(req)) - # Systems not in System.dat but needed for RetroArch -added via + # Systems not in System.dat but needed for RetroArch: added via # shared groups in _shared.yml. The includes directive is resolved # at load time by load_platform_config(). EXTRA_SYSTEMS = { - # ref: Vircon32/libretro.c -virtual console, single BIOS + # ref: Vircon32/libretro.c, virtual console, single BIOS "vircon32": { "files": [ { @@ -269,7 +269,7 @@ class Scraper(BaseScraper): "manufacturer": "Vircon", "docs": "https://docs.libretro.com/library/vircon32/", }, - # ref: xrick/src/sysvid.c, xrick/src/data.c -game data archive + # ref: xrick/src/sysvid.c, xrick/src/data.c, game data archive "xrick": { "files": [ { @@ -295,7 +295,7 @@ class Scraper(BaseScraper): # Arcade BIOS present in the repo but absent from System.dat. # FBNeo expects them in system/ or system/fbneo/. # ref: fbneo/src/burner/libretro/libretro.cpp - # ref: fbneo/src/burner/libretro/libretro.cpp -search order: + # ref: fbneo/src/burner/libretro/libretro.cpp, search order: # 1) romset dir 2) system/fbneo/ 3) system/ EXTRA_ARCADE_FILES = [ {"name": "namcoc69.zip", "destination": "namcoc69.zip", "required": True}, @@ -339,7 +339,7 @@ class Scraper(BaseScraper): # Extra files missing from System.dat for specific systems. # Each traced to the core's source code. EXTRA_SYSTEM_FILES = { - # melonDS DS DSi mode -ref: JesseTG/melonds-ds/src/libretro.cpp + # melonDS DS DSi mode, ref: JesseTG/melonds-ds/src/libretro.cpp "nintendo-ds": [ { "name": "dsi_bios7.bin", @@ -362,7 +362,7 @@ class Scraper(BaseScraper): "required": True, }, ], - # bsnes SGB naming -ref: bsnes/target-libretro/libretro.cpp + # bsnes SGB naming, ref: bsnes/target-libretro/libretro.cpp "nintendo-sgb": [ { "name": "sgb.boot.rom", @@ -370,13 +370,13 @@ class Scraper(BaseScraper): "required": False, }, ], - # JollyCV -ref: jollycv/libretro.c + # JollyCV, ref: jollycv/libretro.c "coleco-colecovision": [ {"name": "BIOS.col", "destination": "BIOS.col", "required": True}, {"name": "coleco.rom", "destination": "coleco.rom", "required": True}, {"name": "bioscv.rom", "destination": "bioscv.rom", "required": True}, ], - # Kronos ST-V -ref: libretro-kronos/libretro/libretro.c + # Kronos ST-V, ref: libretro-kronos/libretro/libretro.c "sega-saturn": [ { "name": "stvbios.zip", @@ -384,7 +384,7 @@ class Scraper(BaseScraper): "required": True, }, ], - # PCSX ReARMed / Beetle PSX alt BIOS -ref: pcsx_rearmed/libpcsxcore/misc.c + # PCSX ReARMed / Beetle PSX alt BIOS, ref: pcsx_rearmed/libpcsxcore/misc.c # docs say PSXONPSP660.bin (uppercase) but core accepts any case "sony-playstation": [ { @@ -393,7 +393,7 @@ class Scraper(BaseScraper): "required": False, }, ], - # Dolphin GC -ref: DolphinLibretro/Boot.cpp:72-73, + # Dolphin GC, ref: DolphinLibretro/Boot.cpp:72-73, # BootManager.cpp:200-217, CommonPaths.h:139 GC_IPL="IPL.bin" # Core searches system/dolphin-emu/Sys/ for data and BIOS. # System.dat gc-ntsc-*.bin names are NOT what Dolphin loads. @@ -414,7 +414,7 @@ class Scraper(BaseScraper): "destination": "dolphin-emu/Sys/GC/JAP/IPL.bin", "required": False, }, - # DSP firmware -ref: Source/Core/Core/HW/DSPLLE/DSPHost.cpp + # DSP firmware, ref: Source/Core/Core/HW/DSPLLE/DSPHost.cpp { "name": "dsp_coef.bin", "destination": "dolphin-emu/Sys/GC/dsp_coef.bin", @@ -425,7 +425,7 @@ class Scraper(BaseScraper): "destination": "dolphin-emu/Sys/GC/dsp_rom.bin", "required": True, }, - # Fonts -ref: Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp + # Fonts, ref: Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp { "name": "font_western.bin", "destination": "dolphin-emu/Sys/GC/font_western.bin", @@ -437,8 +437,8 @@ class Scraper(BaseScraper): "required": False, }, ], - # minivmac casing -ref: minivmac/src/MYOSGLUE.c - # doc says MacII.rom, repo has MacII.ROM -both work on case-insensitive FS + # minivmac casing, ref: minivmac/src/MYOSGLUE.c + # doc says MacII.rom, repo has MacII.ROM: both work on case-insensitive FS "apple-macintosh-ii": [ {"name": "MacII.ROM", "destination": "MacII.ROM", "required": True}, ], @@ -458,7 +458,7 @@ class Scraper(BaseScraper): # Inject shared group references for systems that have core-specific # subdirectory requirements already defined in _shared.yml. # Note: fuse/ prefix NOT injected for sinclair-zx-spectrum. - # Verified in fuse-libretro/src/compat/paths.c -core searches + # Verified in fuse-libretro/src/compat/paths.c, core searches # system/ flat, not fuse/ subfolder. Docs are wrong on this. # A group System.dat already covers entry for entry injects nothing # (ep128emu, keropi and kronos were), and a correction made there @@ -484,12 +484,12 @@ class Scraper(BaseScraper): {"ref": "ppsspp-assets", "destination": "PPSSPP"}, ], # single buildbot ZIP contains both Databases/ and Machines/ - # ref: libretro.c:1118-1119 -system_dir/Machines + system_dir/Databases + # ref: libretro.c:1118-1119, system_dir/Machines + system_dir/Databases "microsoft-msx": [ {"ref": "bluemsx", "destination": ""}, ], - # FreeIntv overlays -system/freeintv_overlays/.png - # ref: FreeIntv/src/libretro.c:273 -stbi_load from system dir + # FreeIntv overlays: system/freeintv_overlays/.png + # ref: FreeIntv/src/libretro.c:273, stbi_load from system dir # ZIP contains FreeIntvTS_Overlays/ subfolder, cache preserves it # pack destination maps cache root to system/freeintv_overlays # so final path is system/freeintv_overlays/FreeIntvTS_Overlays/.png diff --git a/scripts/scraper/retrodeck_scraper.py b/scripts/scraper/retrodeck_scraper.py index d5cf4114..adb3ca1b 100644 --- a/scripts/scraper/retrodeck_scraper.py +++ b/scripts/scraper/retrodeck_scraper.py @@ -184,7 +184,7 @@ def _resolve_path(p: str) -> str: def _extract_bios_entries(component_val: dict) -> list[dict]: """Extract BIOS entries from all three possible locations in a component. - No dedup here -dedup is done in fetch_requirements() with full + No dedup here: dedup is done in fetch_requirements() with full (system, filename) key to avoid dropping valid same-filename entries across different systems. """ @@ -368,13 +368,13 @@ class Scraper(BaseScraper): if resolved.startswith("saves"): continue - # Build destination -default to bios/ if no path specified + # Build destination: default to bios/ if no path specified if resolved: destination = f"{resolved}/{filename}" else: destination = f"bios/{filename}" - # MD5 handling -sanitize upstream errors + # MD5 handling: sanitize upstream errors md5_raw = entry.get("md5", "") if isinstance(md5_raw, list): parts = [str(m).strip().lower() for m in md5_raw if m] diff --git a/scripts/scraper/targets/batocera_targets_scraper.py b/scripts/scraper/targets/batocera_targets_scraper.py index a9ff2969..c4787c07 100644 --- a/scripts/scraper/targets/batocera_targets_scraper.py +++ b/scripts/scraper/targets/batocera_targets_scraper.py @@ -132,7 +132,7 @@ def _check_atom( if tok.startswith('"'): pos += 1 return True, pos - # Unknown token -treat as true to avoid false negatives + # Unknown token: treat as true to avoid false negatives pos += 1 return True, pos diff --git a/scripts/scraper/targets/emudeck_targets_scraper.py b/scripts/scraper/targets/emudeck_targets_scraper.py index 93108e1b..393bbb07 100644 --- a/scripts/scraper/targets/emudeck_targets_scraper.py +++ b/scripts/scraper/targets/emudeck_targets_scraper.py @@ -1,8 +1,8 @@ """Scraper for EmuDeck emulator targets. Sources: - SteamOS: dragoonDorise/EmuDeck -functions/EmuScripts/*.sh - Windows: EmuDeck/emudeck-we -functions/EmuScripts/*.ps1 + SteamOS: dragoonDorise/EmuDeck, functions/EmuScripts/*.sh + Windows: EmuDeck/emudeck-we, functions/EmuScripts/*.ps1 """ from __future__ import annotations diff --git a/scripts/scraper/targets/retroarch_targets_scraper.py b/scripts/scraper/targets/retroarch_targets_scraper.py index 186f18bc..a277809c 100644 --- a/scripts/scraper/targets/retroarch_targets_scraper.py +++ b/scripts/scraper/targets/retroarch_targets_scraper.py @@ -70,7 +70,7 @@ TARGETS: list[tuple[str, str, str]] = [ ("dingux/miyoo-arm32/latest", "miyoo-arm32", "armv5"), ("webos/armv7a/latest", "webos-armv7a", "armv7"), ("webos/aarch64/latest", "webos-aarch64", "aarch64"), - # vita: only VPK bundles on buildbot -cores listed via libretro-super recipes + # vita: only VPK bundles on buildbot, cores listed via libretro-super recipes ] # Recipe-based targets: (recipe_path_under_RECIPE_BASE_URL, target_name, architecture) diff --git a/scripts/sect233r1.py b/scripts/sect233r1.py index 4185547e..7832dadc 100644 --- a/scripts/sect233r1.py +++ b/scripts/sect233r1.py @@ -3,7 +3,7 @@ Implements GF(2^233) field arithmetic, elliptic curve point operations, and ECDSA-SHA256 verification for Nintendo 3DS OTP certificate checking. -Zero external dependencies -uses only Python stdlib. +Zero external dependencies: uses only Python stdlib. Curve: sect233r1 (NIST B-233, SEC 2 v2) Field: GF(2^233) with irreducible polynomial t^233 + t^74 + 1 @@ -83,7 +83,7 @@ def _gf_inv(a: int) -> int: q ^= 1 << shift temp ^= r << shift remainder = temp - # Multiply q * s in GF(2)[x] (no reduction -working in polynomial ring) + # Multiply q * s in GF(2)[x] (no reduction: working in polynomial ring) qs = 0 qt = q st = s diff --git a/scripts/truth.py b/scripts/truth.py index 7ef05940..2c559d03 100644 --- a/scripts/truth.py +++ b/scripts/truth.py @@ -505,7 +505,7 @@ def generate_platform_truth( sys_cov["profiled"].add(emu_name) # Ensure all systems of resolved cores have entries (even with 0 files). - # This documents that the system is covered -the core was analyzed and + # This documents that the system is covered: the core was analyzed and # needs no external files for this system. for emu_name in cores_profiled: profile = profiles[emu_name] @@ -778,7 +778,7 @@ def diff_platform_truth(truth: dict, scraped: dict) -> dict: else: summary["systems_fully_covered"] += 1 - # Truth systems not matched by any scraped system -all files missing + # Truth systems not matched by any scraped system: all files missing for t_sid in sorted(truth_systems): if t_sid in matched_truth: continue diff --git a/scripts/validation.py b/scripts/validation.py index 1b7b2688..9a6a5967 100644 --- a/scripts/validation.py +++ b/scripts/validation.py @@ -23,7 +23,7 @@ from nativemode import SIZE_AND_ANY_HASH, digest_algorithm, hash_mismatch_exclud from ziptools import check_inside_zip # Validation types that require console-specific cryptographic keys. -# verify.py cannot reproduce these -size checks still apply if combined. +# verify.py cannot reproduce these: size checks still apply if combined. _CRYPTO_CHECKS = frozenset({"signature", "crypto"}) @@ -216,7 +216,7 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]: index[fname]["max_size"] = ( max(cur, f["max_size"]) if cur is not None else f["max_size"] ) - # Hash checks -collect all accepted hashes as sets (multiple valid + # Hash checks: collect all accepted hashes as sets (multiple valid # versions of the same file, e.g. MT-32 ROM versions) if "crc32" in checks and f.get("crc32"): crc_val = f["crc32"] @@ -235,7 +235,7 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]: for h in values: if str(h).strip(): index[fname][hash_type].add(str(h).strip().lower()) - # Adler32 -stored as known_hash_adler32 field (not in validation: list + # Adler32: stored as known_hash_adler32 field (not in validation: list # for Dolphin, but support it in both forms for future profiles) adler_val = f.get("known_hash_adler32") or f.get("adler32") for value in adler_val if isinstance(adler_val, list) else [adler_val] if adler_val else []: @@ -370,7 +370,7 @@ def check_file_validation( checks = entry["checks"] pe = entry.get("per_emulator", {}) - # Size checks -sizes is a set of accepted values + # Size checks: sizes is a set of accepted values if "size" in checks: actual_size = os.path.getsize(local_path) if entry["sizes"] and actual_size not in entry["sizes"]: @@ -384,7 +384,7 @@ def check_file_validation( emus = _emulators_for_check("size", pe) return f"size too large: max {entry['max_size']}, got {actual_size}", emus - # Hash checks -compute once, reuse for all hash types. + # Hash checks: compute once, reuse for all hash types. # Each hash field is a set of accepted values (multiple valid ROM versions). need_hashes = any( h in checks and entry.get(h) for h in ("crc32", "md5", "sha1", "sha256") diff --git a/scripts/verify.py b/scripts/verify.py index 569d1655..f7fcbb9a 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -109,7 +109,7 @@ _REPO_PLATFORMS = os.path.join(os.path.dirname(__file__), "..", "platforms") DEFAULT_EMULATORS_DIR = "emulators" -# Status model -aligned with Batocera BiosStatus (batocera-systems:967-969) +# Status model: aligned with Batocera BiosStatus (batocera-systems:967-969) class Status: @@ -420,8 +420,8 @@ def _candidate_verdict( """Whether a profile entry can be a gap, and whether it is settled. Three answers. "keep" means it is a candidate. "settled" means something - has answered for it -the platform declares it, or the profile documents - it as unsourceable -so the same requirement reached from another profile + has answered for it (the platform declares it, or the profile documents + it as unsourceable), so the same requirement reached from another profile must not be reconsidered. "skip" means it does not apply in this context, which leaves it open for a profile where it does: the same file can be libretro-only here and standalone-only there. @@ -735,7 +735,7 @@ def find_exclusion_notes( ) continue - # Count standalone-only files -but only report as excluded if the + # Count standalone-only files, but only report as excluded if the # platform does NOT use this emulator in standalone mode standalone_set = platform_standalone_set(config) is_standalone = runs_standalone(emu_name, profile, standalone_set) diff --git a/tests/test_deterministic_zip.py b/tests/test_deterministic_zip.py index 2d5659fa..24ef3c0b 100644 --- a/tests/test_deterministic_zip.py +++ b/tests/test_deterministic_zip.py @@ -171,7 +171,7 @@ class TestPackDeterminism(unittest.TestCase): sha1 = hashlib.sha1(payload).hexdigest() # A romset goes through the deterministic rebuild, which stages the # archive in a temporary file. Copying that file into the pack took - # its mtime -the wall clock -so 348 members of the real Recalbox + # its mtime, the wall clock, so 348 members of the real Recalbox # pack moved between two builds while every byte matched. Without a # romset here the fixture never reaches that path. romset = self.bios / "romset.zip" diff --git a/tests/test_e2e.py b/tests/test_e2e.py index 3a7472a2..a0a26a47 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -574,7 +574,7 @@ class TestE2E(unittest.TestCase): "type": "libretro", "systems": ["console-a", "sys-md5"], "files": [ - # Size validation -correct size (16 bytes = len(b"PRESENT_REQUIRED")) + # Size validation: correct size (16 bytes = len(b"PRESENT_REQUIRED")) { "name": "present_req.bin", "required": True, @@ -582,14 +582,14 @@ class TestE2E(unittest.TestCase): "size": 16, "source_ref": "test.c:10-20", }, - # Size validation -wrong expected size + # Size validation: wrong expected size { "name": "present_opt.bin", "required": False, "validation": ["size"], "size": 9999, }, - # CRC32 validation -correct crc32 + # CRC32 validation: correct crc32 { "name": "correct_hash.bin", "required": True, @@ -597,7 +597,7 @@ class TestE2E(unittest.TestCase): "crc32": "91d0b1d3", "source_ref": "hash.c:42", }, - # CRC32 validation -wrong crc32 + # CRC32 validation: wrong crc32 { "name": "no_md5.bin", "required": False, @@ -611,28 +611,28 @@ class TestE2E(unittest.TestCase): "validation": ["crc32"], "crc32": "0179e92e", }, - # MD5 validation -correct md5 + # MD5 validation: correct md5 { "name": "correct_hash.bin", "required": True, "validation": ["md5"], "md5": "4a8db431e3b1a1acacec60e3424c4ce8", }, - # SHA1 validation -correct sha1 + # SHA1 validation: correct sha1 { "name": "correct_hash.bin", "required": True, "validation": ["sha1"], "sha1": "a2ab6c95c5bbd191b9e87e8f4e85205a47be5764", }, - # MD5 validation -wrong md5 + # MD5 validation: wrong md5 { "name": "alias_target.bin", "required": False, "validation": ["md5"], "md5": "0000000000000000000000000000dead", }, - # Adler32 -known_hash_adler32 field + # Adler32: known_hash_adler32 field { "name": "present_req.bin", "required": True, @@ -646,7 +646,7 @@ class TestE2E(unittest.TestCase): "min_size": 10, "max_size": 100, }, - # Signature -crypto check we can't reproduce, but size applies + # Signature: crypto check we can't reproduce, but size applies { "name": "correct_hash.bin", "required": True, @@ -747,7 +747,7 @@ class TestE2E(unittest.TestCase): yaml.dump(emu_mixed_agnostic, fh) # --------------------------------------------------------------- - # THE TEST -one method per feature area, all using same fixtures + # THE TEST: one method per feature area, all using same fixtures # --------------------------------------------------------------- def test_01_resolve_sha1(self): @@ -999,7 +999,7 @@ class TestE2E(unittest.TestCase): config, self.emulators_dir, self.db, profiles ) names = {u["name"] for u in undeclared} - # dd_covered.bin is a file entry, not data_dir content -still undeclared + # dd_covered.bin is a file entry, not data_dir content: still undeclared self.assertIn("dd_covered.bin", names) def test_44_cross_ref_skips_launchers(self): @@ -2197,7 +2197,7 @@ class TestE2E(unittest.TestCase): config = load_platform_config("test_existence", self.platforms_dir) profiles = load_emulator_profiles(self.emulators_dir) result = verify_platform(config, self.db, self.emulators_dir, profiles) - # Simulate --json filtering (non-OK only) -ground_truth must survive + # Simulate --json filtering (non-OK only): ground_truth must survive filtered = [d for d in result["details"] if d["status"] != Status.OK] for d in filtered: self.assertIn("ground_truth", d) diff --git a/tests/test_native_mode.py b/tests/test_native_mode.py index 657ea1b5..fa7aac4e 100644 --- a/tests/test_native_mode.py +++ b/tests/test_native_mode.py @@ -260,7 +260,7 @@ class CandidateVerdict(unittest.TestCase): """Whether a profile entry can be a gap, and whether it is settled. The filter chain mixed two kinds of skip. A settled entry is answered for - -the platform declares it, the profile calls it unsourceable -so the same + (the platform declares it, the profile calls it unsourceable), so the same requirement reached from another profile must not be reconsidered. A skipped one merely does not apply here: the same file can be libretro-only in one profile and standalone-only in another, and recording it from the diff --git a/tests/test_prose_style.py b/tests/test_prose_style.py index 0b0b7f2c..e59c4d22 100644 --- a/tests/test_prose_style.py +++ b/tests/test_prose_style.py @@ -238,6 +238,24 @@ class NoClauseSemicolons(unittest.TestCase): self._check(files, _python_prose) + def test_python_prose_has_no_lone_dash_asides(self): + """Removing " -- " asides left 72 comments reading "shape -a size or + a size range -is all": half a dash glued to the next word. A command + line flag quoted in prose (MAME's -listxml) is not an aside, and a + quotation is left alone.""" + lone = re.compile(r"[A-Za-z0-9,)] -(?!listxml\b|lr\b|sa\b)[a-z]{2,}") + offenders = [ + f"{path.relative_to(ROOT)}: {line.strip()[:100]}" + for path in _tracked() if path.suffix == ".py" + for line in re.sub( + r'`[^`]*`|"[^"\n]*\n?[^"\n]*"', + "", + _python_prose(path.read_text(encoding="utf-8")).replace('"""', ""), + ).splitlines() + if lone.search(line) and not re.search(r"\b(python|curl|unittest|sh)\b .* -", line) + ] + self.assertEqual(offenders, [], "\n".join(offenders[:40])) + def test_schema_descriptions(self): offenders = [] for path in sorted((ROOT / "schemas").glob("*.json")): diff --git a/wiki/adding-a-platform.md b/wiki/adding-a-platform.md index 269ac7dc..bfc78961 100644 --- a/wiki/adding-a-platform.md +++ b/wiki/adding-a-platform.md @@ -286,8 +286,8 @@ diff .cache/upstream-native/myplatform/ \ ``` The export must not lose anything the platform already declares. If your -format carries code as well as data - a script, a C# database, a manifest -whose BIOS list sits beside launch configuration - say so with +format carries code as well as data (a script, a C# database, a manifest +whose BIOS list sits beside launch configuration), say so with `needs_original()` and patch their file rather than writing a new one. An exporter that regenerates such a file from BIOS data alone hands the maintainer something that no longer runs.