def __setitem__(self, key: str, item: typing.Any) -> None: key = key.lower() logger.info("Setting %s.", key) if key not in self.all_keys: raise InvalidConfigError(f'Configuration "{key}" is invalid.') self._cache[key] = item
def get(self, key: str, convert=True) -> typing.Any: key = key.lower() if key not in self.all_keys: raise InvalidConfigError(f'Configuration "{key}" is invalid.') if key not in self._cache: self._cache[key] = deepcopy(self.defaults[key]) value = self._cache[key] if not convert: return value if key in self.colors: try: return int(value.lstrip("#"), base=16) except ValueError: logger.error("Invalid %s provided.", key) value = int(self.remove(key).lstrip("#"), base=16) elif key in self.time_deltas: if not isinstance(value, isodate.Duration): try: value = isodate.parse_duration(value) except isodate.ISO8601Error: logger.warning( "The {account} age limit needs to be a " 'ISO-8601 duration formatted duration, not "%s".', value, ) value = self.remove(key) elif key in self.booleans: try: value = strtobool(value) except ValueError: value = self.remove(key) elif key in self.enums: if value is None: return None try: value = self.enums[key](value) except ValueError: logger.warning("Invalid %s %s.", key, value) value = self.remove(key) elif key in self.force_str: # Temporary: as we saved in int previously, leading to int32 overflow, # this is transitioning IDs to strings new_value = {} changed = False for k, v in value.items(): new_v = v if isinstance(v, list): new_v = [] for n in v: if n != -1 and not isinstance(n, str): changed = True n = str(n) new_v.append(n) new_value[k] = new_v if changed: # transition the database as well self.set(key, new_value) value = new_value return value
async def clean_data(self, key: str, val: typing.Any) -> typing.Tuple[str, str]: value_text = val clean_value = val # when setting a color if key in self.colors: try: hex_ = str(val) if hex_.startswith("#"): hex_ = hex_[1:] if len(hex_) == 3: hex_ = "".join(s for s in hex_ for _ in range(2)) if len(hex_) != 6: raise InvalidConfigError("Invalid color name or hex.") try: int(hex_, 16) except ValueError: raise InvalidConfigError("Invalid color name or hex.") hex_ = "#" + hex_ value_text = clean_value = hex_ except InvalidConfigError: name = str(val).lower() name = re.sub(r"[\-+|. ]+", " ", name) hex_ = ALL_COLORS.get(name) if hex_ is None: name = re.sub(r"[\-+|. ]+", "", name) hex_ = ALL_COLORS.get(name) if hex_ is None: raise clean_value = hex_ value_text = f"{name} ({clean_value})" elif key in self.time_deltas: try: isodate.parse_duration(val) except isodate.ISO8601Error: try: converter = UserFriendlyTime() time = await converter.convert(None, val) if time.arg: raise ValueError except BadArgument as exc: raise InvalidConfigError(*exc.args) except Exception: raise InvalidConfigError( "Unrecognized time, please use ISO-8601 duration format " 'string or a simpler "human readable" time.') clean_value = isodate.duration_isoformat(time.dt - converter.now) value_text = f"{val} ({clean_value})" elif key in self.booleans: try: clean_value = value_text = strtobool(val) except ValueError: raise InvalidConfigError("Must be a yes/no value.") return clean_value, value_text
def set(self, key: str, item: typing.Any, convert=True) -> None: if not convert: return self.__setitem__(key, item) if key in self.colors: try: hex_ = str(item) if hex_.startswith("#"): hex_ = hex_[1:] if len(hex_) == 3: hex_ = "".join(s for s in hex_ for _ in range(2)) if len(hex_) != 6: raise InvalidConfigError("Invalid color name or hex.") try: int(hex_, 16) except ValueError: raise InvalidConfigError("Invalid color name or hex.") except InvalidConfigError: name = str(item).lower() name = re.sub(r"[\-+|. ]+", " ", name) hex_ = ALL_COLORS.get(name) if hex_ is None: name = re.sub(r"[\-+|. ]+", "", name) hex_ = ALL_COLORS.get(name) if hex_ is None: raise return self.__setitem__(key, "#" + hex_) if key in self.time_deltas: try: isodate.parse_duration(item) except isodate.ISO8601Error: try: converter = UserFriendlyTimeSync() time = converter.convert(None, item) if time.arg: raise ValueError except BadArgument as exc: raise InvalidConfigError(*exc.args) except Exception as e: logger.debug(e) raise InvalidConfigError( "Unrecognized time, please use ISO-8601 duration format " 'string or a simpler "human readable" time.' ) item = isodate.duration_isoformat(time.dt - converter.now) return self.__setitem__(key, item) if key in self.booleans: try: return self.__setitem__(key, strtobool(item)) except ValueError: raise InvalidConfigError("Must be a yes/no value.") elif key in self.enums: if isinstance(item, self.enums[key]): # value is an enum type item = item.value return self.__setitem__(key, item)
async def clean_data(self, key: str, val: typing.Any) -> typing.Tuple[str, str]: value_text = val clean_value = val # when setting a color if key in self.colors: hex_ = ALL_COLORS.get(val) if hex_ is None: if not isinstance(val, str): raise InvalidConfigError("Invalid color name or hex.") if val.startswith("#"): val = val[1:] if len(val) != 6: raise InvalidConfigError("Invalid color name or hex.") for letter in val: if letter not in { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", }: raise InvalidConfigError("Invalid color name or hex.") clean_value = "#" + val value_text = clean_value else: clean_value = hex_ value_text = f"{val} ({clean_value})" elif key in self.time_deltas: try: isodate.parse_duration(val) except isodate.ISO8601Error: try: converter = UserFriendlyTime() time = await converter.convert(None, val) if time.arg: raise ValueError except BadArgument as exc: raise InvalidConfigError(*exc.args) except Exception: raise InvalidConfigError( "Unrecognized time, please use ISO-8601 duration format " 'string or a simpler "human readable" time.') clean_value = isodate.duration_isoformat(time.dt - converter.now) value_text = f"{val} ({clean_value})" return clean_value, value_text