Core: refactor some loading mechanisms ()

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
This commit is contained in:
Fabian Dill 2023-06-20 01:01:18 +02:00 committed by GitHub
parent 25f285b242
commit 61fc80505e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 37 deletions

View File

@ -11,6 +11,7 @@ Scroll down to components= to add components to the launcher as well as setup.py
import argparse
import itertools
import logging
import multiprocessing
import shlex
import subprocess
@ -55,7 +56,7 @@ def open_patch():
except Exception as e:
messagebox('Error', str(e), error=True)
else:
file, _, component = identify(filename)
file, component = identify(filename)
if file and component:
launch([*get_exe(component), file], component.cli)
@ -96,11 +97,13 @@ components.extend([
def identify(path: Union[None, str]):
if path is None:
return None, None, None
return None, None
for component in components:
if component.handles_file(path):
return path, component.script_name, component
return (None, None, None) if '/' in path or '\\' in path else (None, path, None)
return path, component
elif path == component.display_name or path == component.script_name:
return None, component
return None, None
def get_exe(component: Union[str, Component]) -> Optional[Sequence[str]]:
@ -223,6 +226,15 @@ def run_gui():
Launcher().run()
def run_component(component: Component, *args):
if component.func:
component.func(*args)
elif component.script_name:
subprocess.run([*get_exe(component.script_name), *args])
else:
logging.warning(f"Component {component} does not appear to be executable.")
def main(args: Optional[Union[argparse.Namespace, dict]] = None):
if isinstance(args, argparse.Namespace):
args = {k: v for k, v in args._get_kwargs()}
@ -230,16 +242,18 @@ def main(args: Optional[Union[argparse.Namespace, dict]] = None):
args = {}
if "Patch|Game|Component" in args:
file, component, _ = identify(args["Patch|Game|Component"])
file, component = identify(args["Patch|Game|Component"])
if file:
args['file'] = file
if component:
args['component'] = component
if not component:
logging.warning(f"Could not identify Component responsible for {args['Patch|Game|Component']}")
if 'file' in args:
subprocess.run([*get_exe(args['component']), args['file'], *args['args']])
run_component(args["component"], args["file"], *args["args"])
elif 'component' in args:
subprocess.run([*get_exe(args['component']), *args['args']])
run_component(args["component"], *args["args"])
else:
run_gui()

View File

@ -39,9 +39,50 @@ class DataPackage(typing.TypedDict):
class WorldSource(typing.NamedTuple):
path: str # typically relative path from this module
is_zip: bool = False
relative: bool = True # relative to regular world import folder
def __repr__(self):
return f"{self.__class__.__name__}({self.path}, is_zip={self.is_zip})"
return f"{self.__class__.__name__}({self.path}, is_zip={self.is_zip}, relative={self.relative})"
@property
def resolved_path(self) -> str:
if self.relative:
return os.path.join(folder, self.path)
return self.path
def load(self) -> bool:
try:
if self.is_zip:
importer = zipimport.zipimporter(self.resolved_path)
if hasattr(importer, "find_spec"): # new in Python 3.10
spec = importer.find_spec(os.path.basename(self.path).rsplit(".", 1)[0])
mod = importlib.util.module_from_spec(spec)
else: # TODO: remove with 3.8 support
mod = importer.load_module(os.path.basename(self.path).rsplit(".", 1)[0])
mod.__package__ = f"worlds.{mod.__package__}"
mod.__name__ = f"worlds.{mod.__name__}"
sys.modules[mod.__name__] = mod
with warnings.catch_warnings():
warnings.filterwarnings("ignore", message="__package__ != __spec__.parent")
# Found no equivalent for < 3.10
if hasattr(importer, "exec_module"):
importer.exec_module(mod)
else:
importlib.import_module(f".{self.path}", "worlds")
return True
except Exception as e:
# A single world failing can still mean enough is working for the user, log and carry on
import traceback
import io
file_like = io.StringIO()
print(f"Could not load world {self}:", file=file_like)
traceback.print_exc(file=file_like)
file_like.seek(0)
import logging
logging.exception(file_like.read())
return False
# find potential world containers, currently folders and zip-importable .apworld's
@ -58,35 +99,7 @@ for file in os.scandir(folder):
# import all submodules to trigger AutoWorldRegister
world_sources.sort()
for world_source in world_sources:
try:
if world_source.is_zip:
importer = zipimport.zipimporter(os.path.join(folder, world_source.path))
if hasattr(importer, "find_spec"): # new in Python 3.10
spec = importer.find_spec(world_source.path.split(".", 1)[0])
mod = importlib.util.module_from_spec(spec)
else: # TODO: remove with 3.8 support
mod = importer.load_module(world_source.path.split(".", 1)[0])
mod.__package__ = f"worlds.{mod.__package__}"
mod.__name__ = f"worlds.{mod.__name__}"
sys.modules[mod.__name__] = mod
with warnings.catch_warnings():
warnings.filterwarnings("ignore", message="__package__ != __spec__.parent")
# Found no equivalent for < 3.10
if hasattr(importer, "exec_module"):
importer.exec_module(mod)
else:
importlib.import_module(f".{world_source.path}", "worlds")
except Exception as e:
# A single world failing can still mean enough is working for the user, log and carry on
import traceback
import io
file_like = io.StringIO()
print(f"Could not load world {world_source}:", file=file_like)
traceback.print_exc(file=file_like)
file_like.seek(0)
import logging
logging.exception(file_like.read())
world_source.load()
lookup_any_item_id_to_name = {}
lookup_any_location_id_to_name = {}