Source code for simplematrixbotlib.config

from dataclasses import dataclass, field, fields, asdict
import os.path
import toml
import re
from typing import Set, Union
from nio.crypto import ENCRYPTION_ENABLED


def _config_dict_factory(tmp) -> dict:
    return {
        'simplematrixbotlib': {
            'config':
            {_strip_leading_underscore(name): _extract_pattern_if_neccessary(value)
             for name, value in tmp}
        }
    }

def _extract_pattern_if_neccessary(value):
    try:
        return value.pattern
    except AttributeError:
        return value

def _strip_leading_underscore(tmp: str) -> str:
    return tmp[1:] if tmp[0] == '_' else tmp


def _check_set_regex(value: Set[str]) -> Union[Set[re.Pattern], None]:
    new_list = set()
    for v in value:
        try:
            tmp = re.compile(v)
        except re.error:
            print(
                f"{v} is not a valid regular expression. Ignoring your list update."
            )
            return None
        new_list.add(tmp)
    return new_list


[docs] @dataclass class Config: """ A class to handle built-in user-configurable settings, including support for saving to and loading from a file. Can be inherited from by bot developers to implement custom settings. """ _timeout: int = 65536 _join_on_invite: bool = True _encryption_enabled: bool = ENCRYPTION_ENABLED _emoji_verify: bool = False # So users who enable it are aware of required interactivity _ignore_unverified_devices: bool = True # True by default in Element # TODO: auto-ignore/auto-blacklist devices/users # _allowed_unverified_devices etc _store_path: str = "./store/" _allowlist: Set[re.Pattern] = field( default_factory=set) # TODO: default to bot's homeserver _blocklist: Set[re.Pattern] = field(default_factory=set) def _load_config_dict(self, config_dict: dict) -> None: # TODO: make this into a factory, so defaults for # non-loaded values can be set based on loaded values? existing_fields = [ _strip_leading_underscore(f.name) for f in fields(self) ] for key, value in config_dict.items(): if key not in existing_fields: continue setattr(self, key, value)
[docs] def load_toml(self, file_path: str) -> None: with open(file_path, 'r') as file: config_dict: dict = toml.load(file)['simplematrixbotlib']['config'] self._load_config_dict(config_dict)
[docs] def save_toml(self, file_path: str) -> None: tmp = asdict(self, dict_factory=_config_dict_factory) with open(file_path, 'w') as file: toml.dump(tmp, file)
@property def timeout(self) -> int: """ Returns ------- int Connection timeout for the Matrix client (in milliseconds) """ return self._timeout @timeout.setter def timeout(self, value: int) -> None: self._timeout = value @property def join_on_invite(self) -> bool: """ Returns ------- boolean Whether the bot is configured to automatically accept all invites it receives """ return self._join_on_invite @join_on_invite.setter def join_on_invite(self, value: bool) -> None: self._join_on_invite = value @property def encryption_enabled(self) -> bool: """ Returns ------- boolean Whether to enable encryption support. Requires encryption-specific dependencies to be met, see install instructions. """ return self._encryption_enabled @encryption_enabled.setter def encryption_enabled(self, value: bool) -> None: # safeguards regarding ENCRYPTION_ENABLED are enforced by nio in ClientConfig self._encryption_enabled = value # update dependent values self.emoji_verify = self.emoji_verify self.ignore_unverified_devices = self.ignore_unverified_devices @property def emoji_verify(self) -> bool: """ Returns ------- boolean Whether emoji verification requests should be handled by the built in callback function """ return self._emoji_verify @emoji_verify.setter def emoji_verify(self, value: bool) -> None: self._emoji_verify = value and self.encryption_enabled @property def store_path(self) -> str: """ Returns ------- string Where to store crypto-related data including keys """ return self._store_path @store_path.setter def store_path(self, value: str) -> None: # check if the path exists or can be created, throws an error otherwise os.makedirs(value, mode=0o750, exist_ok=True) self._store_path = value @property def ignore_unverified_devices(self) -> bool: """ Returns ------- boolean If True, ignore that devices are not verified and send the message to them regardless. If False, distrust unverified devices. """ return self._ignore_unverified_devices @ignore_unverified_devices.setter def ignore_unverified_devices(self, value: bool) -> None: self._ignore_unverified_devices = value if self.encryption_enabled else True @property def allowlist(self) -> Set[re.Pattern]: """ Returns ------- Set[re.Pattern] A set of regular expressions matching Matrix IDs. Can be used in conjunction with blocklist to check if the sender is allowed to issue a command to the bot. An empty set implies that everyone is allowed. """ return self._allowlist @allowlist.setter def allowlist(self, value: Set[str]) -> None: checked = _check_set_regex(value) if checked is None: return self._allowlist = checked
[docs] def add_allowlist(self, value: Set[str]) -> None: """ Parameters ---------- value : Set[str] A set of strings which represent Matrix IDs or a regular expression matching Matrix IDs to be added to allowlist. """ checked = _check_set_regex(value) if checked is None: return self._allowlist = self._allowlist.union(checked)
[docs] def remove_allowlist(self, value: Set[str]) -> None: """ Parameters ---------- value : Set[str] A set of strings which represent Matrix IDs or a regular expression matching Matrix IDs to be removed from allowlist. """ checked = _check_set_regex(value) if checked is None: return self._allowlist = self._allowlist - checked
@property def blocklist(self) -> Set[re.Pattern]: """ Returns ------- Set[re.Pattern] A set of regular expressions matching Matrix IDs. Can be used in conjunction with allowlist to check if the sender is disallowed to issue a command to the bot. """ return self._blocklist @blocklist.setter def blocklist(self, value: Set[str]) -> None: checked = _check_set_regex(value) if checked is None: return self._blocklist = checked
[docs] def add_blocklist(self, value: Set[str]) -> None: """ Parameters ---------- value : Set[str] A set of strings which represent Matrix IDs or a regular expression matching Matrix IDs to be added to blocklist. """ checked = _check_set_regex(value) if checked is None: return self._blocklist = self._blocklist.union(checked)
[docs] def remove_blocklist(self, value: Set[str]) -> None: """ Parameters ---------- value : Set[str] A set of strings which represent Matrix IDs or a regular expression matching Matrix IDs to be removed from blocklist. """ checked = _check_set_regex(value) if checked is None: return self._blocklist = self._blocklist - checked