Locations with decorators
This commit is contained in:
41
src/importer/decorators.py
Normal file
41
src/importer/decorators.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""
|
||||
A decorator takes a callable A and returns a callable B that will override the name of A.
|
||||
A decorator with arguments returns a closure decorator having access to the arguments.
|
||||
|
||||
Example usage for the location decorators:
|
||||
|
||||
class MyClass():
|
||||
@cached_property
|
||||
@replaced_by_schema_key(key="source-location")
|
||||
@replaced_by_path(override="/somewhere/that/doesnt/exist")
|
||||
@replaced_by_path(override="/somewhere/that/exists")
|
||||
def location(self):
|
||||
return None
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from os import PathLike
|
||||
from functools import wraps
|
||||
|
||||
def replaced_by_path(path: PathLike): # Decorator builder
|
||||
"""Replace the method's returned path with the override if the override exists on disk"""
|
||||
def decorator(original_function): # Built decorator (closure)
|
||||
@wraps(original_function)
|
||||
def wrapper(*args, **kwargs): # func's override
|
||||
p = Path(path).expanduser()
|
||||
if p.exists(): return p
|
||||
else: return original_function(*args, **kwargs)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
def replaced_by_schema_key(key: str): # Decorator builder
|
||||
"""Replace the method's returned path with the path pointed by the key if it exists on disk"""
|
||||
def decorator(original_function): # Built decorator (closure)
|
||||
@wraps(original_function)
|
||||
def wrapper(*args, **kwargs): # func's override
|
||||
schema = args[0].win.schema
|
||||
try: override = schema.get_string(key)
|
||||
except Exception: return original_function(*args, **kwargs)
|
||||
else: return replaced_by_path(override)(*args, **kwargs)
|
||||
return wrapper
|
||||
return decorator
|
||||
@@ -1,35 +0,0 @@
|
||||
from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
from pathlib import Path
|
||||
from os import PathLike
|
||||
|
||||
|
||||
@dataclass
|
||||
class Location():
|
||||
"""Abstraction for a location that has multiple candidate paths"""
|
||||
|
||||
candidates: list[PathLike] = None
|
||||
|
||||
def __init__(self, *candidates):
|
||||
self.candidates = list()
|
||||
self.candidates.extend(candidates)
|
||||
return self
|
||||
|
||||
def add(self, canddiate):
|
||||
"""Add a candidate (last evaluated)"""
|
||||
self.candidates.append(canddiate)
|
||||
return self
|
||||
|
||||
def add_override(self, candidate):
|
||||
"""Add a canddiate (first evaluated)"""
|
||||
self.candidates.insert(0, candidate)
|
||||
return self
|
||||
|
||||
@cached_property
|
||||
def path(self):
|
||||
"""Chosen path depending on availability on the disk."""
|
||||
for candidate in self.candidates:
|
||||
p = Path(candidate).expanduser()
|
||||
if p.exists:
|
||||
return p
|
||||
return None
|
||||
@@ -27,7 +27,6 @@ class Source(Iterable):
|
||||
"""Source of games. Can be a program location on disk with a config file that points to game for example"""
|
||||
|
||||
win = None
|
||||
schema_keys: dict
|
||||
|
||||
name: str
|
||||
variant: str
|
||||
@@ -36,11 +35,6 @@ class Source(Iterable):
|
||||
def __init__(self, win) -> None:
|
||||
super().__init__()
|
||||
self.win = win
|
||||
self.__init_schema_keys__()
|
||||
|
||||
def __init_schema_keys__(self):
|
||||
"""Initialize schema keys needed by the source if necessary"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def full_name(self):
|
||||
@@ -62,8 +56,3 @@ class Source(Iterable):
|
||||
def __iter__(self):
|
||||
"""Get the source's iterator, to use in for loops"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def __init_locations__(self):
|
||||
"""Initialize locations needed by the source.
|
||||
Extended and called by **final** children."""
|
||||
raise NotImplementedError()
|
||||
@@ -1,10 +1,9 @@
|
||||
from pathlib import Path
|
||||
from functools import cached_property
|
||||
from sqlite3 import connect
|
||||
|
||||
from cartridges.game2 import Game
|
||||
from cartridges.importer.source import Source, SourceIterator
|
||||
from cartridges.importer.location import Location
|
||||
from cartridges.importer.decorators import replaced_by_schema_key, replaced_by_path
|
||||
|
||||
|
||||
class LutrisSourceIterator(SourceIterator):
|
||||
@@ -73,50 +72,48 @@ class LutrisSource(Source):
|
||||
|
||||
name = "Lutris"
|
||||
executable_format = "xdg-open lutris:rungameid/{game_id}"
|
||||
schema_keys = {
|
||||
"location": None,
|
||||
"cache_location": None
|
||||
}
|
||||
|
||||
location = None
|
||||
cache_location = None
|
||||
|
||||
def __init__(self, win) -> None:
|
||||
super().__init__(win)
|
||||
self.location = Location()
|
||||
self.cache_location = Location()
|
||||
|
||||
def __iter__(self):
|
||||
return LutrisSourceIterator(source=self)
|
||||
|
||||
def __init_locations__(self):
|
||||
super().__init_locations__()
|
||||
self.location.add_override(self.win.schema.get_string(self.schema_keys["location"]))
|
||||
self.cache_location.add_override(self.win.schema.get_string(self.schema_keys["cache_location"]))
|
||||
|
||||
|
||||
class LutrisNativeSource(LutrisSource):
|
||||
"""Class representing an installation of Lutris using native packaging"""
|
||||
|
||||
variant = "native"
|
||||
schema_keys = {
|
||||
"location": "lutris-location",
|
||||
"cache_location": "lutris-cache-location"
|
||||
}
|
||||
|
||||
def __init_locations__(self):
|
||||
super().__init_locations__()
|
||||
self.location.add("~/.local/share/lutris/")
|
||||
self.cache_location.add("~/.local/share/lutris/covers")
|
||||
@cached_property
|
||||
@replaced_by_schema_key("lutris-location")
|
||||
@replaced_by_path("~/.local/share/lutris/")
|
||||
def location(self):
|
||||
raise FileNotFoundError()
|
||||
|
||||
@cached_property
|
||||
@replaced_by_schema_key("lutris-cache-location")
|
||||
@replaced_by_path("~/.local/share/lutris/covers")
|
||||
def cache_location(self):
|
||||
raise FileNotFoundError()
|
||||
|
||||
|
||||
class LutrisFlatpakSource(LutrisSource):
|
||||
"""Class representing an installation of Lutris using flatpak"""
|
||||
|
||||
variant = "flatpak"
|
||||
schema_keys = {
|
||||
"location": "lutris-flatpak-location",
|
||||
"cache_location": "lutris-flatpak-cache-location"
|
||||
}
|
||||
|
||||
def __init_locations__(self):
|
||||
super().__init_locations__()
|
||||
self.location.add("~/.var/app/net.lutris.Lutris/data/lutris")
|
||||
self.cache_location.add("~/.var/app/net.lutris.Lutris/data/lutris/covers")
|
||||
@cached_property
|
||||
@replaced_by_schema_key("lutris-flatpak-location")
|
||||
@replaced_by_path("~/.var/app/net.lutris.Lutris/data/lutris")
|
||||
def location(self):
|
||||
raise FileNotFoundError()
|
||||
|
||||
@cached_property
|
||||
@replaced_by_schema_key("lutris-flatpak-cache-location")
|
||||
@replaced_by_path("~/.var/app/net.lutris.Lutris/data/lutris/covers")
|
||||
def cache_location(self):
|
||||
raise FileNotFoundError()
|
||||
Reference in New Issue
Block a user