Core: Update Some Outdated Typing (#4986)

This commit is contained in:
Nicholas Saylor
2025-05-14 07:40:38 -04:00
committed by GitHub
parent a87fec0cbd
commit 02fd75c018
6 changed files with 77 additions and 79 deletions

View File

@@ -10,8 +10,8 @@ import sys
import urllib.parse import urllib.parse
import urllib.request import urllib.request
from collections import Counter from collections import Counter
from typing import Any, Dict, Tuple, Union
from itertools import chain from itertools import chain
from typing import Any
import ModuleUpdate import ModuleUpdate
@@ -77,7 +77,7 @@ def get_seed_name(random_source) -> str:
return f"{random_source.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits) return f"{random_source.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)
def main(args=None) -> Tuple[argparse.Namespace, int]: def main(args=None) -> tuple[argparse.Namespace, int]:
# __name__ == "__main__" check so unittests that already imported worlds don't trip this. # __name__ == "__main__" check so unittests that already imported worlds don't trip this.
if __name__ == "__main__" and "worlds" in sys.modules: if __name__ == "__main__" and "worlds" in sys.modules:
raise Exception("Worlds system should not be loaded before logging init.") raise Exception("Worlds system should not be loaded before logging init.")
@@ -95,7 +95,7 @@ def main(args=None) -> Tuple[argparse.Namespace, int]:
logging.info("Race mode enabled. Using non-deterministic random source.") logging.info("Race mode enabled. Using non-deterministic random source.")
random.seed() # reset to time-based random source random.seed() # reset to time-based random source
weights_cache: Dict[str, Tuple[Any, ...]] = {} weights_cache: dict[str, tuple[Any, ...]] = {}
if args.weights_file_path and os.path.exists(args.weights_file_path): if args.weights_file_path and os.path.exists(args.weights_file_path):
try: try:
weights_cache[args.weights_file_path] = read_weights_yamls(args.weights_file_path) weights_cache[args.weights_file_path] = read_weights_yamls(args.weights_file_path)
@@ -180,7 +180,7 @@ def main(args=None) -> Tuple[argparse.Namespace, int]:
erargs.name = {} erargs.name = {}
erargs.csv_output = args.csv_output erargs.csv_output = args.csv_output
settings_cache: Dict[str, Tuple[argparse.Namespace, ...]] = \ settings_cache: dict[str, tuple[argparse.Namespace, ...]] = \
{fname: (tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.sameoptions else None) {fname: (tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.sameoptions else None)
for fname, yamls in weights_cache.items()} for fname, yamls in weights_cache.items()}
@@ -212,7 +212,7 @@ def main(args=None) -> Tuple[argparse.Namespace, int]:
path = player_path_cache[player] path = player_path_cache[player]
if path: if path:
try: try:
settings: Tuple[argparse.Namespace, ...] = settings_cache[path] if settings_cache[path] else \ settings: tuple[argparse.Namespace, ...] = settings_cache[path] if settings_cache[path] else \
tuple(roll_settings(yaml, args.plando) for yaml in weights_cache[path]) tuple(roll_settings(yaml, args.plando) for yaml in weights_cache[path])
for settingsObject in settings: for settingsObject in settings:
for k, v in vars(settingsObject).items(): for k, v in vars(settingsObject).items():
@@ -242,7 +242,7 @@ def main(args=None) -> Tuple[argparse.Namespace, int]:
return erargs, seed return erargs, seed
def read_weights_yamls(path) -> Tuple[Any, ...]: def read_weights_yamls(path) -> tuple[Any, ...]:
try: try:
if urllib.parse.urlparse(path).scheme in ('https', 'file'): if urllib.parse.urlparse(path).scheme in ('https', 'file'):
yaml = str(urllib.request.urlopen(path).read(), "utf-8-sig") yaml = str(urllib.request.urlopen(path).read(), "utf-8-sig")
@@ -378,7 +378,7 @@ def update_weights(weights: dict, new_weights: dict, update_type: str, name: str
return weights return weights
def roll_meta_option(option_key, game: str, category_dict: Dict) -> Any: def roll_meta_option(option_key, game: str, category_dict: dict) -> Any:
from worlds import AutoWorldRegister from worlds import AutoWorldRegister
if not game: if not game:

View File

@@ -16,9 +16,10 @@ import subprocess
import sys import sys
import urllib.parse import urllib.parse
import webbrowser import webbrowser
from collections.abc import Callable, Sequence
from os.path import isfile from os.path import isfile
from shutil import which from shutil import which
from typing import Callable, Optional, Sequence, Tuple, Union, Any from typing import Any
if __name__ == "__main__": if __name__ == "__main__":
import ModuleUpdate import ModuleUpdate
@@ -114,7 +115,7 @@ components.extend([
]) ])
def handle_uri(path: str, launch_args: Tuple[str, ...]) -> None: def handle_uri(path: str, launch_args: tuple[str, ...]) -> None:
url = urllib.parse.urlparse(path) url = urllib.parse.urlparse(path)
queries = urllib.parse.parse_qs(url.query) queries = urllib.parse.parse_qs(url.query)
launch_args = (path, *launch_args) launch_args = (path, *launch_args)
@@ -162,7 +163,7 @@ def handle_uri(path: str, launch_args: Tuple[str, ...]) -> None:
).open() ).open()
def identify(path: Union[None, str]) -> Tuple[Union[None, str], Union[None, Component]]: def identify(path: None | str) -> tuple[None | str, None | Component]:
if path is None: if path is None:
return None, None return None, None
for component in components: for component in components:
@@ -173,7 +174,7 @@ def identify(path: Union[None, str]) -> Tuple[Union[None, str], Union[None, Comp
return None, None return None, None
def get_exe(component: Union[str, Component]) -> Optional[Sequence[str]]: def get_exe(component: str | Component) -> Sequence[str] | None:
if isinstance(component, str): if isinstance(component, str):
name = component name = component
component = None component = None
@@ -226,7 +227,7 @@ def create_shortcut(button: Any, component: Component) -> None:
button.menu.dismiss() button.menu.dismiss()
refresh_components: Optional[Callable[[], None]] = None refresh_components: Callable[[], None] | None = None
def run_gui(path: str, args: Any) -> None: def run_gui(path: str, args: Any) -> None:
@@ -451,7 +452,7 @@ def run_component(component: Component, *args):
logging.warning(f"Component {component} does not appear to be executable.") logging.warning(f"Component {component} does not appear to be executable.")
def main(args: Optional[Union[argparse.Namespace, dict]] = None): def main(args: argparse.Namespace | dict | None = None):
if isinstance(args, argparse.Namespace): if isinstance(args, argparse.Namespace):
args = {k: v for k, v in args._get_kwargs()} args = {k: v for k, v in args._get_kwargs()}
elif not args: elif not args:

21
Main.py
View File

@@ -7,14 +7,13 @@ import tempfile
import time import time
import zipfile import zipfile
import zlib import zlib
from typing import Dict, List, Optional, Set, Tuple, Union
import worlds import worlds
from BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld, Region from BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld
from Fill import FillError, balance_multiworld_progression, distribute_items_restrictive, flood_items, \ from Fill import FillError, balance_multiworld_progression, distribute_items_restrictive, flood_items, \
parse_planned_blocks, distribute_planned_blocks, resolve_early_locations_for_planned parse_planned_blocks, distribute_planned_blocks, resolve_early_locations_for_planned
from Options import StartInventoryPool from Options import StartInventoryPool
from Utils import __version__, output_path, version_tuple, get_settings from Utils import __version__, output_path, version_tuple
from settings import get_settings from settings import get_settings
from worlds import AutoWorld from worlds import AutoWorld
from worlds.generic.Rules import exclusion_rules, locality_rules from worlds.generic.Rules import exclusion_rules, locality_rules
@@ -22,7 +21,7 @@ from worlds.generic.Rules import exclusion_rules, locality_rules
__all__ = ["main"] __all__ = ["main"]
def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = None): def main(args, seed=None, baked_server_options: dict[str, object] | None = None):
if not baked_server_options: if not baked_server_options:
baked_server_options = get_settings().server_options.as_dict() baked_server_options = get_settings().server_options.as_dict()
assert isinstance(baked_server_options, dict) assert isinstance(baked_server_options, dict)
@@ -140,7 +139,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
# remove starting inventory from pool items. # remove starting inventory from pool items.
# Because some worlds don't actually create items during create_items this has to be as late as possible. # Because some worlds don't actually create items during create_items this has to be as late as possible.
fallback_inventory = StartInventoryPool({}) fallback_inventory = StartInventoryPool({})
depletion_pool: Dict[int, Dict[str, int]] = { depletion_pool: dict[int, dict[str, int]] = {
player: getattr(multiworld.worlds[player].options, "start_inventory_from_pool", fallback_inventory).value.copy() player: getattr(multiworld.worlds[player].options, "start_inventory_from_pool", fallback_inventory).value.copy()
for player in multiworld.player_ids for player in multiworld.player_ids
} }
@@ -149,7 +148,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
} }
if target_per_player: if target_per_player:
new_itempool: List[Item] = [] new_itempool: list[Item] = []
# Make new itempool with start_inventory_from_pool items removed # Make new itempool with start_inventory_from_pool items removed
for item in multiworld.itempool: for item in multiworld.itempool:
@@ -233,7 +232,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
pool.submit(AutoWorld.call_single, multiworld, "generate_output", player, temp_dir)) pool.submit(AutoWorld.call_single, multiworld, "generate_output", player, temp_dir))
# collect ER hint info # collect ER hint info
er_hint_data: Dict[int, Dict[int, str]] = {} er_hint_data: dict[int, dict[int, str]] = {}
AutoWorld.call_all(multiworld, 'extend_hint_information', er_hint_data) AutoWorld.call_all(multiworld, 'extend_hint_information', er_hint_data)
def write_multidata(): def write_multidata():
@@ -274,7 +273,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
for player in multiworld.groups[location.item.player]["players"]: for player in multiworld.groups[location.item.player]["players"]:
precollected_hints[player].add(hint) precollected_hints[player].add(hint)
locations_data: Dict[int, Dict[int, Tuple[int, int, int]]] = {player: {} for player in multiworld.player_ids} locations_data: dict[int, dict[int, tuple[int, int, int]]] = {player: {} for player in multiworld.player_ids}
for location in multiworld.get_filled_locations(): for location in multiworld.get_filled_locations():
if type(location.address) == int: if type(location.address) == int:
assert location.item.code is not None, "item code None should be event, " \ assert location.item.code is not None, "item code None should be event, " \
@@ -303,12 +302,12 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
} }
data_package["Archipelago"] = worlds.network_data_package["games"]["Archipelago"] data_package["Archipelago"] = worlds.network_data_package["games"]["Archipelago"]
checks_in_area: Dict[int, Dict[str, Union[int, List[int]]]] = {} checks_in_area: dict[int, dict[str, int | list[int]]] = {}
# get spheres -> filter address==None -> skip empty # get spheres -> filter address==None -> skip empty
spheres: List[Dict[int, Set[int]]] = [] spheres: list[dict[int, set[int]]] = []
for sphere in multiworld.get_sendable_spheres(): for sphere in multiworld.get_sendable_spheres():
current_sphere: Dict[int, Set[int]] = collections.defaultdict(set) current_sphere: dict[int, set[int]] = collections.defaultdict(set)
for sphere_location in sphere: for sphere_location in sphere:
current_sphere[sphere_location.player].add(sphere_location.address) current_sphere[sphere_location.player].add(sphere_location.address)

View File

@@ -10,9 +10,10 @@ import sys
import types import types
import typing import typing
import warnings import warnings
from collections.abc import Iterator, Sequence
from enum import IntEnum from enum import IntEnum
from threading import Lock from threading import Lock
from typing import cast, Any, BinaryIO, ClassVar, Dict, Iterator, List, Optional, TextIO, Tuple, Union, TypeVar from typing import cast, Any, BinaryIO, ClassVar, TextIO, TypeVar, Union
__all__ = [ __all__ = [
"get_settings", "fmt_doc", "no_gui", "get_settings", "fmt_doc", "no_gui",
@@ -23,7 +24,7 @@ __all__ = [
no_gui = False no_gui = False
skip_autosave = False skip_autosave = False
_world_settings_name_cache: Dict[str, str] = {} # TODO: cache on disk and update when worlds change _world_settings_name_cache: dict[str, str] = {} # TODO: cache on disk and update when worlds change
_world_settings_name_cache_updated = False _world_settings_name_cache_updated = False
_lock = Lock() _lock = Lock()
@@ -53,7 +54,7 @@ def fmt_doc(cls: type, level: int) -> str:
class Group: class Group:
_type_cache: ClassVar[Optional[Dict[str, Any]]] = None _type_cache: ClassVar[dict[str, Any] | None] = None
_dumping: bool = False _dumping: bool = False
_has_attr: bool = False _has_attr: bool = False
_changed: bool = False _changed: bool = False
@@ -106,7 +107,7 @@ class Group:
self.__dict__.values())) self.__dict__.values()))
@classmethod @classmethod
def get_type_hints(cls) -> Dict[str, Any]: def get_type_hints(cls) -> dict[str, Any]:
"""Returns resolved type hints for the class""" """Returns resolved type hints for the class"""
if cls._type_cache is None: if cls._type_cache is None:
if not cls.__annotations__ or not isinstance(next(iter(cls.__annotations__.values())), str): if not cls.__annotations__ or not isinstance(next(iter(cls.__annotations__.values())), str):
@@ -124,10 +125,10 @@ class Group:
return self[key] return self[key]
return default return default
def items(self) -> List[Tuple[str, Any]]: def items(self) -> list[tuple[str, Any]]:
return [(key, getattr(self, key)) for key in self] return [(key, getattr(self, key)) for key in self]
def update(self, dct: Dict[str, Any]) -> None: def update(self, dct: dict[str, Any]) -> None:
assert isinstance(dct, dict), f"{self.__class__.__name__}.update called with " \ assert isinstance(dct, dict), f"{self.__class__.__name__}.update called with " \
f"{dct.__class__.__name__} instead of dict." f"{dct.__class__.__name__} instead of dict."
@@ -196,7 +197,7 @@ class Group:
warnings.warn(f"{self.__class__.__name__}.{k} " warnings.warn(f"{self.__class__.__name__}.{k} "
f"assigned from incompatible type {type(v).__name__}") f"assigned from incompatible type {type(v).__name__}")
def as_dict(self, *args: str, downcast: bool = True) -> Dict[str, Any]: def as_dict(self, *args: str, downcast: bool = True) -> dict[str, Any]:
return { return {
name: _to_builtin(cast(object, getattr(self, name))) if downcast else getattr(self, name) name: _to_builtin(cast(object, getattr(self, name))) if downcast else getattr(self, name)
for name in self if not args or name in args for name in self if not args or name in args
@@ -211,7 +212,7 @@ class Group:
f.write(f"{indent}{yaml_line}") f.write(f"{indent}{yaml_line}")
@classmethod @classmethod
def _dump_item(cls, name: Optional[str], attr: object, f: TextIO, level: int) -> None: def _dump_item(cls, name: str | None, attr: object, f: TextIO, level: int) -> None:
"""Write a group, dict or sequence item to f, where attr can be a scalar or a collection""" """Write a group, dict or sequence item to f, where attr can be a scalar or a collection"""
# lazy construction of yaml Dumper to avoid loading Utils early # lazy construction of yaml Dumper to avoid loading Utils early
@@ -223,7 +224,7 @@ class Group:
def represent_mapping(self, tag: str, mapping: Any, flow_style: Any = None) -> MappingNode: def represent_mapping(self, tag: str, mapping: Any, flow_style: Any = None) -> MappingNode:
from yaml import ScalarNode from yaml import ScalarNode
res: MappingNode = super().represent_mapping(tag, mapping, flow_style) res: MappingNode = super().represent_mapping(tag, mapping, flow_style)
pairs = cast(List[Tuple[ScalarNode, Any]], res.value) pairs = cast(list[tuple[ScalarNode, Any]], res.value)
for k, v in pairs: for k, v in pairs:
k.style = None # remove quotes from keys k.style = None # remove quotes from keys
return res return res
@@ -329,9 +330,9 @@ class Path(str):
"""Marks the file as required and opens a file browser when missing""" """Marks the file as required and opens a file browser when missing"""
is_exe: bool = False is_exe: bool = False
"""Special cross-platform handling for executables""" """Special cross-platform handling for executables"""
description: Optional[str] = None description: str | None = None
"""Title to display when browsing for the file""" """Title to display when browsing for the file"""
copy_to: Optional[str] = None copy_to: str | None = None
"""If not None, copy to AP folder instead of linking it""" """If not None, copy to AP folder instead of linking it"""
@classmethod @classmethod
@@ -339,7 +340,7 @@ class Path(str):
"""Overload and raise to validate input files from browse""" """Overload and raise to validate input files from browse"""
pass pass
def browse(self: T, **kwargs: Any) -> Optional[T]: def browse(self: T, **kwargs: Any) -> T | None:
"""Opens a file browser to search for the file""" """Opens a file browser to search for the file"""
raise NotImplementedError(f"Please use a subclass of Path for {self.__class__.__name__}") raise NotImplementedError(f"Please use a subclass of Path for {self.__class__.__name__}")
@@ -369,12 +370,12 @@ class _LocalPath(str):
class FilePath(Path): class FilePath(Path):
# path to a file # path to a file
md5s: ClassVar[List[Union[str, bytes]]] = [] md5s: ClassVar[list[str | bytes]] = []
"""MD5 hashes for default validator.""" """MD5 hashes for default validator."""
def browse(self: T, def browse(self: T,
filetypes: Optional[typing.Sequence[typing.Tuple[str, typing.Sequence[str]]]] = None, **kwargs: Any)\ filetypes: Sequence[tuple[str, Sequence[str]]] | None = None, **kwargs: Any)\
-> Optional[T]: -> T | None:
from Utils import open_filename, is_windows from Utils import open_filename, is_windows
if not filetypes: if not filetypes:
if self.is_exe: if self.is_exe:
@@ -439,7 +440,7 @@ class FilePath(Path):
class FolderPath(Path): class FolderPath(Path):
# path to a folder # path to a folder
def browse(self: T, **kwargs: Any) -> Optional[T]: def browse(self: T, **kwargs: Any) -> T | None:
from Utils import open_directory from Utils import open_directory
res = open_directory(f"Select {self.description or self.__class__.__name__}", self) res = open_directory(f"Select {self.description or self.__class__.__name__}", self)
if res: if res:
@@ -597,16 +598,16 @@ class ServerOptions(Group):
OFF = 0 OFF = 0
ON = 1 ON = 1
host: Optional[str] = None host: str | None = None
port: int = 38281 port: int = 38281
password: Optional[str] = None password: str | None = None
multidata: Optional[str] = None multidata: str | None = None
savefile: Optional[str] = None savefile: str | None = None
disable_save: bool = False disable_save: bool = False
loglevel: str = "info" loglevel: str = "info"
logtime: bool = False logtime: bool = False
server_password: Optional[ServerPassword] = None server_password: ServerPassword | None = None
disable_item_cheat: Union[DisableItemCheat, bool] = False disable_item_cheat: DisableItemCheat | bool = False
location_check_points: LocationCheckPoints = LocationCheckPoints(1) location_check_points: LocationCheckPoints = LocationCheckPoints(1)
hint_cost: HintCost = HintCost(10) hint_cost: HintCost = HintCost(10)
release_mode: ReleaseMode = ReleaseMode("auto") release_mode: ReleaseMode = ReleaseMode("auto")
@@ -702,7 +703,7 @@ does nothing if not found
""" """
sni_path: SNIPath = SNIPath("SNI") sni_path: SNIPath = SNIPath("SNI")
snes_rom_start: Union[SnesRomStart, bool] = True snes_rom_start: SnesRomStart | bool = True
class BizHawkClientOptions(Group): class BizHawkClientOptions(Group):
@@ -721,7 +722,7 @@ class BizHawkClientOptions(Group):
""" """
emuhawk_path: EmuHawkPath = EmuHawkPath(None) emuhawk_path: EmuHawkPath = EmuHawkPath(None)
rom_start: Union[RomStart, bool] = True rom_start: RomStart | bool = True
# Top-level group with lazy loading of worlds # Top-level group with lazy loading of worlds
@@ -733,7 +734,7 @@ class Settings(Group):
sni_options: SNIOptions = SNIOptions() sni_options: SNIOptions = SNIOptions()
bizhawkclient_options: BizHawkClientOptions = BizHawkClientOptions() bizhawkclient_options: BizHawkClientOptions = BizHawkClientOptions()
_filename: Optional[str] = None _filename: str | None = None
def __getattribute__(self, key: str) -> Any: def __getattribute__(self, key: str) -> Any:
if key.startswith("_") or key in self.__class__.__dict__: if key.startswith("_") or key in self.__class__.__dict__:
@@ -787,7 +788,7 @@ class Settings(Group):
return super().__getattribute__(key) return super().__getattribute__(key)
def __init__(self, location: Optional[str]): # change to PathLike[str] once we drop 3.8? def __init__(self, location: str | None): # change to PathLike[str] once we drop 3.8?
super().__init__() super().__init__()
if location: if location:
from Utils import parse_yaml from Utils import parse_yaml
@@ -821,7 +822,7 @@ class Settings(Group):
import atexit import atexit
atexit.register(autosave) atexit.register(autosave)
def save(self, location: Optional[str] = None) -> None: # as above def save(self, location: str | None = None) -> None: # as above
from Utils import parse_yaml from Utils import parse_yaml
location = location or self._filename location = location or self._filename
assert location, "No file specified" assert location, "No file specified"
@@ -854,7 +855,7 @@ class Settings(Group):
super().dump(f, level) super().dump(f, level)
@property @property
def filename(self) -> Optional[str]: def filename(self) -> str | None:
return self._filename return self._filename
@@ -867,7 +868,7 @@ def get_settings() -> Settings:
if not res: if not res:
from Utils import user_path, local_path from Utils import user_path, local_path
filenames = ("options.yaml", "host.yaml") filenames = ("options.yaml", "host.yaml")
locations: List[str] = [] locations: list[str] = []
if os.path.join(os.getcwd()) != local_path(): if os.path.join(os.getcwd()) != local_path():
locations += filenames # use files from cwd only if it's not the local_path locations += filenames # use files from cwd only if it's not the local_path
locations += [user_path(filename) for filename in filenames] locations += [user_path(filename) for filename in filenames]

View File

@@ -1,22 +1,20 @@
import base64 import base64
import datetime import datetime
import io
import json
import os import os
import platform import platform
import shutil import shutil
import subprocess
import sys import sys
import sysconfig import sysconfig
import threading
import urllib.request
import warnings import warnings
import zipfile import zipfile
import urllib.request from collections.abc import Iterable, Sequence
import io
import json
import threading
import subprocess
from hashlib import sha3_512 from hashlib import sha3_512
from pathlib import Path from pathlib import Path
from typing import Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union
# This is a bit jank. We need cx-Freeze to be able to run anything from this script, so install it # This is a bit jank. We need cx-Freeze to be able to run anything from this script, so install it
requirement = 'cx-Freeze==8.0.0' requirement = 'cx-Freeze==8.0.0'
@@ -60,7 +58,7 @@ from Cython.Build import cythonize
# On Python < 3.10 LogicMixin is not currently supported. # On Python < 3.10 LogicMixin is not currently supported.
non_apworlds: Set[str] = { non_apworlds: set[str] = {
"A Link to the Past", "A Link to the Past",
"Adventure", "Adventure",
"ArchipIDLE", "ArchipIDLE",
@@ -147,7 +145,7 @@ def download_SNI() -> None:
print(f"No SNI found for system spec {platform_name} {machine_name}") print(f"No SNI found for system spec {platform_name} {machine_name}")
signtool: Optional[str] signtool: str | None
if os.path.exists("X:/pw.txt"): if os.path.exists("X:/pw.txt"):
print("Using signtool") print("Using signtool")
with open("X:/pw.txt", encoding="utf-8-sig") as f: with open("X:/pw.txt", encoding="utf-8-sig") as f:
@@ -205,7 +203,7 @@ def remove_sprites_from_folder(folder: Path) -> None:
os.remove(folder / file) os.remove(folder / file)
def _threaded_hash(filepath: Union[str, Path]) -> str: def _threaded_hash(filepath: str | Path) -> str:
hasher = sha3_512() hasher = sha3_512()
hasher.update(open(filepath, "rb").read()) hasher.update(open(filepath, "rb").read())
return base64.b85encode(hasher.digest()).decode() return base64.b85encode(hasher.digest()).decode()
@@ -255,7 +253,7 @@ class BuildExeCommand(cx_Freeze.command.build_exe.build_exe):
self.libfolder = Path(self.buildfolder, "lib") self.libfolder = Path(self.buildfolder, "lib")
self.library = Path(self.libfolder, "library.zip") self.library = Path(self.libfolder, "library.zip")
def installfile(self, path: Path, subpath: Optional[Union[str, Path]] = None, keep_content: bool = False) -> None: def installfile(self, path: Path, subpath: str | Path | None = None, keep_content: bool = False) -> None:
folder = self.buildfolder folder = self.buildfolder
if subpath: if subpath:
folder /= subpath folder /= subpath
@@ -374,7 +372,7 @@ class BuildExeCommand(cx_Freeze.command.build_exe.build_exe):
from worlds.AutoWorld import AutoWorldRegister from worlds.AutoWorld import AutoWorldRegister
assert not non_apworlds - set(AutoWorldRegister.world_types), \ assert not non_apworlds - set(AutoWorldRegister.world_types), \
f"Unknown world {non_apworlds - set(AutoWorldRegister.world_types)} designated for .apworld" f"Unknown world {non_apworlds - set(AutoWorldRegister.world_types)} designated for .apworld"
folders_to_remove: List[str] = [] folders_to_remove: list[str] = []
disabled_worlds_folder = "worlds_disabled" disabled_worlds_folder = "worlds_disabled"
for entry in os.listdir(disabled_worlds_folder): for entry in os.listdir(disabled_worlds_folder):
if os.path.isdir(os.path.join(disabled_worlds_folder, entry)): if os.path.isdir(os.path.join(disabled_worlds_folder, entry)):
@@ -446,12 +444,12 @@ class AppImageCommand(setuptools.Command):
("app-exec=", None, "The application to run inside the image."), ("app-exec=", None, "The application to run inside the image."),
("yes", "y", 'Answer "yes" to all questions.'), ("yes", "y", 'Answer "yes" to all questions.'),
] ]
build_folder: Optional[Path] build_folder: Path | None
dist_file: Optional[Path] dist_file: Path | None
app_dir: Optional[Path] app_dir: Path | None
app_name: str app_name: str
app_exec: Optional[Path] app_exec: Path | None
app_icon: Optional[Path] # source file app_icon: Path | None # source file
app_id: str # lower case name, used for icon and .desktop app_id: str # lower case name, used for icon and .desktop
yes: bool yes: bool
@@ -493,7 +491,7 @@ $APPDIR/$exe "$@"
""") """)
launcher_filename.chmod(0o755) launcher_filename.chmod(0o755)
def install_icon(self, src: Path, name: Optional[str] = None, symlink: Optional[Path] = None) -> None: def install_icon(self, src: Path, name: str | None = None, symlink: Path | None = None) -> None:
assert self.app_dir, "Invalid app_dir" assert self.app_dir, "Invalid app_dir"
try: try:
from PIL import Image from PIL import Image
@@ -556,7 +554,7 @@ $APPDIR/$exe "$@"
subprocess.call(f'ARCH={build_arch} ./appimagetool -n "{self.app_dir}" "{self.dist_file}"', shell=True) subprocess.call(f'ARCH={build_arch} ./appimagetool -n "{self.app_dir}" "{self.dist_file}"', shell=True)
def find_libs(*args: str) -> Sequence[Tuple[str, str]]: def find_libs(*args: str) -> Sequence[tuple[str, str]]:
"""Try to find system libraries to be included.""" """Try to find system libraries to be included."""
if not args: if not args:
return [] return []
@@ -564,7 +562,7 @@ def find_libs(*args: str) -> Sequence[Tuple[str, str]]:
arch = build_arch.replace('_', '-') arch = build_arch.replace('_', '-')
libc = 'libc6' # we currently don't support musl libc = 'libc6' # we currently don't support musl
def parse(line: str) -> Tuple[Tuple[str, str, str], str]: def parse(line: str) -> tuple[tuple[str, str, str], str]:
lib, path = line.strip().split(' => ') lib, path = line.strip().split(' => ')
lib, typ = lib.split(' ', 1) lib, typ = lib.split(' ', 1)
for test_arch in ('x86-64', 'i386', 'aarch64'): for test_arch in ('x86-64', 'i386', 'aarch64'):
@@ -589,8 +587,8 @@ def find_libs(*args: str) -> Sequence[Tuple[str, str]]:
k: v for k, v in (parse(line) for line in data if "=>" in line) k: v for k, v in (parse(line) for line in data if "=>" in line)
} }
def find_lib(lib: str, arch: str, libc: str) -> Optional[str]: def find_lib(lib: str, arch: str, libc: str) -> str | None:
cache: Dict[Tuple[str, str, str], str] = getattr(find_libs, "cache") cache: dict[tuple[str, str, str], str] = getattr(find_libs, "cache")
for k, v in cache.items(): for k, v in cache.items():
if k == (lib, arch, libc): if k == (lib, arch, libc):
return v return v
@@ -599,7 +597,7 @@ def find_libs(*args: str) -> Sequence[Tuple[str, str]]:
return v return v
return None return None
res: List[Tuple[str, str]] = [] res: list[tuple[str, str]] = []
for arg in args: for arg in args:
# try exact match, empty libc, empty arch, empty arch and libc # try exact match, empty libc, empty arch, empty arch and libc
file = find_lib(arg, arch, libc) file = find_lib(arg, arch, libc)

View File

@@ -1,13 +1,12 @@
import re import re
import shutil import shutil
from pathlib import Path from pathlib import Path
from typing import Dict
__all__ = ["copy", "delete"] __all__ = ["copy", "delete"]
_new_worlds: Dict[str, str] = {} _new_worlds: dict[str, str] = {}
def copy(src: str, dst: str) -> None: def copy(src: str, dst: str) -> None: