From 076d13a7c2a3b5f8191ba12c0086b155fe04ac39 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Tue, 4 May 2021 21:16:05 -0400 Subject: [PATCH] lint: Address Codacy linter findings --- .../validation/lint-gamedb/lint-gamedb.py | 177 +++++++++--------- pcsx2/Docs/GameIndex.md | 111 +++++------ 2 files changed, 147 insertions(+), 141 deletions(-) diff --git a/.github/workflows/scripts/validation/lint-gamedb/lint-gamedb.py b/.github/workflows/scripts/validation/lint-gamedb/lint-gamedb.py index 901ce142d4..9e11992ab3 100644 --- a/.github/workflows/scripts/validation/lint-gamedb/lint-gamedb.py +++ b/.github/workflows/scripts/validation/lint-gamedb/lint-gamedb.py @@ -48,17 +48,17 @@ def is_hex_number(string): try: int(string, 16) return True - except: + except Exception: return False def validate_string_option(serial, key, value): - if type(value) != str: + if not isinstance(value, str): issue_list.append("[{}]: '{}' must be a string".format(serial, key)) def validate_int_option(serial, key, value, low, high): - if type(value) != int or (value < low or value > high): + if not isinstance(value, int) or (value < low or value > high): issue_list.append( "[{}]: '{}' must be an int and between {}-{} (inclusive)".format( serial, key, low, high @@ -66,17 +66,100 @@ def validate_int_option(serial, key, value, low, high): ) +def validate_list_of_strings(serial, key, value): + if not isinstance(value, list) or not all(isinstance(item, str) for item in value): + issue_list.append("[{}]: '{}' must be a list of strings".format(serial, key)) + + def validate_valid_options(serial, key, value, allowed_values): if value not in allowed_values: issue_list.append("[{}]: Invalid '{}' option [{}]".format(serial, key, value)) +def validate_clamp_round_modes(serial, key, value, allowed_values): + if not isinstance(value, dict): + issue_list.append("[{}]: '{}' must be a valid object".format(serial, key)) + return + for mode_key, mode_value in value.items(): + validate_valid_options(serial, key, mode_key, allowed_values) + validate_int_option(serial, key, mode_value, 0, 3) + + +def validate_game_fixes(serial, key, value): + if not isinstance(value, list): + issue_list.append( + "[{}]: 'gameFixes' must be a list of valid gameFixes".format(serial) + ) + return + for gamefix in value: + validate_valid_options(serial, key, gamefix, allowed_game_fixes) + + +def validate_speed_hacks(serial, key, value): + if not isinstance(value, dict): + issue_list.append("[{}]: 'speedHacks' must be a valid object".format(serial)) + return + for speedhack, speedhack_value in value.items(): + validate_valid_options(serial, key, speedhack, allowed_speed_hacks) + validate_int_option(serial, speedhack, speedhack_value, 0, 1) + + +def validate_patches(serial, key, value): + if not isinstance(value, dict): + issue_list.append( + "[{}]: 'patches' must be valid mapping of CRC32 -> Patch Objects".format( + serial + ) + ) + return + for crc, patch in value.items(): + if crc != "default" and not is_hex_number(str(crc)): + issue_list.append( + "[{}]: Patches must either be key'd with 'default' or a valid CRC-32 Hex String".format( + serial + ) + ) + continue + for patch_option, option_value in patch.items(): + validate_valid_options(serial, key, patch_option, allowed_patch_options) + if patch_option == "author": + validate_string_option(serial, patch_option, option_value) + if patch_option == "content": + validate_string_option(serial, patch_option, option_value) + + +# pylint:disable=unnecessary-lambda +option_validation_handlers = { + "name": (lambda serial, key, value: validate_string_option(serial, key, value)), + "region": (lambda serial, key, value: validate_string_option(serial, key, value)), + "compat": ( + lambda serial, key, value: validate_int_option(serial, key, value, 0, 6) + ), + "roundModes": ( + lambda serial, key, value: validate_clamp_round_modes( + serial, key, value, allowed_round_modes + ) + ), + "clampModes": ( + lambda serial, key, value: validate_clamp_round_modes( + serial, key, value, allowed_clamp_modes + ) + ), + "gameFixes": (lambda serial, key, value: validate_game_fixes(serial, key, value)), + "speedHacks": (lambda serial, key, value: validate_speed_hacks(serial, key, value)), + "memcardFilters": ( + lambda serial, key, value: validate_list_of_strings(serial, key, value) + ), + "patches": (lambda serial, key, value: validate_patches(serial, key, value)), +} + print("Opening {}...".format(file_path)) with open(file_path) as f: try: print("Attempting to parse GameDB file...") gamedb = yaml.load(f, Loader=yaml.FullLoader) except Exception as err: + print(err) print( "Unable to parse GameDB. Exiting, verify that the file indeed is valid YAML." ) @@ -99,94 +182,14 @@ with open(file_path) as f: if not "region" in game_options.keys(): issue_list.append("[{}]: 'region' is a required value".format(serial)) + # Check the options for key, value in game_options.items(): if key not in allowed_game_options: issue_list.append("[{}]: Invalid option [{}]".format(serial, key)) + continue - # SIMPLE METADATA VALIDATION - if key in ["name", "region"]: - validate_string_option(serial, key, value) - - if key == "compat": - validate_int_option(serial, key, value, 0, 6) - - # ROUND MODE VALIDATION - if key == "roundModes" and type(value) == dict: - for roundMode, roundValue in game_options["roundModes"].items(): - validate_valid_options(serial, key, roundMode, allowed_round_modes) - validate_int_option(serial, key, roundValue, 0, 3) - elif key == "roundModes": - issue_list.append( - "[{}]: 'roundModes' must be a valid object".format(serial) - ) - - # CLAMP MODE VALIDATION - if key == "clampModes" and type(value) == dict: - for clampMode, clampValue in game_options["clampModes"].items(): - validate_valid_options(serial, key, clampMode, allowed_clamp_modes) - validate_int_option(serial, key, clampValue, 0, 3) - elif key == "clampModes": - issue_list.append( - "[{}]: 'clampModes' must be a valid object".format(serial) - ) - - # GAME FIX VALIDATION - if key == "gameFixes" and type(value) == list: - for gamefix in game_options["gameFixes"]: - validate_valid_options(serial, key, gamefix, allowed_game_fixes) - elif key == "gameFixes": - issue_list.append( - "[{}]: 'gameFixes' must be a list of valid gameFixes".format(serial) - ) - - # SPEEDHACKS VALIDATION - if key == "speedHacks" and type(value) == dict: - for speedhack, speedhackValue in game_options["speedHacks"].items(): - validate_valid_options(serial, key, speedhack, allowed_speed_hacks) - validate_int_option(serial, speedhack, speedhackValue, 0, 1) - elif key == "speedHacks": - issue_list.append( - "[{}]: 'speedHacks' must be a valid object".format(serial) - ) - - # MEM CARD VALIDAITON - if key == "memcardFilters" and not all( - isinstance(memcardFilter, str) for memcardFilter in value - ): - issue_list.append( - "[{}]: 'memcardFilters' must be a list of strings".format(serial) - ) - - # PATCH VALIDATION - if key == "patches" and type(value) == dict: - for crc, patch in game_options["patches"].items(): - if crc != "default" and not is_hex_number(str(crc)): - issue_list.append( - "[{}]: Patches must either be key'd with 'default' or a valid CRC-32 Hex String".format( - serial - ) - ) - continue - for patchOption, optionValue in patch.items(): - validate_valid_options( - serial, key, patchOption, allowed_patch_options - ) - if key == "author": - validate_string_option(serial, patchOption, optionValue) - if key == "content" and not all( - isinstance(patchLine, str) for patchLine in optionValue - ): - issue_list.append( - "[{}]: Patch 'content' must be a list of strings".format( - serial - ) - ) - elif key == "patches": - issue_list.append( - "[{}]: 'patches' must be valid mapping of CRC32 -> Patch Objects".format( - serial - ) - ) + if key in option_validation_handlers: + option_validation_handlers[key](serial, key, value) if len(issue_list) > 0: print("Issues found during validation:") diff --git a/pcsx2/Docs/GameIndex.md b/pcsx2/Docs/GameIndex.md index f67d4141e4..51c780ec68 100644 --- a/pcsx2/Docs/GameIndex.md +++ b/pcsx2/Docs/GameIndex.md @@ -63,15 +63,16 @@ SERIAL-12345: # !required! Serial number for the game, this is how games are loo patch=1,EE,00000001,word,00000000 ``` -> Note that quoting strings in YAML is optional, but certain characters are reserved like '*' and require the string to be quoted, be aware / use a YAML linter to avoid confusion. +> Note that quoting strings in YAML is optional, but certain characters are reserved like '\*' and require the string to be quoted, be aware / use a YAML linter to avoid confusion. ## A Note on Case Sensitivity Both the serial numbers for the games, and the CRC patches are at the moment not case-sensitive and will be looked up with their lowercase representations. **However, stylistically, uppercase is preferred and may be enforced and migrated to in the future**. For example: -- `SLUS-123` will be stored and looked up in the GameDB as `slus-123` -- Likewise, a CRC with upper-case hex `23AF6876` will be stored and looked up as `23af6876` + +* `SLUS-123` will be stored and looked up in the GameDB as `slus-123` +* Likewise, a CRC with upper-case hex `23AF6876` will be stored and looked up as `23af6876` However, YAML is case-sensitive and will allow multiple serials that only differ on casing. To prevent mistakes, this will also throw a validation error and the first entry will be the one that wins. @@ -80,13 +81,14 @@ However, YAML is case-sensitive and will allow multiple serials that only differ ## Compatibility `compat` can be set to the following values: -- `0` = Unknown Compatibility Status -- `1` = Nothing -- `2` = Intro -- `3` = Menu -- `4` = In-game -- `5` = Playable -- `6` = Perfect + +* `0` = Unknown Compatibility Status +* `1` = Nothing +* `2` = Intro +* `3` = Menu +* `4` = In-game +* `5` = Playable +* `6` = Perfect ## Rounding Modes @@ -96,24 +98,25 @@ These modes can be specified either on the **EE** (`eeRoundMode`) or **VU** (`vu ### Options for rounding -- `0` = **Nearest** -- `1` = **Negative Infinity** -- `2` = **Positive Infinity** -- `3` = **Chop (Zero)** -- The is the common default +* `0` = **Nearest** +* `1` = **Negative Infinity** +* `2` = **Positive Infinity** +* `3` = **Chop (Zero)** +* The is the common default ## Clamping Modes The clamp modes are also numerically based. -- `eeClampMode` refers to the EE's FPU co-processor -- `vuClampMode` refers to the VU's and COP2 (VU0 Macro-mode) + +* `eeClampMode` refers to the EE's FPU co-processor +* `vuClampMode` refers to the VU's and COP2 (VU0 Macro-mode) ### Options for clamping -- `0` = **Disables** clamping completely -- `1` = Clamp **Normally** (only clamp results) -- `2` = Clamp **Extra** (clamp results as well as operands) -- `3` = **Full Clamping** for FPU / Extra+Preserve Sign Clamping for VU +* `0` = **Disables** clamping completely +* `1` = Clamp **Normally** (only clamp results) +* `2` = Clamp **Extra** (clamp results as well as operands) +* `3` = **Full Clamping** for FPU / Extra+Preserve Sign Clamping for VU ## Game Fixes @@ -121,53 +124,53 @@ These values are case-sensitive so take care. If you incorrectly specify a Game ### Options for Game Fixes -- `VuAddSubHack` - - Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate. +* `VuAddSubHack` + * Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate. - `FpuMulHack` - Tales of Destiny hangs. -- `FpuNegDivHack` - - Gundam games messed up camera-view. Dakar 2's sky showing over 3D. Others... +* `FpuNegDivHack` + * Gundam games messed up camera-view. Dakar 2's sky showing over 3D. Others... -- `XGKickHack` - - Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace. +* `XGKickHack` + * Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace. -- `IPUWaitHack` - - FFX FMV, makes GIF flush before doing IPU work. Fixes bad graphics overlay. +* `IPUWaitHack` + * FFX FMV, makes GIF flush before doing IPU work. Fixes bad graphics overlay. -- `EETimingHack` - - General purpose timing hack. +* `EETimingHack` + * General purpose timing hack. -- `SkipMPEGHack` - - Finds sceMpegIsEnd pattern in games and then recompiles code to say the videos are finished. +* `SkipMPEGHack` + * Finds sceMpegIsEnd pattern in games and then recompiles code to say the videos are finished. -- `OPHFlagHack` - - Bleach Bankais and others. +* `OPHFlagHack` + * Bleach Bankais and others. -- `DMABusyHack` - - Mana Khemia, Metal Saga. Denies writes to the DMAC when it's busy. +* `DMABusyHack` + * Mana Khemia, Metal Saga. Denies writes to the DMAC when it's busy. -- `VIFFIFOHack` - - Transformers Armada, Test Drive Unlimited. Fixes slow booting issue. +* `VIFFIFOHack` + * Transformers Armada, Test Drive Unlimited. Fixes slow booting issue. -- `VIF1StallHack` - - SOCOM II HUD and Spy Hunter loading hang. +* `VIF1StallHack` + * SOCOM II HUD and Spy Hunter loading hang. -- `GIFFIFOHack` - - Enables the GIF FIFO. Needed for Wallace & Grommit, Hot Wheels, DJ Hero. +* `GIFFIFOHack` + * Enables the GIF FIFO. Needed for Wallace & Grommit, Hot Wheels, DJ Hero. -- `GoemonTlbHack` - - Preload TLB hack to avoid tlb miss on Goemon. +* `GoemonTlbHack` + * Preload TLB hack to avoid tlb miss on Goemon. -- `ScarfaceIbitHack` - - VU I bit Hack avoid constant recompilation (Scarface The World Is Yours). +* `ScarfaceIbitHack` + * VU I bit Hack avoid constant recompilation (Scarface The World Is Yours). -- `CrashTagTeamRacingIbitHack` - - VU I bit Hack avoid constant recompilation (Crash Tag Team Racing). +* `CrashTagTeamRacingIbitHack` + * VU I bit Hack avoid constant recompilation (Crash Tag Team Racing). -- `VU0KickstartHack` - - Let VU0 run ahead to fix some timing issues +* `VU0KickstartHack` + * Let VU0 run ahead to fix some timing issues ## SpeedHacks @@ -175,9 +178,9 @@ These values are in a key-value format, where the value is assumed to be an inte ### Options for SpeedHacks -- `mvuFlagSpeedHack` -- Accepted Values - `0` / `1` -- Katamari Damacy have weird speed bug when this speed hack is enabled (and it is by default) +* `mvuFlagSpeedHack` +* Accepted Values - `0` / `1` +* Katamari Damacy have weird speed bug when this speed hack is enabled (and it is by default)