1
Fork 0
mirror of https://github.com/Steffo99/cfig.git synced 2024-11-22 07:54:21 +00:00

Accumulate resolution errors

This commit is contained in:
Steffo 2022-04-19 01:01:55 +02:00
parent d63a6fdc93
commit df5443129c
Signed by: steffo
GPG key ID: 6965406171929D01
3 changed files with 57 additions and 11 deletions

View file

@ -31,17 +31,39 @@ class Configuration:
An extended :class:`dict` with methods to perform some actions on the contained proxies. An extended :class:`dict` with methods to perform some actions on the contained proxies.
""" """
def resolve(self): def resolve(self) -> None:
""" """
Resolve all values of the proxies inside this dictionary. Resolve all values of the proxies inside this dictionary.
:raises .errors.BatchResolutionFailure: If it was not possible to resolve at least one value.
""" """
log.debug("Resolving and caching all values...") errors_dict = {}
for item in self.values():
log.debug(f"Resolving: {item!r}")
_ = item.__wrapped__
def unresolve(self): log.debug("Resolving and caching all proxied values...")
for key, proxy in self.items():
log.debug(f"Resolving: {proxy!r}")
try:
_ = proxy.__wrapped__
except Exception as e:
errors_dict[key] = e
if errors_dict:
raise errors.BatchResolutionFailure(errors=errors_dict)
def resolve_failfast(self) -> None:
"""
Resolve all values of the proxies inside this dictionary, failing immediately if an error occurs during a resolution, and raising the error itself.
:raises Exception: The error occurred during the resolution.
"""
log.debug("Resolving and caching all proxied values in failfast mode...")
for key, proxy in self.items():
log.debug(f"Resolving: {proxy!r}")
_ = proxy.__wrapped__
def unresolve(self) -> None:
""" """
Unresolve all values of the proxies inside this dictionary. Unresolve all values of the proxies inside this dictionary.
""" """
@ -98,7 +120,7 @@ class Configuration:
if not key: if not key:
log.debug("Determining key...") log.debug("Determining key...")
key: str = self._find_resolver_key(configurable) key = self._find_resolver_key(configurable)
log.debug(f"Key is: {key!r}") log.debug(f"Key is: {key!r}")
log.debug("Creating required item...") log.debug("Creating required item...")
@ -135,7 +157,7 @@ class Configuration:
if not key: if not key:
log.debug("Determining key...") log.debug("Determining key...")
key: str = self._find_resolver_key(configurable) key = self._find_resolver_key(configurable)
log.debug(f"Key is: {key!r}") log.debug(f"Key is: {key!r}")
log.debug("Creating optional item...") log.debug("Creating optional item...")

View file

@ -1,6 +1,14 @@
class DefinitionError(Exception): class CfigError(Exception):
"""
Base class for all :mod:`cfig` errors.
"""
class DefinitionError(CfigError):
""" """
An error is present in the definition of a :class:`cfig.Configuration`. An error is present in the definition of a :class:`cfig.Configuration`.
This is a developer-side error: the user has no way to solve it.
""" """
@ -24,9 +32,11 @@ class DuplicateProxyNameError(ProxyRegistrationError):
""" """
class ConfigurationError(Exception): class ConfigurationError(CfigError):
""" """
An error is present in the configuration specified by the user. An error is present in the configuration specified by the user.
This is a user-side error: the developer of the application has no way to solve it.
""" """
@ -36,6 +46,18 @@ class MissingValueError(ConfigurationError):
""" """
class BatchResolutionFailure(BaseException):
"""
A cumulative error which sums the errors occurred while resolving proxied configuration values.
"""
def __init__(self, errors: dict[str, Exception]):
self.errors: dict[str, Exception] = errors
def __repr__(self):
return f"<{self.__class__.__qualname__}: {len(self.errors)} errors>"
__all__ = ( __all__ = (
"DefinitionError", "DefinitionError",
"UnknownResolverNameError", "UnknownResolverNameError",
@ -43,4 +65,5 @@ __all__ = (
"DuplicateProxyNameError", "DuplicateProxyNameError",
"ConfigurationError", "ConfigurationError",
"MissingValueError", "MissingValueError",
"BatchResolutionFailure",
) )

View file

@ -60,8 +60,9 @@ class TestConfig:
assert not os.environ.get("FIRST_NUMBER") assert not os.environ.get("FIRST_NUMBER")
assert not os.environ.get("SECOND_NUMBER") assert not os.environ.get("SECOND_NUMBER")
with pytest.raises(cfig.MissingValueError): with pytest.raises(cfig.BatchResolutionFailure) as ei:
numbers_config.proxies.resolve() numbers_config.proxies.resolve()
assert isinstance(ei.value.errors["FIRST_NUMBER"], cfig.MissingValueError)
def test_resolve_required(self, numbers_config, monkeypatch): def test_resolve_required(self, numbers_config, monkeypatch):
monkeypatch.setenv("FIRST_NUMBER", "1") monkeypatch.setenv("FIRST_NUMBER", "1")