Coverage for src/local_deep_research/settings/exceptions.py: 91%

38 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-22 21:20 +0000

1"""Custom exception classes for the settings module.""" 

2 

3from collections.abc import Sequence 

4from pathlib import Path 

5from typing import Any 

6 

7 

8class SettingsValueError(ValueError): 

9 """A configured setting cannot be read safely. 

10 

11 Include only the setting key, source and a fixed diagnostic reason. Values 

12 and the exceptions raised while parsing them may contain credentials. 

13 """ 

14 

15 def __init__(self, key: str, *, source: str, reason: str): 

16 self.key = key 

17 self.source = source 

18 self.reason = reason 

19 super().__init__(self.diagnostic) 

20 

21 @property 

22 def diagnostic(self) -> str: 

23 """Return the setting key, its source and the reason, without a value. 

24 

25 HTTP handlers return this text so an operator can locate the setting. 

26 It is rebuilt from the three fields rather than taken from the 

27 exception's arguments. 

28 """ 

29 return f"Invalid setting {self.key!r} from {self.source}: {self.reason}" 

30 

31 

32class EnvSettingError(ValueError): 

33 """Base class for environment setting errors.""" 

34 

35 def __init__(self, env_var: str, message: str): 

36 self.env_var = env_var 

37 super().__init__(f"{env_var}: {message}") 

38 

39 

40class MissingEnvironmentVariableError(EnvSettingError): 

41 """Raised when a required environment variable is not set.""" 

42 

43 def __init__(self, env_var: str): 

44 super().__init__(env_var, "Required environment variable is not set") 

45 

46 

47class EnvironmentValueRangeError(EnvSettingError): 

48 """Raised when an environment variable value is out of the allowed range.""" 

49 

50 def __init__( 

51 self, env_var: str, value: Any, min_val: Any = None, max_val: Any = None 

52 ): 

53 if min_val is not None and value < min_val: 

54 msg = f"value {value} is below minimum {min_val}" 

55 elif max_val is not None and value > max_val: 55 ↛ 58line 55 didn't jump to line 58 because the condition on line 55 was always true

56 msg = f"value {value} is above maximum {max_val}" 

57 else: 

58 msg = f"value {value} is out of range" 

59 super().__init__(env_var, msg) 

60 

61 

62class EnvironmentPathNotFoundError(EnvSettingError): 

63 """Raised when a path specified in an environment variable does not exist.""" 

64 

65 def __init__(self, env_var: str, path: Path | str): 

66 super().__init__(env_var, f"Path {path} does not exist") 

67 

68 

69class InvalidEnvironmentValueError(EnvSettingError): 

70 """Raised when an environment variable value fails its typed validation.""" 

71 

72 def __init__( 

73 self, 

74 env_var: str, 

75 value: str, 

76 allowed_values: Sequence[str] | None = None, 

77 expected_type: str | None = None, 

78 ): 

79 if expected_type is not None: 

80 message = "value '{}' is not a valid {}".format( 

81 value, expected_type 

82 ) 

83 elif allowed_values is not None: 83 ↛ 88line 83 didn't jump to line 88 because the condition on line 83 was always true

84 message = "value '{}' not in allowed values: {}".format( 

85 value, allowed_values 

86 ) 

87 else: 

88 message = "value '{}' is invalid".format(value) 

89 super().__init__(env_var, message)