Skip to content

Instantly share code, notes, and snippets.

@victorusachev
Last active July 12, 2021 13:13
Show Gist options
  • Save victorusachev/b1d3ef4882e4e6573924beb225ad7288 to your computer and use it in GitHub Desktop.
Save victorusachev/b1d3ef4882e4e6573924beb225ad7288 to your computer and use it in GitHub Desktop.
Application configuration example
from contextlib import contextmanager
from typing import TYPE_CHECKING, Any, Iterator
from my_app.settings import get_settings
if TYPE_CHECKING:
from my_app.settings import Settings
@contextmanager
def override_settings(**overrides: Any) -> Iterator["Settings"]:
try:
settings = get_settings()
for name, value in overrides.items():
if not hasattr(settings, name):
raise AttributeError(
f'The Settings class does not define the "{name}" setting'
)
setattr(settings, name, value)
yield settings
finally:
get_settings.cache_clear()
import enum
import logging.config
from functools import lru_cache
from typing import Any, Dict, List
from pydantic import BaseSettings
__all__ = ("TRACE_LOG_LEVEL", "Settings", "get_settings")
TRACE_LOG_LEVEL = 5
@lru_cache()
def get_settings() -> "Settings":
return Settings()
class LogLevel(str, enum.Enum):
critical = "critical"
error = "error"
warning = "warning"
info = "info"
debug = "debug"
trace = "trace"
notset = "notset"
class Settings(BaseSettings):
"""Application settings.
The application defines a set of configuration parameters.
The application is configured as follows, in descending order of priority:
- environment variables with the `DEFMAIN_` prefix,
- variables with the `DEFMAIN_` prefix in the` .env` file
in the current working directory (if any),
- default values specified in the code.
"""
debug: bool = False
# CORS middleware
allow_origins: List[str] = ["*"]
allow_methods: List[str] = ["*"]
allow_headers: List[str] = ["*"]
# Logging
log_level: LogLevel = LogLevel.warning
class Config:
env_file = ".env"
env_prefix = "DEFMAIN_"
def __init__(self, **values: Any) -> None:
super().__init__(**values)
self.configure_logging()
def configure_logging(self) -> None:
logging.addLevelName(TRACE_LOG_LEVEL, LogLevel.trace.upper())
logging.config.dictConfig(self.logging_config)
@property
def logging_config(self) -> Dict[str, Any]:
log_level = self.log_level.name.upper()
return {
"version": 1,
"formatters": {
"defaultFormatter": {
"format": "%(asctime)s - %(levelname)s - %(name)s - %(message)s",
},
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": log_level,
"formatter": "defaultFormatter",
"stream": "ext://sys.stderr",
},
},
"loggers": {
"": {"level": log_level, "propagate": False, "handlers": ["console"]},
},
"disable_existing_loggers": False,
}
from my_app.settings import get_settings
from tests.helpers import override_settings
def test_override_settings():
original_settings = get_settings()
debug = not original_settings.debug
with override_settings(debug=debug) as settings:
assert settings.debug is debug
assert get_settings().debug is debug
settings = get_settings()
assert settings.debug is not debug
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment