forked from mirror/Archipelago
Core: Make .apworlds importable using importlib (without force-importing them first) (#5734)
* Make apworlds importable in general * move it to a probably more appropriate place? * oops
This commit is contained in:
@@ -1,14 +1,17 @@
|
|||||||
import importlib
|
import importlib
|
||||||
|
import importlib.abc
|
||||||
|
import importlib.machinery
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
|
||||||
import zipimport
|
import zipimport
|
||||||
import time
|
import time
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import json
|
import json
|
||||||
from typing import List
|
from pathlib import Path
|
||||||
|
from types import ModuleType
|
||||||
|
from typing import List, Sequence
|
||||||
|
|
||||||
from NetUtils import DataPackage
|
from NetUtils import DataPackage
|
||||||
from Utils import local_path, user_path, Version, version_tuple, tuplize_version
|
from Utils import local_path, user_path, Version, version_tuple, tuplize_version
|
||||||
@@ -53,21 +56,7 @@ class WorldSource:
|
|||||||
def load(self) -> bool:
|
def load(self) -> bool:
|
||||||
try:
|
try:
|
||||||
start = time.perf_counter()
|
start = time.perf_counter()
|
||||||
if self.is_zip:
|
importlib.import_module(f".{Path(self.path).stem}", "worlds")
|
||||||
importer = zipimport.zipimporter(self.resolved_path)
|
|
||||||
spec = importer.find_spec(os.path.basename(self.path).rsplit(".", 1)[0])
|
|
||||||
assert spec, f"{self.path} is not a loadable module"
|
|
||||||
mod = importlib.util.module_from_spec(spec)
|
|
||||||
|
|
||||||
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")
|
|
||||||
importer.exec_module(mod)
|
|
||||||
else:
|
|
||||||
importlib.import_module(f".{self.path}", "worlds")
|
|
||||||
self.time_taken = time.perf_counter()-start
|
self.time_taken = time.perf_counter()-start
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -112,7 +101,6 @@ for world_source in world_sources:
|
|||||||
else:
|
else:
|
||||||
world_source.load()
|
world_source.load()
|
||||||
|
|
||||||
|
|
||||||
from .AutoWorld import AutoWorldRegister
|
from .AutoWorld import AutoWorldRegister
|
||||||
|
|
||||||
for world_source in world_sources:
|
for world_source in world_sources:
|
||||||
@@ -174,6 +162,16 @@ if apworlds:
|
|||||||
core_compatible.sort(
|
core_compatible.sort(
|
||||||
key=lambda element: element[1].world_version if element[1].world_version else Version(0, 0, 0),
|
key=lambda element: element[1].world_version if element[1].world_version else Version(0, 0, 0),
|
||||||
reverse=True)
|
reverse=True)
|
||||||
|
|
||||||
|
apworld_module_specs = {}
|
||||||
|
class APWorldModuleFinder(importlib.abc.MetaPathFinder):
|
||||||
|
def find_spec(
|
||||||
|
self, fullname: str, _path: Sequence[str] | None, _target: ModuleType = None
|
||||||
|
) -> importlib.machinery.ModuleSpec | None:
|
||||||
|
return apworld_module_specs.get(fullname)
|
||||||
|
|
||||||
|
sys.meta_path.insert(0, APWorldModuleFinder())
|
||||||
|
|
||||||
for apworld_source, apworld in core_compatible:
|
for apworld_source, apworld in core_compatible:
|
||||||
if apworld.game and apworld.game in AutoWorldRegister.world_types:
|
if apworld.game and apworld.game in AutoWorldRegister.world_types:
|
||||||
fail_world(apworld.game,
|
fail_world(apworld.game,
|
||||||
@@ -181,6 +179,12 @@ if apworlds:
|
|||||||
f"as its game {apworld.game} is already loaded.",
|
f"as its game {apworld.game} is already loaded.",
|
||||||
add_as_failed_to_load=False)
|
add_as_failed_to_load=False)
|
||||||
else:
|
else:
|
||||||
|
importer = zipimport.zipimporter(apworld_source.resolved_path)
|
||||||
|
world_name = Path(apworld.path).stem
|
||||||
|
|
||||||
|
spec = importer.find_spec(f"worlds.{world_name}")
|
||||||
|
apworld_module_specs[f"worlds.{world_name}"] = spec
|
||||||
|
|
||||||
apworld_source.load()
|
apworld_source.load()
|
||||||
if apworld.game in AutoWorldRegister.world_types:
|
if apworld.game in AutoWorldRegister.world_types:
|
||||||
# world could fail to load at this point
|
# world could fail to load at this point
|
||||||
|
|||||||
Reference in New Issue
Block a user