from pathlib import Path import tomllib CONTENT_DIR = None TEMPLATES_DIR = None STYLES_DIR = None class Configuration: """ Configuration class for loading and validating application settings from a TOML file. This class encapsulates the logic for reading configuration data from a specified TOML file, validating the presence of required sections and keys, and exposing configuration values as instance attributes. The configuration file is expected to contain at least two sections: 'paths' (with 'content_dir', 'templates_dir', and 'styles_dir') and 'server' (with optional server-related settings). Attributes: config_path (str or Path): Path to the TOML configuration file. content_dir (Path): Directory containing content files (required). templates_dir (Path): Directory containing template files (required). styles_dir (Path): Directory containing style files (required). listen_address (str): Address for the server to listen on (default: "127.0.0.1"). listen_port (int): Port for the server to listen on (default: 8080). debug (bool): Enable or disable debug mode (default: False). access_log (bool): Enable or disable access logging (default: True). max_threads (int): Maximum number of server threads (default: 4). admin_browser (bool): Enable or disable admin browser access (default: False). admin_password (str): Password for admin access (optional). Methods: load_config(): Loads and validates configuration data from the TOML file specified by `config_path`. Raises FileNotFoundError if the file does not exist, tomllib.TOMLDecodeError if the file is not valid TOML, or ValueError if required sections or keys are missing. set_globals(): Sets global variables CONTENT_DIR, TEMPLATES_DIR, and STYLES_DIR based on the loaded configuration values. """ def __init__(self, config_path): self.config_path = config_path self.content_dir: Path = None self.templates_dir: Path = None self.styles_dir: Path = None self.listen_address: str = "127.0.0.1" self.listen_port: int = 8080 self.debug: bool = False self.access_log: bool = True self.max_threads: int = 4 self.admin_browser: bool = False self.admin_password: str = None def load_config(self): """ Loads and validates configuration data from a TOML file specified by `self.config_path`. This method reads the configuration file, parses its contents, and sets various instance attributes based on the configuration values. It expects the configuration file to contain at least two sections: 'paths' and 'server'. The 'paths' section must include 'content_dir', 'templates_dir', and 'styles_dir'. The 'server' section may include 'listen_address', 'listen_port', 'debug', 'access_log', 'max_threads', 'admin_browser', and 'admin_password'. If any required section or key is missing, or if the file is not found or is invalid TOML, an appropriate exception is raised. Raises: FileNotFoundError: If the configuration file does not exist. tomllib.TOMLDecodeError: If the configuration file is not valid TOML. ValueError: If required sections or keys are missing in the configuration file. """ try: with open(self.config_path, "rb") as f: self.config_data = tomllib.load(f) except FileNotFoundError: raise FileNotFoundError(f"Config file not found at {self.config_path}") except tomllib.TOMLDecodeError: raise tomllib.TOMLDecodeError(f"Config file at {self.config_path} is not valid TOML") paths = self.config_data.get("paths", {}) if not paths: raise ValueError("Config file does not contain paths section") self.content_dir = paths.get("content_dir") if not self.content_dir: raise ValueError("Config file does not contain content_dir path") self.content_dir = Path(self.content_dir) self.templates_dir = paths.get("templates_dir") if not self.templates_dir: raise ValueError("Config file does not contain templates_dir path") self.templates_dir = Path(self.templates_dir) self.styles_dir = paths.get("styles_dir") if not self.styles_dir: raise ValueError("Config file does not contain styles_dir path") self.styles_dir = Path(self.styles_dir) server = self.config_data.get("server", {}) if not server: raise ValueError("Config file does not contain server section") self.listen_address = server.get("listen_address", self.listen_address) self.listen_port = server.get("listen_port", self.listen_port) self.debug = server.get("debug", self.debug) self.access_log = server.get("access_log", self.access_log) self.max_threads = server.get("max_threads", self.max_threads) self.admin_browser = server.get("admin_browser", self.admin_browser) self.admin_password = server.get("admin_password", self.admin_password)