Update deprecated type hints

This commit is contained in:
Robin Avery 2024-09-23 08:43:05 -04:00
parent 2f94ccb062
commit 64475523f0
No known key found for this signature in database
GPG Key ID: 633B2D5AB640375C
3 changed files with 80 additions and 81 deletions

View File

@ -15,7 +15,7 @@
import argparse import argparse
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List from typing import Any
from tools.project import ( from tools.project import (
Object, Object,
@ -218,7 +218,7 @@ config.linker_version = "GC/1.3.2"
# Helper function for Dolphin libraries # Helper function for Dolphin libraries
def DolphinLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: def DolphinLib(lib_name: str, objects: list[Object]) -> dict[str, Any]:
return { return {
"lib": lib_name, "lib": lib_name,
"mw_version": "GC/1.2.5n", "mw_version": "GC/1.2.5n",
@ -229,7 +229,7 @@ def DolphinLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]:
# Helper function for REL script objects # Helper function for REL script objects
def Rel(lib_name: str, objects: List[Object]) -> Dict[str, Any]: def Rel(lib_name: str, objects: list[Object]) -> dict[str, Any]:
return { return {
"lib": lib_name, "lib": lib_name,
"mw_version": "GC/1.3.2", "mw_version": "GC/1.3.2",
@ -250,7 +250,7 @@ config.libs = [
"lib": "Runtime.PPCEABI.H", "lib": "Runtime.PPCEABI.H",
"mw_version": config.linker_version, "mw_version": config.linker_version,
"cflags": cflags_runtime, "cflags": cflags_runtime,
"progress_category": "sdk", # str | List[str] "progress_category": "sdk", # str | list[str]
"objects": [ "objects": [
Object(NonMatching, "Runtime.PPCEABI.H/global_destructor_chain.c"), Object(NonMatching, "Runtime.PPCEABI.H/global_destructor_chain.c"),
Object(NonMatching, "Runtime.PPCEABI.H/__init_cpp_exceptions.cpp"), Object(NonMatching, "Runtime.PPCEABI.H/__init_cpp_exceptions.cpp"),

View File

@ -55,6 +55,7 @@ def dtk_url(tag: str) -> str:
repo = "https://github.com/encounter/decomp-toolkit" repo = "https://github.com/encounter/decomp-toolkit"
return f"{repo}/releases/download/{tag}/dtk-{system}-{arch}{suffix}" return f"{repo}/releases/download/{tag}/dtk-{system}-{arch}{suffix}"
def objdiff_cli_url(tag: str) -> str: def objdiff_cli_url(tag: str) -> str:
uname = platform.uname() uname = platform.uname()
suffix = "" suffix = ""

View File

@ -17,26 +17,26 @@ import os
import platform import platform
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast from typing import Any, cast
from . import ninja_syntax from . import ninja_syntax
from .ninja_syntax import serialize_path from .ninja_syntax import serialize_path
if sys.platform == "cygwin": if sys.platform == "cygwin":
sys.exit( sys.exit(
f"Cygwin/MSYS2 is not supported." "Cygwin/MSYS2 is not supported."
f"\nPlease use native Windows Python instead." + f"\nPlease use native Windows Python instead."
f"\n(Current path: {sys.executable})" + f"\n(Current path: {sys.executable})"
) )
Library = Dict[str, Any] Library = dict[str, Any]
class Object: class Object:
def __init__(self, completed: bool, name: str, **options: Any) -> None: def __init__(self, completed: bool, name: str, **options: Any) -> None:
self.name = name self.name = name
self.completed = completed self.completed = completed
self.options: Dict[str, Any] = { self.options: dict[str, Any] = {
"add_to_all": None, "add_to_all": None,
"asflags": None, "asflags": None,
"asm_dir": None, "asm_dir": None,
@ -54,12 +54,12 @@ class Object:
self.options.update(options) self.options.update(options)
# Internal # Internal
self.src_path: Optional[Path] = None self.src_path: Path | None = None
self.asm_path: Optional[Path] = None self.asm_path: Path | None = None
self.src_obj_path: Optional[Path] = None self.src_obj_path: Path | None = None
self.asm_obj_path: Optional[Path] = None self.asm_obj_path: Path | None = None
self.host_obj_path: Optional[Path] = None self.host_obj_path: Path | None = None
self.ctx_path: Optional[Path] = None self.ctx_path: Path | None = None
def resolve(self, config: "ProjectConfig", lib: Library) -> "Object": def resolve(self, config: "ProjectConfig", lib: Library) -> "Object":
# Use object options, then library options # Use object options, then library options
@ -108,51 +108,49 @@ class ProjectConfig:
self.build_dir: Path = Path("build") # Output build files self.build_dir: Path = Path("build") # Output build files
self.src_dir: Path = Path("src") # C/C++/asm source files self.src_dir: Path = Path("src") # C/C++/asm source files
self.tools_dir: Path = Path("tools") # Python scripts self.tools_dir: Path = Path("tools") # Python scripts
self.asm_dir: Optional[Path] = Path( self.asm_dir: Path | None = Path(
"asm" "asm"
) # Override incomplete objects (for modding) ) # Override incomplete objects (for modding)
# Tooling # Tooling
self.binutils_tag: Optional[str] = None # Git tag self.binutils_tag: str | None = None # Git tag
self.binutils_path: Optional[Path] = None # If None, download self.binutils_path: Path | None = None # If None, download
self.dtk_tag: Optional[str] = None # Git tag self.dtk_tag: str | None = None # Git tag
self.dtk_path: Optional[Path] = None # If None, download self.dtk_path: Path | None = None # If None, download
self.compilers_tag: Optional[str] = None # 1 self.compilers_tag: str | None = None # 1
self.compilers_path: Optional[Path] = None # If None, download self.compilers_path: Path | None = None # If None, download
self.wibo_tag: Optional[str] = None # Git tag self.wibo_tag: str | None = None # Git tag
self.wrapper: Optional[Path] = None # If None, download wibo on Linux self.wrapper: Path | None = None # If None, download wibo on Linux
self.sjiswrap_tag: Optional[str] = None # Git tag self.sjiswrap_tag: str | None = None # Git tag
self.sjiswrap_path: Optional[Path] = None # If None, download self.sjiswrap_path: Path | None = None # If None, download
self.objdiff_tag: Optional[str] = None # Git tag self.objdiff_tag: str | None = None # Git tag
self.objdiff_path: Optional[Path] = None # If None, download self.objdiff_path: Path | None = None # If None, download
# Project config # Project config
self.non_matching: bool = False self.non_matching: bool = False
self.build_rels: bool = True # Build REL files self.build_rels: bool = True # Build REL files
self.check_sha_path: Optional[Path] = None # Path to version.sha1 self.check_sha_path: Path | None = None # Path to version.sha1
self.config_path: Optional[Path] = None # Path to config.yml self.config_path: Path | None = None # Path to config.yml
self.generate_map: bool = False # Generate map file(s) self.generate_map: bool = False # Generate map file(s)
self.asflags: Optional[List[str]] = None # Assembler flags self.asflags: list[str | None] = None # Assembler flags
self.ldflags: Optional[List[str]] = None # Linker flags self.ldflags: list[str | None] = None # Linker flags
self.libs: Optional[List[Library]] = None # List of libraries self.libs: list[Library | None] = None # list of libraries
self.linker_version: Optional[str] = None # mwld version self.linker_version: str | None = None # mwld version
self.version: Optional[str] = None # Version name self.version: str | None = None # Version name
self.warn_missing_config: bool = False # Warn on missing unit configuration self.warn_missing_config: bool = False # Warn on missing unit configuration
self.warn_missing_source: bool = False # Warn on missing source file self.warn_missing_source: bool = False # Warn on missing source file
self.rel_strip_partial: bool = True # Generate PLFs with -strip_partial self.rel_strip_partial: bool = True # Generate PLFs with -strip_partial
self.rel_empty_file: Optional[str] = ( self.rel_empty_file: str | None = None # Object name for generating empty RELs
None # Object name for generating empty RELs
)
self.shift_jis = ( self.shift_jis = (
True # Convert source files from UTF-8 to Shift JIS automatically True # Convert source files from UTF-8 to Shift JIS automatically
) )
self.reconfig_deps: Optional[List[Path]] = ( self.reconfig_deps: list[Path | None] = (
None # Additional re-configuration dependency files None # Additional re-configuration dependency files
) )
self.custom_build_rules: Optional[List[Dict[str, Any]]] = ( self.custom_build_rules: list[dict[str, Any | None]] = (
None # Custom ninja build rules None # Custom ninja build rules
) )
self.custom_build_steps: Optional[Dict[str, List[Dict[str, Any]]]] = ( self.custom_build_steps: dict[str, list[dict[str, Any | None]]] = (
None # Custom build steps, types are ["pre-compile", "post-compile", "post-link", "post-build"] None # Custom build steps, types are ["pre-compile", "post-compile", "post-link", "post-build"]
) )
@ -162,7 +160,7 @@ class ProjectConfig:
self.progress_each_module: bool = ( self.progress_each_module: bool = (
False # Include individual modules, disable for large numbers of modules False # Include individual modules, disable for large numbers of modules
) )
self.progress_categories: List[ProgressCategory] = [] # Additional categories self.progress_categories: list[ProgressCategory] = [] # Additional categories
# Progress fancy printing # Progress fancy printing
self.progress_use_fancy: bool = False self.progress_use_fancy: bool = False
@ -189,10 +187,10 @@ class ProjectConfig:
# Creates a map of object names to Object instances # Creates a map of object names to Object instances
# Options are fully resolved from the library and object # Options are fully resolved from the library and object
def objects(self) -> Dict[str, Object]: def objects(self) -> dict[str, Object]:
out = {} out = {}
for lib in self.libs or {}: for lib in self.libs or {}:
objects: List[Object] = lib["objects"] objects: list[Object] = lib["objects"]
for obj in objects: for obj in objects:
if obj.name in out: if obj.name in out:
sys.exit(f"Duplicate object name {obj.name}") sys.exit(f"Duplicate object name {obj.name}")
@ -213,7 +211,7 @@ CHAIN = "cmd /c " if is_windows() else ""
EXE = ".exe" if is_windows() else "" EXE = ".exe" if is_windows() else ""
def make_flags_str(flags: Optional[Union[str, List[str]]]) -> str: def make_flags_str(flags: str | list[str] | None) -> str:
if flags is None: if flags is None:
return "" return ""
elif isinstance(flags, list): elif isinstance(flags, list):
@ -225,7 +223,7 @@ def make_flags_str(flags: Optional[Union[str, List[str]]]) -> str:
# Load decomp-toolkit generated config.json # Load decomp-toolkit generated config.json
def load_build_config( def load_build_config(
config: ProjectConfig, build_config_path: Path config: ProjectConfig, build_config_path: Path
) -> Optional[Dict[str, Any]]: ) -> dict[str, Any | None]:
if not build_config_path.is_file(): if not build_config_path.is_file():
return None return None
@ -233,7 +231,7 @@ def load_build_config(
return tuple(map(int, (v.split(".")))) return tuple(map(int, (v.split("."))))
f = open(build_config_path, "r", encoding="utf-8") f = open(build_config_path, "r", encoding="utf-8")
build_config: Dict[str, Any] = json.load(f) build_config: dict[str, Any] = json.load(f)
config_version = build_config.get("version") config_version = build_config.get("version")
if config_version is None: if config_version is None:
print("Invalid config.json, regenerating...") print("Invalid config.json, regenerating...")
@ -264,8 +262,8 @@ def generate_build(config: ProjectConfig) -> None:
# Generate build.ninja # Generate build.ninja
def generate_build_ninja( def generate_build_ninja(
config: ProjectConfig, config: ProjectConfig,
objects: Dict[str, Object], objects: dict[str, Object],
build_config: Optional[Dict[str, Any]], build_config: dict[str, Any | None],
) -> None: ) -> None:
out = io.StringIO() out = io.StringIO()
n = ninja_syntax.Writer(out) n = ninja_syntax.Writer(out)
@ -407,7 +405,7 @@ def generate_build_ninja(
# Only add an implicit dependency on wibo if we download it # Only add an implicit dependency on wibo if we download it
wrapper = config.wrapper wrapper = config.wrapper
wrapper_implicit: Optional[Path] = None wrapper_implicit: Path | None = None
if ( if (
config.wibo_tag is not None config.wibo_tag is not None
and sys.platform == "linux" and sys.platform == "linux"
@ -429,7 +427,7 @@ def generate_build_ninja(
wrapper = Path("wine") wrapper = Path("wine")
wrapper_cmd = f"{wrapper} " if wrapper else "" wrapper_cmd = f"{wrapper} " if wrapper else ""
compilers_implicit: Optional[Path] = None compilers_implicit: Path | None = None
if config.compilers_path: if config.compilers_path:
compilers = config.compilers_path compilers = config.compilers_path
elif config.compilers_tag: elif config.compilers_tag:
@ -486,16 +484,16 @@ def generate_build_ninja(
# MWCC # MWCC
mwcc = compiler_path / "mwcceppc.exe" mwcc = compiler_path / "mwcceppc.exe"
mwcc_cmd = f"{wrapper_cmd}{mwcc} $cflags -MMD -c $in -o $basedir" mwcc_cmd = f"{wrapper_cmd}{mwcc} $cflags -MMD -c $in -o $basedir"
mwcc_implicit: List[Optional[Path]] = [compilers_implicit or mwcc, wrapper_implicit] mwcc_implicit: list[Path | None] = [compilers_implicit or mwcc, wrapper_implicit]
# MWCC with UTF-8 to Shift JIS wrapper # MWCC with UTF-8 to Shift JIS wrapper
mwcc_sjis_cmd = f"{wrapper_cmd}{sjiswrap} {mwcc} $cflags -MMD -c $in -o $basedir" mwcc_sjis_cmd = f"{wrapper_cmd}{sjiswrap} {mwcc} $cflags -MMD -c $in -o $basedir"
mwcc_sjis_implicit: List[Optional[Path]] = [*mwcc_implicit, sjiswrap] mwcc_sjis_implicit: list[Path | None] = [*mwcc_implicit, sjiswrap]
# MWLD # MWLD
mwld = compiler_path / "mwldeppc.exe" mwld = compiler_path / "mwldeppc.exe"
mwld_cmd = f"{wrapper_cmd}{mwld} $ldflags -o $out @$out.rsp" mwld_cmd = f"{wrapper_cmd}{mwld} $ldflags -o $out @$out.rsp"
mwld_implicit: List[Optional[Path]] = [compilers_implicit or mwld, wrapper_implicit] mwld_implicit: list[Path | None] = [compilers_implicit or mwld, wrapper_implicit]
# GNU as # GNU as
gnu_as = binutils / f"powerpc-eabi-as{EXE}" gnu_as = binutils / f"powerpc-eabi-as{EXE}"
@ -577,12 +575,12 @@ def generate_build_ninja(
) )
n.newline() n.newline()
def write_custom_step(step: str) -> List[str | Path]: def write_custom_step(step: str) -> list[str | Path]:
implicit: List[str | Path] = [] implicit: list[str | Path] = []
if config.custom_build_steps and step in config.custom_build_steps: if config.custom_build_steps and step in config.custom_build_steps:
n.comment(f"Custom build steps ({step})") n.comment(f"Custom build steps ({step})")
for custom_step in config.custom_build_steps[step]: for custom_step in config.custom_build_steps[step]:
outputs = cast(List[str | Path], custom_step.get("outputs")) outputs = cast(list[str | Path], custom_step.get("outputs"))
if isinstance(outputs, list): if isinstance(outputs, list):
implicit.extend(outputs) implicit.extend(outputs)
@ -633,12 +631,12 @@ def generate_build_ninja(
return path.parent / (path.name + ".MAP") return path.parent / (path.name + ".MAP")
class LinkStep: class LinkStep:
def __init__(self, config: Dict[str, Any]) -> None: def __init__(self, config: dict[str, Any]) -> None:
self.name: str = config["name"] self.name: str = config["name"]
self.module_id: int = config["module_id"] self.module_id: int = config["module_id"]
self.ldscript: Optional[Path] = Path(config["ldscript"]) self.ldscript: Path | None = Path(config["ldscript"])
self.entry = config["entry"] self.entry = config["entry"]
self.inputs: List[str] = [] self.inputs: list[str] = []
def add(self, obj: Path) -> None: def add(self, obj: Path) -> None:
self.inputs.append(serialize_path(obj)) self.inputs.append(serialize_path(obj))
@ -715,15 +713,15 @@ def generate_build_ninja(
) )
n.newline() n.newline()
link_outputs: List[Path] = [] link_outputs: list[Path] = []
if build_config: if build_config:
link_steps: List[LinkStep] = [] link_steps: list[LinkStep] = []
used_compiler_versions: Set[str] = set() used_compiler_versions: Set[str] = set()
source_inputs: List[Path] = [] source_inputs: list[Path] = []
host_source_inputs: List[Path] = [] host_source_inputs: list[Path] = []
source_added: Set[Path] = set() source_added: Set[Path] = set()
def c_build(obj: Object, src_path: Path) -> Optional[Path]: def c_build(obj: Object, src_path: Path) -> Path | None:
cflags_str = make_flags_str(obj.options["cflags"]) cflags_str = make_flags_str(obj.options["cflags"])
if obj.options["extra_cflags"] is not None: if obj.options["extra_cflags"] is not None:
extra_cflags_str = make_flags_str(obj.options["extra_cflags"]) extra_cflags_str = make_flags_str(obj.options["extra_cflags"])
@ -783,8 +781,8 @@ def generate_build_ninja(
return obj.src_obj_path return obj.src_obj_path
def asm_build( def asm_build(
obj: Object, src_path: Path, obj_path: Optional[Path] obj: Object, src_path: Path, obj_path: Path | None
) -> Optional[Path]: ) -> Path | None:
if obj.options["asflags"] is None: if obj.options["asflags"] is None:
sys.exit("ProjectConfig.asflags missing") sys.exit("ProjectConfig.asflags missing")
asflags_str = make_flags_str(obj.options["asflags"]) asflags_str = make_flags_str(obj.options["asflags"])
@ -824,7 +822,7 @@ def generate_build_ninja(
return return
link_built_obj = obj.completed link_built_obj = obj.completed
built_obj_path: Optional[Path] = None built_obj_path: Path | None = None
if obj.src_path is not None and obj.src_path.exists(): if obj.src_path is not None and obj.src_path.exists():
if obj.src_path.suffix in (".c", ".cp", ".cpp"): if obj.src_path.suffix in (".c", ".cp", ".cpp"):
# Add MWCC & host build rules # Add MWCC & host build rules
@ -932,7 +930,7 @@ def generate_build_ninja(
rspfile="$rspfile", rspfile="$rspfile",
rspfile_content="$in_newline", rspfile_content="$in_newline",
) )
generated_rels: List[str] = [] generated_rels: list[str] = []
for idx, link in enumerate(build_config["links"]): for idx, link in enumerate(build_config["links"]):
# Map module names to link steps # Map module names to link steps
link_steps_local = list( link_steps_local = list(
@ -1048,7 +1046,7 @@ def generate_build_ninja(
command=f"{objdiff} report generate -o $out", command=f"{objdiff} report generate -o $out",
description="REPORT", description="REPORT",
) )
report_implicit: List[str | Path] = [objdiff, "all_source"] report_implicit: list[str | Path] = [objdiff, "all_source"]
n.build( n.build(
outputs=report_path, outputs=report_path,
rule="report", rule="report",
@ -1163,13 +1161,13 @@ def generate_build_ninja(
# Generate objdiff.json # Generate objdiff.json
def generate_objdiff_config( def generate_objdiff_config(
config: ProjectConfig, config: ProjectConfig,
objects: Dict[str, Object], objects: dict[str, Object],
build_config: Optional[Dict[str, Any]], build_config: dict[str, Any | None],
) -> None: ) -> None:
if build_config is None: if build_config is None:
return return
objdiff_config: Dict[str, Any] = { objdiff_config: dict[str, Any] = {
"min_version": "2.0.0-beta.5", "min_version": "2.0.0-beta.5",
"custom_make": "ninja", "custom_make": "ninja",
"build_target": False, "build_target": False,
@ -1222,11 +1220,11 @@ def generate_objdiff_config(
} }
def add_unit( def add_unit(
build_obj: Dict[str, Any], module_name: str, progress_categories: List[str] build_obj: dict[str, Any], module_name: str, progress_categories: list[str]
) -> None: ) -> None:
obj_path, obj_name = build_obj["object"], build_obj["name"] obj_path, obj_name = build_obj["object"], build_obj["name"]
base_object = Path(obj_name).with_suffix("") base_object = Path(obj_name).with_suffix("")
unit_config: Dict[str, Any] = { unit_config: dict[str, Any] = {
"name": Path(module_name) / base_object, "name": Path(module_name) / base_object,
"target_path": obj_path, "target_path": obj_path,
"metadata": { "metadata": {
@ -1291,7 +1289,7 @@ def generate_objdiff_config(
"build_ctx": True, "build_ctx": True,
} }
) )
category_opt: List[str] | str = obj.options["progress_category"] category_opt: list[str] | str = obj.options["progress_category"]
if isinstance(category_opt, list): if isinstance(category_opt, list):
progress_categories.extend(category_opt) progress_categories.extend(category_opt)
elif category_opt is not None: elif category_opt is not None:
@ -1372,7 +1370,7 @@ def calculate_progress(config: ProjectConfig) -> None:
self.objects: Set[Object] = set() self.objects: Set[Object] = set()
self.objects_progress: int = 0 self.objects_progress: int = 0
def add(self, build_obj: Dict[str, Any]) -> None: def add(self, build_obj: dict[str, Any]) -> None:
self.code_total += build_obj["code_size"] self.code_total += build_obj["code_size"]
self.data_total += build_obj["data_size"] self.data_total += build_obj["data_size"]
@ -1404,7 +1402,7 @@ def calculate_progress(config: ProjectConfig) -> None:
return 1.0 return 1.0
return self.data_progress / self.data_total return self.data_progress / self.data_total
progress_units: Dict[str, ProgressUnit] = {} progress_units: dict[str, ProgressUnit] = {}
if config.progress_all: if config.progress_all:
progress_units["all"] = ProgressUnit("All") progress_units["all"] = ProgressUnit("All")
progress_units["dol"] = ProgressUnit("DOL") progress_units["dol"] = ProgressUnit("DOL")
@ -1418,7 +1416,7 @@ def calculate_progress(config: ProjectConfig) -> None:
for module in build_config["modules"]: for module in build_config["modules"]:
progress_units[module["name"]] = ProgressUnit(module["name"]) progress_units[module["name"]] = ProgressUnit(module["name"])
def add_unit(id: str, unit: Dict[str, Any]) -> None: def add_unit(id: str, unit: dict[str, Any]) -> None:
progress = progress_units.get(id) progress = progress_units.get(id)
if progress is not None: if progress is not None:
progress.add(unit) progress.add(unit)
@ -1485,7 +1483,7 @@ def calculate_progress(config: ProjectConfig) -> None:
) )
# Generate and write progress.json # Generate and write progress.json
progress_json: Dict[str, Any] = {} progress_json: dict[str, Any] = {}
for id, unit in progress_units.items(): for id, unit in progress_units.items():
if len(unit.objects) == 0: if len(unit.objects) == 0:
continue continue