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
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-22 21:20 +0000
1"""Custom exception classes for the settings module."""
3from collections.abc import Sequence
4from pathlib import Path
5from typing import Any
8class SettingsValueError(ValueError):
9 """A configured setting cannot be read safely.
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 """
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)
21 @property
22 def diagnostic(self) -> str:
23 """Return the setting key, its source and the reason, without a value.
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}"
32class EnvSettingError(ValueError):
33 """Base class for environment setting errors."""
35 def __init__(self, env_var: str, message: str):
36 self.env_var = env_var
37 super().__init__(f"{env_var}: {message}")
40class MissingEnvironmentVariableError(EnvSettingError):
41 """Raised when a required environment variable is not set."""
43 def __init__(self, env_var: str):
44 super().__init__(env_var, "Required environment variable is not set")
47class EnvironmentValueRangeError(EnvSettingError):
48 """Raised when an environment variable value is out of the allowed range."""
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)
62class EnvironmentPathNotFoundError(EnvSettingError):
63 """Raised when a path specified in an environment variable does not exist."""
65 def __init__(self, env_var: str, path: Path | str):
66 super().__init__(env_var, f"Path {path} does not exist")
69class InvalidEnvironmentValueError(EnvSettingError):
70 """Raised when an environment variable value fails its typed validation."""
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)