Locations with decorators

This commit is contained in:
GeoffreyCoulaud
2023-05-01 22:46:18 +02:00
parent 0abb7d3df9
commit 451fde8a91
4 changed files with 67 additions and 75 deletions

View 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

View File

@@ -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

View File

@@ -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""" """Source of games. Can be a program location on disk with a config file that points to game for example"""
win = None win = None
schema_keys: dict
name: str name: str
variant: str variant: str
@@ -36,11 +35,6 @@ class Source(Iterable):
def __init__(self, win) -> None: def __init__(self, win) -> None:
super().__init__() super().__init__()
self.win = win self.win = win
self.__init_schema_keys__()
def __init_schema_keys__(self):
"""Initialize schema keys needed by the source if necessary"""
raise NotImplementedError()
@property @property
def full_name(self): def full_name(self):
@@ -61,9 +55,4 @@ class Source(Iterable):
def __iter__(self): def __iter__(self):
"""Get the source's iterator, to use in for loops""" """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() raise NotImplementedError()

View File

@@ -1,10 +1,9 @@
from pathlib import Path
from functools import cached_property from functools import cached_property
from sqlite3 import connect from sqlite3 import connect
from cartridges.game2 import Game from cartridges.game2 import Game
from cartridges.importer.source import Source, SourceIterator 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): class LutrisSourceIterator(SourceIterator):
@@ -73,50 +72,48 @@ class LutrisSource(Source):
name = "Lutris" name = "Lutris"
executable_format = "xdg-open lutris:rungameid/{game_id}" executable_format = "xdg-open lutris:rungameid/{game_id}"
schema_keys = {
"location": None, location = None
"cache_location": None cache_location = None
}
def __init__(self, win) -> None: def __init__(self, win) -> None:
super().__init__(win) super().__init__(win)
self.location = Location()
self.cache_location = Location()
def __iter__(self): def __iter__(self):
return LutrisSourceIterator(source=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 LutrisNativeSource(LutrisSource):
"""Class representing an installation of Lutris using native packaging""" """Class representing an installation of Lutris using native packaging"""
variant = "native" variant = "native"
schema_keys = {
"location": "lutris-location",
"cache_location": "lutris-cache-location"
}
def __init_locations__(self): @cached_property
super().__init_locations__() @replaced_by_schema_key("lutris-location")
self.location.add("~/.local/share/lutris/") @replaced_by_path("~/.local/share/lutris/")
self.cache_location.add("~/.local/share/lutris/covers") 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 LutrisFlatpakSource(LutrisSource):
"""Class representing an installation of Lutris using flatpak""" """Class representing an installation of Lutris using flatpak"""
variant = "flatpak" variant = "flatpak"
schema_keys = {
"location": "lutris-flatpak-location",
"cache_location": "lutris-flatpak-cache-location"
}
def __init_locations__(self): @cached_property
super().__init_locations__() @replaced_by_schema_key("lutris-flatpak-location")
self.location.add("~/.var/app/net.lutris.Lutris/data/lutris") @replaced_by_path("~/.var/app/net.lutris.Lutris/data/lutris")
self.cache_location.add("~/.var/app/net.lutris.Lutris/data/lutris/covers") 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()