Add config handler

This commit is contained in:
Peter Vacho 2024-11-27 16:08:00 +01:00
parent 04b2ee57bd
commit 9affe75810
Signed by: school
GPG key ID: 8CFC3837052871B4
6 changed files with 101 additions and 1 deletions

View file

@ -3,7 +3,12 @@ name = "event_management"
version = "0.1.0"
description = "Backed part of the final project assignment for AP7PD"
authors = [{ name = "Peter Vacho", email = "p_vacho@utb.cz" }]
dependencies = ["fastapi>=0.115.5", "uvicorn>=0.32.1", "poethepoet>=0.31.1"]
dependencies = [
"fastapi>=0.115.5",
"uvicorn>=0.32.1",
"poethepoet>=0.31.1",
"python-decouple>=3.8",
]
readme = "README.md"
requires-python = ">= 3.12"
license = { text = "GPL-3.0-or-later" }

View file

@ -46,6 +46,8 @@ pydantic==2.10.2
# via fastapi
pydantic-core==2.27.1
# via pydantic
python-decouple==3.8
# via event-management
pyyaml==6.0.2
# via poethepoet
# via pre-commit

View file

@ -30,6 +30,8 @@ pydantic==2.10.2
# via fastapi
pydantic-core==2.27.1
# via pydantic
python-decouple==3.8
# via event-management
pyyaml==6.0.2
# via poethepoet
sniffio==1.3.1

0
src/settings.py Normal file
View file

0
src/utils/__init__.py Normal file
View file

91
src/utils/config.py Normal file
View file

@ -0,0 +1,91 @@
"""File containing a typed wrapper function around ``decouple.config``."""
from __future__ import annotations
from collections.abc import Callable
from typing import Any, NewType, TypeVar, cast, overload
from decouple import UndefinedValueError, config
__all__ = ["get_config"]
T = TypeVar("T")
U = TypeVar("U")
Sentinel = NewType("Sentinel", object)
_MISSING = cast(Sentinel, object())
@overload
def get_config(
search_path: str,
*,
cast: None = None,
default: U | Sentinel = _MISSING,
) -> str | U: ...
@overload
def get_config(
search_path: str,
*,
cast: Callable[[str], T],
default: U | Sentinel = _MISSING,
) -> T | U: ...
def get_config(
search_path: str,
*,
cast: Callable[[str], object] | None = None,
default: object = _MISSING,
) -> object:
"""Typed wrapper around ``decouple.config`` for static type analysis."""
try:
val = config(search_path)
except UndefinedValueError as exc:
if default is not _MISSING:
return default
raise exc from exc
# Treat empty strings as unset values
if val == "":
if default is not _MISSING:
return default
raise UndefinedValueError(
f"{search_path} was found, but the content was an empty string. "
"Set a non-empty value for the envvar or define a default value."
)
# We run this again, this time with a cast function.
# the reason we don't do this immediately is that the empty strings might not
# work with the cast function, which could raise various exceptions.
if cast is None:
cast = lambda x: x
return config(search_path, cast=cast)
@overload
def config_cast_list(cast: None = None) -> Callable[[str], list[str]]: ...
@overload
def config_cast_list(cast: Callable[[str], T]) -> Callable[[str], list[T]]: ...
def config_cast_list(cast: Callable[[str], object] | None = None) -> Callable[[str], list[Any]]:
"""Cast function to convert the content of an environmental variable to a list of values.
This works by splitting the contents of the environmental variable on `,` characters.
Currently, there is not support for escaping here, so list variables that require `,`
symbol to be present will not work.
You can use this function in :func:`get_config` for the ``cast`` argument.
"""
if cast is None or cast is str: # type: ignore[reportUnnecessaryComparison] # str is infact a subtype of (str) -> object
cast = lambda x: x
def inner(raw_value: str) -> list[Any]:
return [cast(x) for x in raw_value.split(",") if x]
return inner