From 976a3e5060e1d0f6b5617cd64819c32d90c82cac Mon Sep 17 00:00:00 2001 From: Henrique Gemignani Passos Lima Date: Sat, 12 Oct 2024 20:44:47 +0300 Subject: [PATCH 1/2] Test with Python 3.13 --- .github/workflows/python.yml | 5 +++-- pyproject.toml | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 75f87ae5..c5ae5e6b 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -29,7 +29,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: "3.11" + python-version: "3.12" - name: Install Python packages run: python -m pip install --upgrade build @@ -57,7 +57,8 @@ jobs: python: - { version: "3.10" } - { version: "3.11" } - - { version: "3.12.0-beta - 3.12.0" } + - { version: "3.12" } + - { version: "3.13" } steps: - name: Checkout diff --git a/pyproject.toml b/pyproject.toml index dde4591c..fcbd4333 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,8 @@ classifiers = [ "Intended Audience :: Developers", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] requires-python = ">=3.10" dynamic = ["version"] @@ -27,7 +29,6 @@ dependencies = [ "zstandard", ] - [project.readme] file = "README.md" content-type = "text/markdown" @@ -67,7 +68,7 @@ lint.select = ["E", "F", "W", "C90", "I", "UP"] src = ["src"] # Version to target for generated code. -target-version = "py38" +target-version = "py310" [tool.ruff.lint.mccabe] # Flag errors (`C901`) whenever the complexity level exceeds 25. From 7f186174711d0fed3461920cb6e3119577bbe89c Mon Sep 17 00:00:00 2001 From: Henrique Gemignani Passos Lima Date: Sat, 12 Oct 2024 20:51:17 +0300 Subject: [PATCH 2/2] Modernized code --- .../_dread_data_construct.py | 5 ++-- src/mercury_engine_data_structures/cli.py | 3 +-- .../common_types.py | 2 +- .../construct_extensions/enum.py | 7 +++--- .../construct_extensions/function_complex.py | 11 ++++----- src/mercury_engine_data_structures/crc.py | 8 +++---- .../dread_data.py | 15 ++++++------ .../file_tree_editor.py | 24 +++++++++---------- .../formats/__init__.py | 4 +--- .../formats/base_resource.py | 2 +- .../formats/bmmdef.py | 4 +--- .../formats/bmsad.py | 2 +- .../formats/bmsld.py | 4 ++-- .../formats/brfld.py | 6 ++--- .../formats/brsa.py | 2 +- .../formats/property_enum.py | 8 +++---- .../formats/standard_format.py | 11 ++++----- .../formats/toc.py | 4 ++-- .../formats/txt.py | 3 +-- .../game_check.py | 3 ++- src/mercury_engine_data_structures/object.py | 9 +++---- .../pointer_set.py | 11 ++++----- .../samus_returns_data.py | 15 ++++++------ tests/test_lib.py | 9 +++---- tools/ghidra_export.py | 8 +++---- tools/plot_simple_map.py | 12 +++++----- tools/sr_export_rdv_database.py | 6 ++--- 27 files changed, 87 insertions(+), 111 deletions(-) diff --git a/src/mercury_engine_data_structures/_dread_data_construct.py b/src/mercury_engine_data_structures/_dread_data_construct.py index 3db88eaf..5a90a66b 100644 --- a/src/mercury_engine_data_structures/_dread_data_construct.py +++ b/src/mercury_engine_data_structures/_dread_data_construct.py @@ -1,5 +1,4 @@ import struct -import typing import construct @@ -30,7 +29,7 @@ def __init__(self): ), ) - def _parse(self, stream, context, path) -> typing.Dict[str, int]: + def _parse(self, stream, context, path) -> dict[str, int]: key_struct = struct.Struct("=H") value_struct = struct.Struct("=Q") @@ -44,7 +43,7 @@ def _parse(self, stream, context, path) -> typing.Dict[str, int]: return result - def _build(self, obj: typing.Dict[str, int], stream, context, path): + def _build(self, obj: dict[str, int], stream, context, path): return self._build_construct._build(list(obj.items()), stream, context, path) diff --git a/src/mercury_engine_data_structures/cli.py b/src/mercury_engine_data_structures/cli.py index 51c83045..229aefb4 100644 --- a/src/mercury_engine_data_structures/cli.py +++ b/src/mercury_engine_data_structures/cli.py @@ -6,7 +6,6 @@ import typing from concurrent.futures import ProcessPoolExecutor from pathlib import Path -from typing import Optional from mercury_engine_data_structures import formats from mercury_engine_data_structures.construct_extensions.json import convert_to_raw_python @@ -205,7 +204,7 @@ async def compare_all_files_in_path(args): input_path: Path = args.input_path file_format: str = args.format game: Game = args.game - limit: Optional[int] = args.limit + limit: int | None = args.limit def apply_limit(it): if limit is None: diff --git a/src/mercury_engine_data_structures/common_types.py b/src/mercury_engine_data_structures/common_types.py index 80d31a8e..e1102c74 100644 --- a/src/mercury_engine_data_structures/common_types.py +++ b/src/mercury_engine_data_structures/common_types.py @@ -402,7 +402,7 @@ def _emitbuild(code): return result -def make_enum(values: typing.Union[typing.List[str], typing.Dict[str, int]], *, add_invalid: bool = True): +def make_enum(values: list[str] | dict[str, int], *, add_invalid: bool = True): if isinstance(values, dict): mapping = copy.copy(values) else: diff --git a/src/mercury_engine_data_structures/construct_extensions/enum.py b/src/mercury_engine_data_structures/construct_extensions/enum.py index 6631fdd9..84e157ab 100644 --- a/src/mercury_engine_data_structures/construct_extensions/enum.py +++ b/src/mercury_engine_data_structures/construct_extensions/enum.py @@ -1,18 +1,17 @@ import enum -import typing import construct class StrictEnum(construct.Adapter): - def __init__(self, enum_class: typing.Type[enum.IntEnum]): + def __init__(self, enum_class: type[enum.IntEnum]): super().__init__(construct.Int32ul) self.enum_class = enum_class def _decode(self, obj: int, context, path): return self.enum_class(obj) - def _encode(self, obj: typing.Union[str, enum.IntEnum, int], context, path) -> int: + def _encode(self, obj: str | enum.IntEnum | int, context, path) -> int: if isinstance(obj, str): obj = getattr(self.enum_class, obj) @@ -39,7 +38,7 @@ def _encode_enum_{i}(obj, io, this): return f"_encode_enum_{i}(obj, io, this)" -def BitMaskEnum(enum_type: typing.Type[enum.IntEnum]): +def BitMaskEnum(enum_type: type[enum.IntEnum]): flags = {} for enumentry in enum_type: flags[enumentry.name] = 2**enumentry.value diff --git a/src/mercury_engine_data_structures/construct_extensions/function_complex.py b/src/mercury_engine_data_structures/construct_extensions/function_complex.py index 7382290a..7203be26 100644 --- a/src/mercury_engine_data_structures/construct_extensions/function_complex.py +++ b/src/mercury_engine_data_structures/construct_extensions/function_complex.py @@ -1,10 +1,9 @@ import re -from typing import Dict, Optional, Type, Union import construct -def _resolve_id(type_class: Union[construct.Construct, Type[construct.Construct]]) -> int: +def _resolve_id(type_class: construct.Construct | type[construct.Construct]) -> int: if isinstance(type_class, construct.Renamed): return _resolve_id(type_class.subcon) return id(type_class) @@ -16,8 +15,8 @@ def _resolve_id(type_class: Union[construct.Construct, Type[construct.Construct] def emit_switch_cases_parse( code: construct.CodeGen, - fields: Dict[Union[str, int], Union[construct.Construct, Type[construct.Construct]]], - custom_table_name: Optional[str] = None, + fields: dict[str | int, construct.Construct | type[construct.Construct]], + custom_table_name: str | None = None, ) -> str: """Construct codegen helper for handling the switch cases dict in _emitparse.""" table_name = custom_table_name @@ -48,8 +47,8 @@ def {code_name}(io, this): def emit_switch_cases_build( code: construct.CodeGen, - fields: Dict[Union[str, int], Union[construct.Construct, Type[construct.Construct]]], - custom_table_name: Optional[str] = None, + fields: dict[str | int, construct.Construct | type[construct.Construct]], + custom_table_name: str | None = None, ) -> str: """Construct codegen helper for handling the switch cases dict in _emitbuild.""" table_name = custom_table_name diff --git a/src/mercury_engine_data_structures/crc.py b/src/mercury_engine_data_structures/crc.py index 88625e4a..419a7bd3 100644 --- a/src/mercury_engine_data_structures/crc.py +++ b/src/mercury_engine_data_structures/crc.py @@ -2,8 +2,6 @@ Module for calculating CRC hashes with the algorithm and data used by Mercury Engine. """ -import typing - _crc32_constants = [ 0x00000000, 0x77073096, @@ -523,7 +521,7 @@ ] -def _algorithm(data: typing.Union[bytes, str], constants: typing.List[int], checksum: int) -> int: +def _algorithm(data: bytes | str, constants: list[int], checksum: int) -> int: if isinstance(data, str): data = data.encode("utf-8") @@ -533,7 +531,7 @@ def _algorithm(data: typing.Union[bytes, str], constants: typing.List[int], chec return checksum -def crc32(data: typing.Union[bytes, str]) -> int: +def crc32(data: bytes | str) -> int: return _algorithm( data, _crc32_constants, @@ -541,7 +539,7 @@ def crc32(data: typing.Union[bytes, str]) -> int: ) -def crc64(data: typing.Union[bytes, str]) -> int: +def crc64(data: bytes | str) -> int: return _algorithm( data, _crc64_constants, diff --git a/src/mercury_engine_data_structures/dread_data.py b/src/mercury_engine_data_structures/dread_data.py index b7a15be2..8720d365 100644 --- a/src/mercury_engine_data_structures/dread_data.py +++ b/src/mercury_engine_data_structures/dread_data.py @@ -2,7 +2,6 @@ import json import typing from pathlib import Path -from typing import Dict, Optional from mercury_engine_data_structures._dread_data_construct import KnownHashes @@ -10,14 +9,14 @@ @functools.lru_cache -def get_raw_types() -> Dict[str, typing.Any]: +def get_raw_types() -> dict[str, typing.Any]: path = _root.joinpath("dread_types.json") with path.open() as f: return json.load(f) @functools.lru_cache -def all_name_to_asset_id() -> Dict[str, int]: +def all_name_to_asset_id() -> dict[str, int]: bin_path = _root.joinpath("dread_resource_names.bin") if bin_path.exists(): return dict(KnownHashes.parse_file(bin_path)) @@ -28,16 +27,16 @@ def all_name_to_asset_id() -> Dict[str, int]: @functools.lru_cache -def all_asset_id_to_name() -> Dict[int, str]: +def all_asset_id_to_name() -> dict[int, str]: return {asset_id: name for name, asset_id in all_name_to_asset_id().items()} -def name_for_asset_id(asset_id: int) -> Optional[str]: +def name_for_asset_id(asset_id: int) -> str | None: return all_asset_id_to_name().get(asset_id) @functools.lru_cache -def all_name_to_property_id() -> Dict[str, int]: +def all_name_to_property_id() -> dict[str, int]: bin_path = _root.joinpath("dread_property_names.bin") if bin_path.exists(): return dict(KnownHashes.parse_file(bin_path)) @@ -48,13 +47,13 @@ def all_name_to_property_id() -> Dict[str, int]: @functools.lru_cache -def all_property_id_to_name() -> Dict[int, str]: +def all_property_id_to_name() -> dict[int, str]: names = all_name_to_property_id() return {asset_id: name for name, asset_id in names.items()} -def all_files_ending_with(ext: str, exclusions: Optional[list[str]] = None) -> list[str]: +def all_files_ending_with(ext: str, exclusions: list[str] | None = None) -> list[str]: if not ext.startswith("."): ext = "." + ext diff --git a/src/mercury_engine_data_structures/file_tree_editor.py b/src/mercury_engine_data_structures/file_tree_editor.py index 88ecd862..466c7b00 100644 --- a/src/mercury_engine_data_structures/file_tree_editor.py +++ b/src/mercury_engine_data_structures/file_tree_editor.py @@ -4,8 +4,8 @@ import logging import os.path import typing +from collections.abc import Iterator from pathlib import Path -from typing import Dict, Iterator, Optional, Set import construct @@ -60,11 +60,11 @@ class FileTreeEditor: _modified_resources: mapping of asset id to bytes. When saving, these asset ids are replaced """ - headers: Dict[str, construct.Container] - _files_for_asset_id: Dict[AssetId, Set[Optional[str]]] - _ensured_asset_ids: Dict[str, Set[AssetId]] - _modified_resources: Dict[AssetId, Optional[bytes]] - _in_memory_pkgs: Dict[str, Pkg] + headers: dict[str, construct.Container] + _files_for_asset_id: dict[AssetId, set[str | None]] + _ensured_asset_ids: dict[str, set[AssetId]] + _modified_resources: dict[AssetId, bytes | None] + _in_memory_pkgs: dict[str, Pkg] _toc: Toc def __init__(self, root: Path, target_game: Game): @@ -78,7 +78,7 @@ def __init__(self, root: Path, target_game: Game): def path_for_pkg(self, pkg_name: str) -> Path: return self.root.joinpath(pkg_name) - def _add_pkg_name_for_asset_id(self, asset_id: AssetId, pkg_name: Optional[str]): + def _add_pkg_name_for_asset_id(self, asset_id: AssetId, pkg_name: str | None): self._files_for_asset_id[asset_id] = self._files_for_asset_id.get(asset_id, set()) self._files_for_asset_id[asset_id].add(pkg_name) @@ -154,7 +154,7 @@ def does_asset_exists(self, asset_id: NameOrAssetId) -> bool: return asset_id in self._files_for_asset_id - def get_raw_asset(self, asset_id: NameOrAssetId, *, in_pkg: Optional[str] = None) -> bytes: + def get_raw_asset(self, asset_id: NameOrAssetId, *, in_pkg: str | None = None) -> bytes: """ Gets the bytes data for the given asset name/id, optionally restricting from which pkg. :raises ValueError if the asset doesn't exist. @@ -189,9 +189,7 @@ def get_raw_asset(self, asset_id: NameOrAssetId, *, in_pkg: Optional[str] = None raise ValueError(f"Unknown asset_id: {original_name}") - def get_parsed_asset( - self, name: str, *, in_pkg: Optional[str] = None, type_hint: typing.Type[_T] = BaseResource - ) -> _T: + def get_parsed_asset(self, name: str, *, in_pkg: str | None = None, type_hint: type[_T] = BaseResource) -> _T: """ Gets the resource with the given name and decodes it based on the extension. """ @@ -214,7 +212,7 @@ def get_file(self, path: str, type_hint: type[_T] = BaseResource) -> _T: """ return self.get_parsed_asset(path, type_hint=type_hint) - def add_new_asset(self, name: str, new_data: typing.Union[bytes, BaseResource], in_pkgs: typing.Iterable[str]): + def add_new_asset(self, name: str, new_data: bytes | BaseResource, in_pkgs: typing.Iterable[str]): """ Adds an asset that doesn't already exist. """ @@ -241,7 +239,7 @@ def add_new_asset(self, name: str, new_data: typing.Union[bytes, BaseResource], for pkg_name in in_pkgs: self.ensure_present(pkg_name, asset_id) - def replace_asset(self, asset_id: NameOrAssetId, new_data: typing.Union[bytes, BaseResource]): + def replace_asset(self, asset_id: NameOrAssetId, new_data: bytes | BaseResource): """ Replaces an existing asset. See `add_new_asset` for new assets. diff --git a/src/mercury_engine_data_structures/formats/__init__.py b/src/mercury_engine_data_structures/formats/__init__.py index bb0e37e3..760e7d45 100644 --- a/src/mercury_engine_data_structures/formats/__init__.py +++ b/src/mercury_engine_data_structures/formats/__init__.py @@ -1,5 +1,3 @@ -from typing import Type - from mercury_engine_data_structures.formats.bapd import Bapd from mercury_engine_data_structures.formats.base_resource import AssetType, BaseResource from mercury_engine_data_structures.formats.bcmdl import Bcmdl @@ -105,5 +103,5 @@ } -def format_for(type_name: AssetType) -> Type[BaseResource]: +def format_for(type_name: AssetType) -> type[BaseResource]: return ALL_FORMATS[type_name.upper()] diff --git a/src/mercury_engine_data_structures/formats/base_resource.py b/src/mercury_engine_data_structures/formats/base_resource.py index d07dcaa5..8b5ed30b 100644 --- a/src/mercury_engine_data_structures/formats/base_resource.py +++ b/src/mercury_engine_data_structures/formats/base_resource.py @@ -40,7 +40,7 @@ def raw(self) -> Container: AssetType = str AssetId = int -NameOrAssetId = typing.Union[str, AssetId] +NameOrAssetId = str | AssetId def resolve_asset_id(value: NameOrAssetId, game: Game) -> AssetId: diff --git a/src/mercury_engine_data_structures/formats/bmmdef.py b/src/mercury_engine_data_structures/formats/bmmdef.py index aeef731c..5e986bfa 100644 --- a/src/mercury_engine_data_structures/formats/bmmdef.py +++ b/src/mercury_engine_data_structures/formats/bmmdef.py @@ -1,5 +1,3 @@ -from typing import Tuple - from construct import Construct, Container from mercury_engine_data_structures.formats import standard_format @@ -25,7 +23,7 @@ def add_icon( uSpriteCol: int, sInspectorLabel: str, sDisabledIconId: str = "", - vAnchorOffset: Tuple[int, int] = (0, 0), + vAnchorOffset: tuple[int, int] = (0, 0), bAutoScale: bool = True, **kwargs, ): diff --git a/src/mercury_engine_data_structures/formats/bmsad.py b/src/mercury_engine_data_structures/formats/bmsad.py index a9f68a0c..8122ee83 100644 --- a/src/mercury_engine_data_structures/formats/bmsad.py +++ b/src/mercury_engine_data_structures/formats/bmsad.py @@ -497,7 +497,7 @@ def __set__(self, inst: ActorDefFunc, value: T): Vec3 = list -FieldType = typing.Union[bool, str, float, int, Vec3] +FieldType = bool | str | float | int | Vec3 class ComponentFields: diff --git a/src/mercury_engine_data_structures/formats/bmsld.py b/src/mercury_engine_data_structures/formats/bmsld.py index ea624b87..77f6508b 100644 --- a/src/mercury_engine_data_structures/formats/bmsld.py +++ b/src/mercury_engine_data_structures/formats/bmsld.py @@ -1,5 +1,5 @@ import logging -from typing import Iterator, Tuple +from collections.abc import Iterator import construct from construct import Const, Construct, Container, Flag, Float32l, Hex, Int32ul, Struct, Switch @@ -145,7 +145,7 @@ class Bmsld(BaseResource): def construct_class(cls, target_game: Game) -> Construct: return BMSLD - def all_actors(self) -> Iterator[Tuple[int, str, construct.Container]]: + def all_actors(self) -> Iterator[tuple[int, str, construct.Container]]: for layer in self.raw.actors: for actor_name, actor in layer.items(): yield layer, actor_name, actor diff --git a/src/mercury_engine_data_structures/formats/brfld.py b/src/mercury_engine_data_structures/formats/brfld.py index 57575b0e..3536ff20 100644 --- a/src/mercury_engine_data_structures/formats/brfld.py +++ b/src/mercury_engine_data_structures/formats/brfld.py @@ -1,6 +1,6 @@ import functools import logging -from typing import Iterator, List, Tuple +from collections.abc import Iterator import construct @@ -23,7 +23,7 @@ def actors_for_layer(self, name: str) -> dict: def all_layers(self) -> Iterator[str]: yield from self.raw.Root.pScenario.rEntitiesLayer.dctSublayers.keys() - def all_actors(self) -> Iterator[Tuple[str, str, construct.Container]]: + def all_actors(self) -> Iterator[tuple[str, str, construct.Container]]: for layer_name, sublayer in self.raw.Root.pScenario.rEntitiesLayer.dctSublayers.items(): for actor_name, actor in sublayer.dctActors.items(): yield layer_name, actor_name, actor @@ -41,7 +41,7 @@ def link_for_actor(self, actor_name: str, layer_name: str = "default") -> str: def all_actor_groups(self) -> Iterator[str]: yield from self.raw.Root.pScenario.rEntitiesLayer.dctActorGroups.keys() - def get_actor_group(self, group_name: str) -> List[str]: + def get_actor_group(self, group_name: str) -> list[str]: return self.raw.Root.pScenario.rEntitiesLayer.dctActorGroups[group_name] def is_actor_in_group(self, group_name: str, actor_name: str, layer_name: str = "default") -> bool: diff --git a/src/mercury_engine_data_structures/formats/brsa.py b/src/mercury_engine_data_structures/formats/brsa.py index 75beefc9..cd9b6064 100644 --- a/src/mercury_engine_data_structures/formats/brsa.py +++ b/src/mercury_engine_data_structures/formats/brsa.py @@ -1,5 +1,5 @@ import functools -from typing import Iterator +from collections.abc import Iterator from construct import Construct, Container diff --git a/src/mercury_engine_data_structures/formats/property_enum.py b/src/mercury_engine_data_structures/formats/property_enum.py index ca19719f..c9bd7544 100644 --- a/src/mercury_engine_data_structures/formats/property_enum.py +++ b/src/mercury_engine_data_structures/formats/property_enum.py @@ -1,8 +1,6 @@ import enum import functools -import typing import warnings -from typing import Dict import construct @@ -24,7 +22,7 @@ class HashSet(enum.Enum): PROPERTY = enum.auto() FILE_NAME = enum.auto() - def known_hashes(self, context) -> Dict[str, int]: + def known_hashes(self, context) -> dict[str, int]: if self == HashSet.PROPERTY: return _correct_data(context._params.target_game).all_name_to_property_id() elif self == HashSet.FILE_NAME: @@ -32,7 +30,7 @@ def known_hashes(self, context) -> Dict[str, int]: else: raise ValueError("Unknown") - def inverted_hashes(self, context) -> Dict[int, str]: + def inverted_hashes(self, context) -> dict[int, str]: if self == HashSet.PROPERTY: return _correct_data(context._params.target_game).all_property_id_to_name() elif self == HashSet.FILE_NAME: @@ -41,7 +39,7 @@ def inverted_hashes(self, context) -> Dict[int, str]: raise ValueError("Unknown") -HashedName = typing.Union[str, int] +HashedName = str | int class CRCAdapter(construct.Adapter): diff --git a/src/mercury_engine_data_structures/formats/standard_format.py b/src/mercury_engine_data_structures/formats/standard_format.py index c5c5b933..39566ce3 100644 --- a/src/mercury_engine_data_structures/formats/standard_format.py +++ b/src/mercury_engine_data_structures/formats/standard_format.py @@ -1,6 +1,5 @@ import functools import typing -from typing import Optional import construct @@ -15,9 +14,9 @@ def _const_if_present(con: construct.Construct, value: typing.Any | None) -> con def create( - name: Optional[str], - version: Optional[int | str | tuple[int, int, int]], - root_name: Optional[str] = None, + name: str | None, + version: int | str | tuple[int, int, int] | None, + root_name: str | None = None, explicit_root: bool = False, ): # this maybe needs to change in the future if SR and Dread have different formats for type using this @@ -49,9 +48,9 @@ def create( @functools.lru_cache -def _cached_game_model(name: Optional[str], version: Optional[int | str | tuple[int, int, int]]): +def _cached_game_model(name: str | None, version: int | str | tuple[int, int, int] | None): return create(name, version, "gameeditor::CGameModelRoot").compile() -def game_model(name: Optional[str], version: Optional[int | str | tuple[int, int, int]]): +def game_model(name: str | None, version: int | str | tuple[int, int, int] | None): return _cached_game_model(name, version) diff --git a/src/mercury_engine_data_structures/formats/toc.py b/src/mercury_engine_data_structures/formats/toc.py index e9e25a2b..8b205af3 100644 --- a/src/mercury_engine_data_structures/formats/toc.py +++ b/src/mercury_engine_data_structures/formats/toc.py @@ -1,5 +1,5 @@ import functools -from typing import Iterator, Optional +from collections.abc import Iterator import construct @@ -34,7 +34,7 @@ def construct_class(cls, target_game: Game) -> construct.Construct: def system_files_name(cls) -> str: return "system/files.toc" - def get_size_for(self, asset_id: NameOrAssetId) -> Optional[int]: + def get_size_for(self, asset_id: NameOrAssetId) -> int | None: asset_id = resolve_asset_id(asset_id, self.target_game) return self._raw.files.get(asset_id) diff --git a/src/mercury_engine_data_structures/formats/txt.py b/src/mercury_engine_data_structures/formats/txt.py index 41bd6f8f..ff06c295 100644 --- a/src/mercury_engine_data_structures/formats/txt.py +++ b/src/mercury_engine_data_structures/formats/txt.py @@ -1,5 +1,4 @@ import functools -from typing import Dict import construct from construct.core import Const, Construct, GreedyRange, Struct @@ -54,7 +53,7 @@ def construct_class(cls, target_game: Game) -> Construct: return TXT.compile() @property - def strings(self) -> Dict[str, str]: + def strings(self) -> dict[str, str]: return self._raw.strings @strings.setter diff --git a/src/mercury_engine_data_structures/game_check.py b/src/mercury_engine_data_structures/game_check.py index 4deb060b..3b1314e5 100644 --- a/src/mercury_engine_data_structures/game_check.py +++ b/src/mercury_engine_data_structures/game_check.py @@ -2,9 +2,10 @@ For checking which game is being parsed """ +from collections.abc import Callable from enum import Enum from functools import cached_property -from typing import Any, Callable +from typing import Any import construct from construct.core import IfThenElse diff --git a/src/mercury_engine_data_structures/object.py b/src/mercury_engine_data_structures/object.py index b2f913dd..8992de93 100644 --- a/src/mercury_engine_data_structures/object.py +++ b/src/mercury_engine_data_structures/object.py @@ -1,6 +1,3 @@ -import typing -from typing import Dict, Type, Union - import construct from mercury_engine_data_structures.construct_extensions.function_complex import ( @@ -11,11 +8,11 @@ class Object(construct.Construct): - def __init__(self, fields: Dict[str, Union[construct.Construct, Type[construct.Construct]]]): + def __init__(self, fields: dict[str, construct.Construct | type[construct.Construct]]): super().__init__() self.fields = fields - def _parse(self, stream, context, path) -> typing.Union[construct.Container, construct.ListContainer]: + def _parse(self, stream, context, path) -> construct.Container | construct.ListContainer: field_count = construct.Int32ul._parsereport(stream, context, path) array_response = False @@ -44,7 +41,7 @@ def _parse(self, stream, context, path) -> typing.Union[construct.Container, con return result - def _build(self, obj: typing.Union[construct.Container, construct.ListContainer], stream, context, path): + def _build(self, obj: construct.Container | construct.ListContainer, stream, context, path): construct.Int32ul._build(len(obj), stream, context, path) if isinstance(obj, list): diff --git a/src/mercury_engine_data_structures/pointer_set.py b/src/mercury_engine_data_structures/pointer_set.py index 2d0a2a87..39127e43 100644 --- a/src/mercury_engine_data_structures/pointer_set.py +++ b/src/mercury_engine_data_structures/pointer_set.py @@ -4,7 +4,6 @@ import copy import struct -from typing import Dict, Type, Union import construct from construct import Adapter, Construct, Container, Hex, Int64ul, ListContainer, Struct, Switch @@ -18,9 +17,9 @@ class PointerAdapter(Adapter): - types: Dict[int, Union[Construct, Type[Construct]]] + types: dict[int, Construct | type[Construct]] - def __init__(self, types: Dict[int, Union[Construct, Type[Construct]]], category: str): + def __init__(self, types: dict[int, Construct | type[Construct]], category: str): get_name = mercury_engine_data_structures.dread_data.all_property_id_to_name().get self.switch_con = Switch( construct.this.type, @@ -155,7 +154,7 @@ def {fname}(the_obj, io, this): class PointerSet: - types: Dict[int, Union[Construct, Type[Construct]]] + types: dict[int, Construct | type[Construct]] def __init__(self, category: str, *, allow_null: bool = True): self.category = category @@ -164,12 +163,12 @@ def __init__(self, category: str, *, allow_null: bool = True): self.add_option("void", construct.Pass) @classmethod - def construct_pointer_for(cls, name: str, conn: Union[Construct, Type[Construct]]) -> Construct: + def construct_pointer_for(cls, name: str, conn: Construct | type[Construct]) -> Construct: ret = cls(name, allow_null=True) ret.add_option(name, conn) return ret.create_construct() - def add_option(self, name: str, value: Union[Construct, Type[Construct]]) -> None: + def add_option(self, name: str, value: Construct | type[Construct]) -> None: prop_id = mercury_engine_data_structures.dread_data.all_name_to_property_id()[name] if prop_id in self.types: raise ValueError(f"Attempting to add {name} to {self.category}, but already present.") diff --git a/src/mercury_engine_data_structures/samus_returns_data.py b/src/mercury_engine_data_structures/samus_returns_data.py index d34d120d..6da3ab13 100644 --- a/src/mercury_engine_data_structures/samus_returns_data.py +++ b/src/mercury_engine_data_structures/samus_returns_data.py @@ -2,7 +2,6 @@ import json import typing from pathlib import Path -from typing import Dict, Optional from mercury_engine_data_structures._dread_data_construct import KnownHashes @@ -10,14 +9,14 @@ @functools.lru_cache -def get_raw_types() -> Dict[str, typing.Any]: +def get_raw_types() -> dict[str, typing.Any]: path = Path(__file__).parent.joinpath("samus_returns_types.json") with path.open() as f: return json.load(f) @functools.lru_cache -def all_name_to_asset_id() -> Dict[str, int]: +def all_name_to_asset_id() -> dict[str, int]: bin_path = _root.joinpath("sr_resource_names.bin") if bin_path.exists(): return dict(KnownHashes.parse_file(bin_path)) @@ -29,16 +28,16 @@ def all_name_to_asset_id() -> Dict[str, int]: @functools.lru_cache -def all_asset_id_to_name() -> Dict[int, str]: +def all_asset_id_to_name() -> dict[int, str]: return {asset_id: name for name, asset_id in all_name_to_asset_id().items()} -def name_for_asset_id(asset_id: int) -> Optional[str]: +def name_for_asset_id(asset_id: int) -> str | None: return all_asset_id_to_name().get(asset_id) @functools.lru_cache -def all_name_to_property_id() -> Dict[str, int]: +def all_name_to_property_id() -> dict[str, int]: bin_path = _root.joinpath("sr_property_names.bin") if bin_path.exists(): return dict(KnownHashes.parse_file(bin_path)) @@ -49,13 +48,13 @@ def all_name_to_property_id() -> Dict[str, int]: @functools.lru_cache -def all_property_id_to_name() -> Dict[int, str]: +def all_property_id_to_name() -> dict[int, str]: names = all_name_to_property_id() return {asset_id: name for name, asset_id in names.items()} -def all_files_ending_with(ext: str, exclusions: Optional[list[str]] = None) -> list[str]: +def all_files_ending_with(ext: str, exclusions: list[str] | None = None) -> list[str]: if not ext.startswith("."): ext = "." + ext diff --git a/tests/test_lib.py b/tests/test_lib.py index 90a6757d..7fdffac7 100644 --- a/tests/test_lib.py +++ b/tests/test_lib.py @@ -1,4 +1,3 @@ -import typing from pathlib import Path import construct @@ -26,7 +25,7 @@ def parse_and_build_compare(module, game: Game, file_path: Path, print_data=Fals assert encoded == raw -def _parse_build_compare(module: typing.Type[BaseResource], editor: FileTreeEditor, file_name: str, print_data=False): +def _parse_build_compare(module: type[BaseResource], editor: FileTreeEditor, file_name: str, print_data=False): construct_class = module.construct_class(editor.target_game) raw = editor.get_raw_asset(file_name) @@ -38,16 +37,14 @@ def _parse_build_compare(module: typing.Type[BaseResource], editor: FileTreeEdit return raw, encoded, data -def parse_build_compare_editor( - module: typing.Type[BaseResource], editor: FileTreeEditor, file_name: str, print_data=False -): +def parse_build_compare_editor(module: type[BaseResource], editor: FileTreeEditor, file_name: str, print_data=False): raw, encoded, _ = _parse_build_compare(module, editor, file_name, print_data) assert encoded == raw def parse_build_compare_editor_parsed( - module: typing.Type[BaseResource], editor: FileTreeEditor, file_name: str, print_data=False + module: type[BaseResource], editor: FileTreeEditor, file_name: str, print_data=False ): _, encoded, data = _parse_build_compare(module, editor, file_name, print_data) diff --git a/tools/ghidra_export.py b/tools/ghidra_export.py index b73a2eac..853967e0 100644 --- a/tools/ghidra_export.py +++ b/tools/ghidra_export.py @@ -408,7 +408,7 @@ def get_function_list() -> dict[str, tuple[int, int, int]]: } -bridge: typing.Optional[ghidra_bridge.GhidraBridge] = None +bridge: ghidra_bridge.GhidraBridge | None = None def initialize_worker(): @@ -430,8 +430,8 @@ def initialize_worker(): def decompile_type( - type_name: str, init_id: typing.Optional[int], fields_id: typing.Optional[int], values_id: typing.Optional[int] -) -> tuple[str, typing.Optional[str], dict[str, str], dict[str, int]]: + type_name: str, init_id: int | None, fields_id: int | None, values_id: int | None +) -> tuple[str, str | None, dict[str, str], dict[str, int]]: if bridge is None: raise ValueError("Bridge not initialized") @@ -443,7 +443,7 @@ def find_parent(f): return other.getName(True) """) - parent_init: typing.Optional[str] = None + parent_init: str | None = None if init_id is not None: parent_init = bridge.remote_eval( """find_parent( diff --git a/tools/plot_simple_map.py b/tools/plot_simple_map.py index 89edf821..4d6f9c6f 100644 --- a/tools/plot_simple_map.py +++ b/tools/plot_simple_map.py @@ -28,9 +28,9 @@ } id_to_name = {os.path.splitext(path.split("/")[-1])[0]: name for path, name in world_names.items()} pickup_index = 0 -bmscc: typing.Optional[Bmscc] = None -brsa: typing.Optional[Brsa] = None -brfld: typing.Optional[Brfld] = None +bmscc: Bmscc | None = None +brsa: Brsa | None = None +brfld: Brfld | None = None brfld_path: str = None events: dict[str, dict] = {} @@ -3134,7 +3134,7 @@ def create_node_template( self, node_type: str, default_name: str, - existing_data: typing.Optional[dict[str, NodeDefinition]], + existing_data: dict[str, NodeDefinition] | None, ) -> NodeDefinition: result: dict = { "node_type": node_type, @@ -3212,7 +3212,7 @@ def _find_room_orientation(world: dict, room_a: str, room_b: str): raise ValueError(f"{room_a} and {room_b} are aligned") -def get_def_link_for_entity(actor_ref: str) -> typing.Optional[str]: +def get_def_link_for_entity(actor_ref: str) -> str | None: a = brfld.follow_link(actor_ref) if a is not None: return a.oActorDefLink @@ -3396,7 +3396,7 @@ def add_node(target_area: str, node_def: NodeDefinition): world["areas"][target_area]["nodes"][node_def.name] = node_def.data actor_to_area[get_actor_name_for_node(node_def.data)] = target_area - def get_node_def_for_actor(actor_name: str) -> typing.Optional[NodeDefinition]: + def get_node_def_for_actor(actor_name: str) -> NodeDefinition | None: actor_area = actor_to_area.get(actor_name) if actor_area is not None: for existing_name, existing_node in world["areas"][actor_area]["nodes"].items(): diff --git a/tools/sr_export_rdv_database.py b/tools/sr_export_rdv_database.py index f72618ee..26abcc3b 100644 --- a/tools/sr_export_rdv_database.py +++ b/tools/sr_export_rdv_database.py @@ -39,9 +39,9 @@ } id_to_name = {os.path.splitext(path.split("/")[-1])[0]: name for path, name in world_names.items()} pickup_index = 0 -bmscc: typing.Optional[Bmscc] = None +bmscc: Bmscc | None = None # brsa: typing.Optional[Brsa] = None -bmsld: typing.Optional[Bmsld] = None +bmsld: Bmsld | None = None bmsld_path: str = None events: dict[str, dict] = {} @@ -398,7 +398,7 @@ def create_node_template( self, node_type: str, default_name: str, - existing_data: typing.Optional[dict[str, NodeDefinition]], + existing_data: dict[str, NodeDefinition] | None, ) -> NodeDefinition: result: dict = { "node_type": node_type,