smal: add config class
This commit is contained in:
parent
4c9ba7dcdb
commit
285bb0647f
2 changed files with 159 additions and 1 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from .app import SMALApp
|
from .app import SMALApp
|
||||||
|
from .config import SMALConfig
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -14,9 +15,10 @@ logger = logging.getLogger(__name__)
|
||||||
class SMALBot(SMALApp):
|
class SMALBot(SMALApp):
|
||||||
""" """
|
""" """
|
||||||
|
|
||||||
def __init__(self, sigil):
|
def __init__(self, sigil, config=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._sigil = sigil
|
self._sigil = sigil
|
||||||
|
self._config = config if config is not None else SMALConfig.create_new()
|
||||||
|
|
||||||
async def sendmessage(self, roomid, text):
|
async def sendmessage(self, roomid, text):
|
||||||
data = {}
|
data = {}
|
||||||
|
|
|
||||||
156
mxsmal/src/mxsmal/config.py
Normal file
156
mxsmal/src/mxsmal/config.py
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
# Copyright (C) 2026 saces@c-base.org
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
from dataclasses import asdict, dataclass
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
import dacite
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigFileType(Enum):
|
||||||
|
YAML = "yaml"
|
||||||
|
TOML = "toml"
|
||||||
|
JSON = "json"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ConfigFile:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_new(cls):
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_file(cls, file_path=None, file_type=None, cast=None):
|
||||||
|
"""
|
||||||
|
automagic config file loader
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: fd, filename or "-"
|
||||||
|
type: type of config file, required for fd and "-"
|
||||||
|
cast: type hint decite/decoder
|
||||||
|
|
||||||
|
Returns: config object
|
||||||
|
|
||||||
|
"""
|
||||||
|
if file_path is None:
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
if file_type is None:
|
||||||
|
# try to guess the type from name extension
|
||||||
|
ext = pathlib.Path(file_path).suffix
|
||||||
|
if ext in [".yaml", ".yml"]:
|
||||||
|
file_type = ConfigFileType.YAML
|
||||||
|
elif ext in [".toml", ".tml"]:
|
||||||
|
file_type = ConfigFileType.TOML
|
||||||
|
elif ext == ".json":
|
||||||
|
file_type = ConfigFileType.JSON
|
||||||
|
else:
|
||||||
|
raise ConfigError("Unable to guess the file type from name.")
|
||||||
|
|
||||||
|
# try to load the data
|
||||||
|
data = None
|
||||||
|
if file_path == "-":
|
||||||
|
file_path = sys.stdin
|
||||||
|
if file_type == ConfigFileType.TOML:
|
||||||
|
import toml
|
||||||
|
|
||||||
|
data = toml.load(file_path)
|
||||||
|
elif file_type == ConfigFileType.YAML:
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
data = yaml.safe_load(file_path)
|
||||||
|
elif file_type == ConfigFileType.JSON:
|
||||||
|
import json
|
||||||
|
|
||||||
|
with open(file_path) as f:
|
||||||
|
data = json.load(f)
|
||||||
|
else:
|
||||||
|
# after adding new file types you may need to update the logic
|
||||||
|
raise RuntimeError()
|
||||||
|
|
||||||
|
return dacite.from_dict(
|
||||||
|
data_class=cls,
|
||||||
|
data=data,
|
||||||
|
# tell dacite to cast some types while deserializing
|
||||||
|
config=dacite.Config(cast=cast) if cast else None,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_file_auto(cls, file_path: str, file_type=None, cast=None):
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
return cls.load_file(file_path, file_type, cast)
|
||||||
|
else:
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
def save_file(self, file_path: str, file_type=None):
|
||||||
|
|
||||||
|
if file_path == "-" and file_type is None:
|
||||||
|
raise ConfigError("file_type required if printing to stdout")
|
||||||
|
|
||||||
|
if file_type is None:
|
||||||
|
# try to guess the type from name extension
|
||||||
|
ext = pathlib.Path(file_path).suffix
|
||||||
|
if ext in [".yaml", ".yml"]:
|
||||||
|
file_type = ConfigFileType.YAML
|
||||||
|
elif ext in [".toml", ".tml"]:
|
||||||
|
file_type = ConfigFileType.TOML
|
||||||
|
elif ext == ".json":
|
||||||
|
file_type = ConfigFileType.JSON
|
||||||
|
else:
|
||||||
|
raise ConfigError("Unable to guess the file type from name.")
|
||||||
|
|
||||||
|
def my_factory(data):
|
||||||
|
def convert_value(obj):
|
||||||
|
if isinstance(obj, Enum):
|
||||||
|
return obj.value
|
||||||
|
return obj
|
||||||
|
|
||||||
|
return dict((k, convert_value(v)) for k, v in data)
|
||||||
|
|
||||||
|
d = asdict(self, dict_factory=my_factory)
|
||||||
|
|
||||||
|
if file_path == "-":
|
||||||
|
file_path = sys.stdout
|
||||||
|
if file_type == ConfigFileType.TOML:
|
||||||
|
import toml
|
||||||
|
|
||||||
|
toml.dump(d, file_path)
|
||||||
|
elif file_type == ConfigFileType.YAML:
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
yaml.dump(d, file_path)
|
||||||
|
elif file_type == ConfigFileType.JSON:
|
||||||
|
import json
|
||||||
|
|
||||||
|
json.dump(d, file_path)
|
||||||
|
else:
|
||||||
|
# after adding new file types you may need to update the logic
|
||||||
|
raise RuntimeError()
|
||||||
|
else:
|
||||||
|
if file_type == ConfigFileType.TOML:
|
||||||
|
import toml
|
||||||
|
|
||||||
|
with open(file_path, "w") as file:
|
||||||
|
toml.dump(d, file)
|
||||||
|
elif file_type == ConfigFileType.YAML:
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
with open(file_path, "w") as file:
|
||||||
|
yaml.dump(d, file)
|
||||||
|
elif file_type == ConfigFileType.JSON:
|
||||||
|
import json
|
||||||
|
|
||||||
|
with open(file_path, "w") as file:
|
||||||
|
json.dump(d, file)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SMALConfig(ConfigFile):
|
||||||
|
pass
|
||||||
Loading…
Add table
Add a link
Reference in a new issue