hotdog/hotdog/config.py
2020-11-07 19:55:34 +01:00

89 lines
2.7 KiB
Python

import platform
import re
from pathlib import Path
from typing import *
import yaml
class ConfigError(RuntimeError):
pass
class Fallbackdict(dict):
"""Like defaultdict, but not implicitly creating entries."""
def __init__(self, default):
super().__init__()
self._default = default
def __missing__(self, key):
return self._default
class Config:
def __init__(self, path):
self.load(path)
def load(self, path):
with open(path) as fp:
self.config = yaml.safe_load(fp)
self.command_prefix = self.get("command_prefix")
# Logging
self.loglevel = self.get("loglevel", default="INFO")
# Storage
self.store_path = Path(self.get("storage.store_path"))
# Matrix
self.user_id = self.get("matrix.user_id")
if not re.fullmatch("@.*:.*", self.user_id):
raise ConfigError("matrix.user_id must be in the form @name:domain")
self.device_id_path = self.store_path / f"{self.user_id}.device_id"
try:
self.device_id = self.device_id_path.read_text()
except FileNotFoundError:
self.device_id = ""
self.device_name = self.get(
"matrix.session_name", default=f"hotdog/{platform.node()}"
)
self.display_name = self.get("matrix.nick_name")
self.homeserver_url = self.get("matrix.homeserver_url")
self.password = self.get("matrix.password")
# Development
self.is_dev = self.get("dev.active", False)
self.dev_room = self.get("dev.room", "")
# Location / l6n
l6n_default = self.get("l6n.default")
l6n = Fallbackdict(l6n_default)
for room in self.get("l6n.rooms"):
l6n[room["id"]] = {**l6n_default, **room} # XXX in py3.9 use |-operator
self.l6n = l6n
def get(self, path: Union[str, List[str]], default: Any = None) -> Any:
if isinstance(path, str):
path = path.split(".")
config = self.config
for part in path:
config = config.get(part)
if config is None:
if default is not None:
return default
raise ConfigError(f"Config value is missing: {'.'.join(path)}")
return config
def set(self, path: Union[str, List[str]], value: Any):
if isinstance(path, str):
path = path.split(".")
config = self.config
for part in path[:-1]:
if part in config and not isinstance(config[part], dict):
raise ConfigError(f"Conflicting value exists: {'.'.join(path)}")
config = config.get(part, {})
config[path[-1]] = value