From 54c654f7ce2724da16591091f388f2db8f787b56 Mon Sep 17 00:00:00 2001 From: Jenny Danzmayr Date: Mon, 27 Nov 2023 03:17:13 +0100 Subject: [PATCH] raise the propper exception if a required config setting is missing --- src/c3nav/utils/config.py | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/c3nav/utils/config.py b/src/c3nav/utils/config.py index 96e61c54..cc5b84f7 100644 --- a/src/c3nav/utils/config.py +++ b/src/c3nav/utils/config.py @@ -1,4 +1,7 @@ -from configparser import _UNSET, RawConfigParser +from configparser import _UNSET, NoOptionError, NoSectionError, RawConfigParser +from contextlib import contextmanager + +from django.core.exceptions import ImproperlyConfigured from c3nav.utils.environ import Env @@ -25,25 +28,44 @@ class C3navConfigParser(RawConfigParser): key = 'C3NAV_' + key return key + @classmethod + @contextmanager + def _error_wrapper(cls, section: str, option: str, env: bool | str): + try: + yield + except (NoOptionError, NoSectionError) as e: + error_msg = f'Missing required setting {section} -> {option}' + if env: + error_msg += f' ({cls.get_env_key(section, option, env)} environment variable)' + raise ImproperlyConfigured(error_msg) from e + + # for our error wrapper to work we need to make sure getint, getfloat, and getboolean call the original get method + def _get(self, section, conv, option, **kwargs): + return conv(super().get(section, option, **kwargs)) + def get(self, section: str, option: str, *, raw=False, vars=None, fallback=_UNSET, env: bool | str = True) -> str: if env and (value := self.env.str(self.get_env_key(section, option, env), default=None)) is not None: return value - return super().get(section, option, raw=raw, vars=vars, fallback=fallback) + with self._error_wrapper(section, option, env): + return super().get(section, option, raw=raw, vars=vars, fallback=fallback) def getint(self, section: str, option: str, *, raw=False, vars=None, fallback=_UNSET, env: bool | str = True, **kwargs) -> int: if env and (value := self.env.int(self.get_env_key(section, option, env), default=None)) is not None: return value - return super().getint(section, option, raw=raw, vars=vars, fallback=fallback) + with self._error_wrapper(section, option, env): + return super().getint(section, option, raw=raw, vars=vars, fallback=fallback) def getfloat(self, section: str, option: str, *, raw=False, vars=None, fallback=_UNSET, env: bool | str = True, **kwargs) -> float: if env and (value := self.env.float(self.get_env_key(section, option, env), default=None)) is not None: return value - return super().getfloat(section, option, raw=raw, vars=vars, fallback=fallback) + with self._error_wrapper(section, option, env): + return super().getfloat(section, option, raw=raw, vars=vars, fallback=fallback) def getboolean(self, section: str, option: str, *, raw=False, vars=None, fallback=_UNSET, env: bool | str = True, **kwargs) -> bool: if env and (value := self.env.bool(self.get_env_key(section, option, env), default=None)) is not None: return value - return super().getboolean(section, option, raw=raw, vars=vars, fallback=fallback) + with self._error_wrapper(section, option, env): + return super().getboolean(section, option, raw=raw, vars=vars, fallback=fallback)