from typing import Optional, Any from dataclasses import dataclass from omegaconf import OmegaConf, DictConfig import os from pathlib import Path @dataclass class OpenAI: api_key: str model: str def getattr(self, name: str): return getattr(self, name) def _setattr(self, name: str, value: Any): setattr(self, name, value) @dataclass class Zotero: api_key: str library_id: str library_type: str def getattr(self, name: str): return getattr(self, name) def _setattr(self, name: str, value: Any): setattr(self, name, value) @dataclass class Database: name: str path: str | Path temp: str | Path def getattr(self, name: str): return getattr(self, name) def _setattr(self, name: str, value: Any): setattr(self, name, value) def __post_init__(self): if isinstance(self.path, str): self.path = Path(self.path).expanduser() if isinstance(self.temp, str): self.temp = Path(self.temp).expanduser() @dataclass class Mail: smtp_server: str port: int sender: str password: str use_user_name: bool printer_mail: str user_name: str signature: str | None = None empty_signature = """


""" def getattr(self, name: str): return getattr(self, name) def _setattr(self, name: str, value: Any): setattr(self, name, value) def setValue(self, **kwargs: Any): for key, value in kwargs.items(): if hasattr(self, key): setattr(self, key, value) else: raise KeyError(f"Invalid option: {key}") class Icons: def __init__(self): self._path = None self._colors = None self._icons = None def assign(self, key: str, value: Any): setattr(self, key, value) @property def path(self): return self._path @path.setter def path(self, value: Any): self._path = value @property def colors(self): return self._colors @colors.setter def colors(self, value: Any): self._colors = value @property def icons(self): return self._icons @icons.setter def icons(self, value: Any): self._icons = value def get(self, name: str): return self.icons.get(name) class Config: """A class to handle the configuration of the application. After initializing, it will try to load the config file and store it for future access. Any changes made can be saved to the file using the .save() method. Changes are used in real time in the app, if a restart is required, the Application will show a window. Raises: RuntimeError: Configuration not loaded KeyError: Invalid option """ _config: Optional[DictConfig] = None config_exists: bool = True def __init__(self, config_path: str): """ Loads the configuration file and stores it for future access. Args: config_path (str): Path to the YAML configuration file. Raises: FileNotFoundError: Configuration file not found """ if not os.path.exists(config_path): # copy base config file to the given path base = "config/base_config.yaml" if not os.path.exists(base): raise FileNotFoundError(f"Base configuration file not found: {base}") with open(base, "r") as base_file: base_config = base_file.read() with open(config_path, "w") as config_file: config_file.write(base_config) self.config_exists = False self._config = OmegaConf.load(config_path) self.config_path = config_path @property def exists(self) -> bool: return self.config_exists def save(self): """ Saves the current configuration to the file. Args: config_path (str): Path to the YAML configuration file. """ OmegaConf.save(self._config, self.config_path) def reload(self): """ Reloads the configuration from the file. """ self._config = OmegaConf.load(self.config_path) @property def zotero(self): return Zotero(**self._config.zotero) @property def zotero_attr(self, name: str): return getattr(self.zotero, name) @zotero_attr.setter def zotero_attr(self, name: str, value: Any): self.zotero._setattr(name, value) @property def database(self): return Database(**self._config.database) @property def database_attr(self, name: str): return getattr(self.database, name) @database_attr.setter def database_attr(self, name: str, value: Any): self.database._setattr(name, value) @property def openAI(self): return OpenAI(**self._config.openAI) @property def mail(self): return Mail(**self._config.mail) def mail_attr(self, name: str): return getattr(self.mail, name) def set_mail_attr(self, name: str, value: Any): OmegaConf.update(self._config, f"mail.{name}", value) def set_database_attr(self, name: str, value: Any): OmegaConf.update(self._config, f"database.{name}", value) def set_zotero_attr(self, name: str, value: Any): OmegaConf.update(self._config, f"zotero.{name}", value) def set_icon_attr(self, name: str, value: Any): OmegaConf.update(self._config, f"icons.{name}", value) @property def save_path(self): return self._config.save_path @save_path.setter def save_path(self, value: str): self._config.save_path = value def load_config(self, path, filename): return OmegaConf.load(os.path.join(path, filename)) @property def icons(self): icons = Icons() icons.assign("path", self._config.icon_path) icons.assign("colors", self._config.colors) icons.assign("icons", self._config.icons) return icons def dict(self): return OmegaConf.to_container(self._config)