mirror of
https://github.com/Steffo99/cfig.git
synced 2024-11-21 23:44:21 +00:00
✨ Accumulate resolution errors
This commit is contained in:
parent
d63a6fdc93
commit
df5443129c
3 changed files with 57 additions and 11 deletions
|
@ -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...")
|
||||||
|
|
|
@ -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",
|
||||||
)
|
)
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in a new issue