You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
2.4 KiB
Python

from __future__ import annotations
from typing import (
Mapping,
Optional,
Tuple,
Type,
TypeAlias,
)
# type aliases
TypeSet: TypeAlias = Tuple[Type, ...]
TypeLike: TypeAlias = Type | TypeSet
# exceptions
class ConfigValidationError(Exception):
key: str
class ConfigMissingRequiredError(ConfigValidationError):
def __init__(self, *, key: str) -> None:
super().__init__(f"Missing configuration value for key {key!r}")
self.key = key
class ConfigInvalidTypeError(ConfigValidationError):
key: str
types: TypeSet
def __init__(self, *, key: str, types: TypeLike, got_type: Type) -> None:
self.key = key
self.types = self.__parse_type_like(types)
super().__init__(
f"Required configuration value for key {key!r} to be of either {self.type_list}; got type {got_type}."
)
@staticmethod
def __parse_type_like(types: TypeLike) -> TypeSet:
if isinstance(types, tuple):
return types
return (types,)
@property
def type_list(self) -> str:
return ", ".join(str(t) for t in self.types)
# methods
_REQUIRED_KEYS: Mapping[str, Optional[TypeLike]] = {
"PONY_PROVIDER": str,
"SECRET_KEY": (bytes, str),
}
_OPTIONAL_KEYS: Mapping[str, Optional[TypeLike]] = {
"PONY_CHARSET": str,
"PONY_CREATE_DB": bool,
"PONY_DATABASE": str,
"PONY_DB": str,
"PONY_DSN": str,
"PONY_FILENAME": str,
"PONY_HOST": str,
"PONY_PASSWD": str,
"PONY_PASSWORD": str,
"PONY_PORT": int,
"PONY_USER": str,
}
def validate_config(config: Mapping) -> None:
for required, key_list in {True: _REQUIRED_KEYS, False: _OPTIONAL_KEYS}.items():
for key, types in key_list.items():
check_value(
config=config,
key=key,
types=types,
required=required,
)
def check_value(
config: Mapping, key: str, types: Optional[TypeLike] = None, required: bool = True
) -> None:
if key not in config:
if required:
raise ConfigMissingRequiredError(
key=key,
)
return
if types is None:
return
value = config[key]
if not isinstance(value, types):
raise ConfigInvalidTypeError(
key=key,
types=types,
got_type=type(value),
)