Coverage for src/typedconfig/errors.py: 100%
26 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-13 18:05 +0200
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-13 18:05 +0200
1"""
2Contains module-specific custom errors.
3"""
4import typing
5from dataclasses import dataclass
8class ConfigError(Exception):
9 """
10 Base exception class for this module.
11 """
14@dataclass
15class ConfigErrorMissingKey(ConfigError):
16 """
17 Exception for when the config file is missing a required key.
18 """
20 key: str
21 cls: type
22 annotated_type: type
24 def __post_init__(self) -> None:
25 """
26 Automatically filles in the names of annotated type and cls for printing from __str__.
27 """
28 self._annotated_type = self.annotated_type.__name__
29 self._cls = self.cls.__name__
31 def __str__(self) -> str:
32 """
33 Custom error message based on dataclass values and calculated actual type.
34 """
35 return (
36 f"Config key '{self.key}' (type `{self._annotated_type}`) "
37 f"of class `{self._cls}` was not found in the config, "
38 f"but is required as a default value is not specified."
39 )
42@dataclass
43class ConfigErrorInvalidType(ConfigError):
44 """
45 Exception for when the config file contains a key with an unexpected type.
46 """
48 key: str
49 value: typing.Any
50 expected_type: type
52 def __post_init__(self) -> None:
53 """
54 Store the actual type of the config variable.
55 """
56 self.actual_type = type(self.value)
58 max_len = 50
59 self._value = str(self.value)
60 if len(self._value) > max_len:
61 self._value = f"{self._value[:max_len]}..."
63 def __str__(self) -> str:
64 """
65 Custom error message based on dataclass values and calculated actual type.
66 """
67 return (
68 f"Config key '{self.key}' had a value (`{self._value}`) with a type (`{self.actual_type}`) "
69 f"that was not expected: `{self.expected_type}` is the required type."
70 )