Skip to content

Commit

Permalink
AppImage: allow loading apworlds from ~/Archipelago and copy scripts (A…
Browse files Browse the repository at this point in the history
…rchipelagoMW#2358)

also fixes some mypy and flake8 violations in worlds/__init__.py
  • Loading branch information
black-sliver authored Nov 4, 2023
1 parent 880326c commit d2e9bfb
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 22 deletions.
10 changes: 7 additions & 3 deletions Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,16 @@ def user_path(*path: str) -> str:
if user_path.cached_path != local_path():
import filecmp
if not os.path.exists(user_path("manifest.json")) or \
not os.path.exists(local_path("manifest.json")) or \
not filecmp.cmp(local_path("manifest.json"), user_path("manifest.json"), shallow=True):
import shutil
for dn in ("Players", "data/sprites"):
for dn in ("Players", "data/sprites", "data/lua"):
shutil.copytree(local_path(dn), user_path(dn), dirs_exist_ok=True)
for fn in ("manifest.json",):
shutil.copy2(local_path(fn), user_path(fn))
if not os.path.exists(local_path("manifest.json")):
warnings.warn(f"Upgrading {user_path()} from something that is not a proper install")
else:
shutil.copy2(local_path("manifest.json"), user_path("manifest.json"))
os.makedirs(user_path("worlds"), exist_ok=True)

return os.path.join(user_path.cached_path, *path)

Expand Down
42 changes: 23 additions & 19 deletions worlds/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@
import warnings
import zipimport

folder = os.path.dirname(__file__)
from Utils import user_path, local_path

__all__ = {
local_folder = os.path.dirname(__file__)
user_folder = user_path("worlds") if user_path() != local_path() else None

__all__ = (
"lookup_any_item_id_to_name",
"lookup_any_location_id_to_name",
"network_data_package",
"AutoWorldRegister",
"world_sources",
"folder",
}

if typing.TYPE_CHECKING:
from .AutoWorld import World
"local_folder",
"user_folder",
)


class GamesData(typing.TypedDict):
Expand All @@ -41,13 +42,13 @@ class WorldSource(typing.NamedTuple):
is_zip: bool = False
relative: bool = True # relative to regular world import folder

def __repr__(self):
def __repr__(self) -> str:
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 os.path.join(local_folder, self.path)
return self.path

def load(self) -> bool:
Expand All @@ -56,6 +57,7 @@ def load(self) -> bool:
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])
assert spec, f"{self.path} is not a loadable module"
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])
Expand All @@ -72,7 +74,7 @@ def load(self) -> bool:
importlib.import_module(f".{self.path}", "worlds")
return True

except Exception as e:
except Exception:
# A single world failing can still mean enough is working for the user, log and carry on
import traceback
import io
Expand All @@ -87,14 +89,16 @@ def load(self) -> bool:

# find potential world containers, currently folders and zip-importable .apworld's
world_sources: typing.List[WorldSource] = []
file: os.DirEntry # for me (Berserker) at least, PyCharm doesn't seem to infer the type correctly
for file in os.scandir(folder):
# prevent loading of __pycache__ and allow _* for non-world folders, disable files/folders starting with "."
if not file.name.startswith(("_", ".")):
if file.is_dir():
world_sources.append(WorldSource(file.name))
elif file.is_file() and file.name.endswith(".apworld"):
world_sources.append(WorldSource(file.name, is_zip=True))
for folder in (folder for folder in (user_folder, local_folder) if folder):
relative = folder == local_folder
for entry in os.scandir(folder):
# prevent loading of __pycache__ and allow _* for non-world folders, disable files/folders starting with "."
if not entry.name.startswith(("_", ".")):
file_name = entry.name if relative else os.path.join(folder, entry.name)
if entry.is_dir():
world_sources.append(WorldSource(file_name, relative=relative))
elif entry.is_file() and entry.name.endswith(".apworld"):
world_sources.append(WorldSource(file_name, is_zip=True, relative=relative))

# import all submodules to trigger AutoWorldRegister
world_sources.sort()
Expand All @@ -105,7 +109,7 @@ def load(self) -> bool:
lookup_any_location_id_to_name = {}
games: typing.Dict[str, GamesPackage] = {}

from .AutoWorld import AutoWorldRegister
from .AutoWorld import AutoWorldRegister # noqa: E402

# Build the data package for each game.
for world_name, world in AutoWorldRegister.world_types.items():
Expand Down

0 comments on commit d2e9bfb

Please sign in to comment.