Skip to content

Instantly share code, notes, and snippets.

@etherealite
Created September 14, 2024 10:53
Show Gist options
  • Select an option

  • Save etherealite/fc47e0582fa798ecbdd344ed42b4a0bb to your computer and use it in GitHub Desktop.

Select an option

Save etherealite/fc47e0582fa798ecbdd344ed42b4a0bb to your computer and use it in GitHub Desktop.
"""
App configuration.
"""
import os
import yaml
from dataclasses import dataclass, field
from platformdirs import PlatformDirs
@dataclass(frozen=True)
class AppConfig:
"""
Configuration wrapper around yaml file.
Adds various properties for lint-time checking.
"""
env: str
is_docker: bool
dbname: str
is_test_db: bool
datapath: str
plugin_datapath: str
userimagespath: str
useraudiopath: str
userthemespath: str
temppath: str
dbfilename: str
system_backup_path: str
default_user_backup_path: str
sqliteconnstring: str
@staticmethod
def _get_appdata_dir():
"Get user's appdata directory from platformdirs."
dirs = PlatformDirs("Lute3", "Lute3")
return dirs.user_data_dir
@staticmethod
def configdir():
"Return the path to the configuration file directory."
return os.path.dirname(os.path.realpath(__file__))
@staticmethod
def default_config_filename():
"Return the path to the default configuration file."
thisdir = AppConfig.configdir()
return os.path.join(thisdir, "config.yml")
@classmethod
def factory(cls, env, is_docker, dbname, datapath, default_user_backup_path):
if env not in ["prod", "dev"]:
raise ValueError(f"ENV must be prod or dev, was {env}.")
if dbname is None:
raise ValueError("Config file must have 'DBNAME'")
plugin_datapath = os.path.join(datapath, "plugins")
userimagespath = os.path.join(datapath, "userimages")
useraudiopath = os.path.join(datapath, "useraudio")
userthemespath = os.path.join(datapath, "userthemes")
temppath = os.path.join(datapath, "temp")
dbfilename = os.path.join(datapath, dbname)
system_backup_path = os.path.join(datapath, ".system_db_backups")
is_test_db = dbname.startswith("test_")
if default_user_backup_path is None:
default_user_backup_path = os.path.join(datapath, "backups")
sqliteconnstring = f"sqlite:///{dbfilename}"
return cls(
env=env,
is_docker=is_docker,
dbname=dbname,
datapath=datapath,
default_user_backup_path=default_user_backup_path,
plugin_datapath=plugin_datapath,
userimagespath=userimagespath,
useraudiopath=useraudiopath,
userthemespath=userthemespath,
temppath=temppath,
dbfilename=dbfilename,
system_backup_path=system_backup_path,
is_test_db=is_test_db,
sqliteconnstring=sqliteconnstring,
)
@classmethod
def from_yml(cls, config_file_path):
"""
Load and validate the config file.
"""
with open(config_file_path, "r", encoding="utf-8") as cf:
config = yaml.safe_load(cf)
if not isinstance(config, dict):
raise RuntimeError(
f"File at {config_file_path} is invalid or is not a yaml dictionary."
)
return cls.factory(
env=config.get("ENV", None),
is_docker="IS_DOCKER" in config,
dbname=config.get("DBNAME", None),
datapath=config.get("DATAPATH", cls._get_appdata_dir()),
default_user_backup_path=config.get("BACKUP_PATH", None),
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment