diff options
| author | 2019-11-15 13:39:24 +0000 | |
|---|---|---|
| committer | 2019-11-15 13:39:24 +0000 | |
| commit | bfcf40edd71c5bdd436ab8b535c880fad8781f16 (patch) | |
| tree | f26b390a444203f03a03be84b475cb83bf907bb0 /src/utils/__init__.py | |
| parent | only try to shlex when we know we've found a command hook (diff) | |
| signature | ||
split some stuff out of utils/__init__.py
Diffstat (limited to 'src/utils/__init__.py')
| -rw-r--r-- | src/utils/__init__.py | 184 |
1 files changed, 4 insertions, 180 deletions
diff --git a/src/utils/__init__.py b/src/utils/__init__.py index 33ad449b..1013b2ac 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -2,6 +2,10 @@ import contextlib, datetime, decimal, enum, io, ipaddress, multiprocessing import queue, re, signal, threading, typing from . import cli, consts, irc, http, parse, security +from .decorators import export, get_magic, has_magic, hook, kwarg +from .settings import (BoolSetting, FunctionSetting, IntRangeSetting, + IntSetting, OptionsSetting, sensitive_format, SensitiveSetting, Setting) + class Direction(enum.Enum): Send = 0 Recv = 1 @@ -129,31 +133,6 @@ def to_pretty_time(total_seconds: int, minimum_unit: int=UNIT_SECOND, units += 1 return " ".join(out) -def parse_number(s: str) -> str: - try: - decimal.Decimal(s) - return s - except: - pass - - unit = s[-1].lower() - number_str = s[:-1] - try: - number = decimal.Decimal(number_str) - except: - raise ValueError("Invalid format '%s' passed to parse_number" % - number_str) - - if unit == "k": - number *= decimal.Decimal("1_000") - elif unit == "m": - number *= decimal.Decimal("1_000_000") - elif unit == "b": - number *= decimal.Decimal("1_000_000_000") - else: - raise ValueError("Unknown unit '%s' given to parse_number" % unit) - return str(number) - def prevent_highlight(nickname: str) -> str: return nickname[0]+"\u200c"+nickname[1:] @@ -169,53 +148,6 @@ class EventsUsageError(EventError): def __init__(self, usage): EventError.__init__(self, "Not enough arguments, usage: %s" % usage) -class BitBotMagic(object): - def __init__(self): - self._hooks: typing.List[typing.Tuple[str, dict]] = [] - self._kwargs: typing.List[typing.Tuple[str, typing.Any]] = [] - self._exports: typing.List[typing.Tuple[str, typing.Any]] = [] - def add_hook(self, hook: str, kwargs: dict): - self._hooks.append((hook, kwargs)) - def add_kwarg(self, key: str, value: typing.Any): - self._kwargs.append((key, value)) - - def get_hooks(self): - hooks: typing.List[typing.Tuple[str, typing.List[Tuple[str, typing.Any]]]] = [] - for hook, kwargs in self._hooks: - hooks.append((hook, self._kwargs.copy()+list(kwargs.items()))) - return hooks - - def add_export(self, key: str, value: typing.Any): - self._exports.append((key, value)) - def get_exports(self): - return self._exports.copy() - -def get_magic(obj: typing.Any): - if not has_magic(obj): - setattr(obj, consts.BITBOT_MAGIC, BitBotMagic()) - return getattr(obj, consts.BITBOT_MAGIC) -def has_magic(obj: typing.Any): - return hasattr(obj, consts.BITBOT_MAGIC) - -def hook(event: str, **kwargs): - def _hook_func(func): - magic = get_magic(func) - magic.add_hook(event, kwargs) - return func - return _hook_func -def export(setting: str, value: typing.Any): - def _export_func(module): - magic = get_magic(module) - magic.add_export(setting, value) - return module - return _export_func -def kwarg(key: str, value: typing.Any): - def _kwarg_func(func): - magic = get_magic(func) - magic.add_kwarg(key, value) - return func - return _kwarg_func - class MultiCheck(object): def __init__(self, requests: typing.List[typing.Tuple[str, typing.List[str]]]): @@ -275,114 +207,6 @@ def is_ip(s: str) -> bool: def is_main_thread() -> bool: return threading.current_thread() is threading.main_thread() -class SettingParseException(Exception): - pass - -class Setting(object): - example: typing.Optional[str] = None - def __init__(self, name: str, help: str=None, example: str=None): - self.name = name - self.help = help - if not example == None: - self.example = example - def parse(self, value: str) -> typing.Any: - return value - - def get_example(self): - if not self.example == None: - return "Example: %s" % self.example - else: - return self._format_example() - def _format_example(self): - return None - - def format(self, value: typing.Any): - return repr(value) - -SETTING_TRUE = ["true", "yes", "on", "y"] -SETTING_FALSE = ["false", "no", "off", "n"] -class BoolSetting(Setting): - example: typing.Optional[str] = "on" - def parse(self, value: str) -> typing.Any: - value_lower = value.lower() - if value_lower in SETTING_TRUE: - return True - elif value_lower in SETTING_FALSE: - return False - return None - -class IntSetting(Setting): - example: typing.Optional[str] = "10" - def parse(self, value: str) -> typing.Any: - if value == "0": - return 0 - else: - stripped = value.lstrip("0") - if stripped.isdigit(): - return int(stripped) - return None - -class IntRangeSetting(IntSetting): - example: typing.Optional[str] = None - def __init__(self, n_min: int, n_max: int, name: str, help: str=None, - example: str=None): - self._n_min = n_min - self._n_max = n_max - Setting.__init__(self, name, help, example) - - def parse(self, value: str) -> typing.Any: - out = IntSetting.parse(self, value) - if not out == None and self._n_min <= out <= self._n_max: - return out - return None - - def _format_example(self): - return "Must be between %d and %d" % (self._n_min, self._n_max) - -class OptionsSetting(Setting): - def __init__(self, options: typing.List[str], name: str, help: str=None, - example: str=None, - options_factory: typing.Callable[[], typing.List[str]]=None): - self._options = options - self._options_factory = options_factory - Setting.__init__(self, name, help, example) - - def _get_options(self): - if not self._options_factory == None: - return self._options_factory() - else: - return self._options - - def parse(self, value: str) -> typing.Any: - value_lower = value.lower() - for option in self._get_options(): - if option.lower() == value_lower: - return option - return None - - def _format_example(self): - options = self._get_options() - options_str = ["'%s'" % option for option in options] - return "Options: %s" % ", ".join(options_str) - -class FunctionSetting(Setting): - def __init__(self, func: typing.Callable[[str], bool], name: str, - help: str=None, example: str=None, format=None): - self._func = func - Setting.__init__(self, name, help, example) - if not format == None: - self.format = format # type: ignore - - def parse(self, value: str) -> typing.Any: - return self._func(value) - -def sensitive_format(value: typing.Any): - return "*"*16 - -class SensitiveSetting(Setting): - def format(self, value: typing.Any): - return sensitive_format(value) - class DeadlineExceededException(Exception): pass def _raise_deadline(): |
