Coverage for src / dataknobs_common / exceptions.py: 87%

23 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-08 17:37 -0700

1"""Common exception hierarchy for all dataknobs packages. 

2 

3This module provides a unified exception framework that all dataknobs packages 

4can extend. It supports both simple exceptions and context-rich exceptions with 

5detailed error information. 

6 

7The exception hierarchy supports: 

8- Simple error messages for straightforward cases 

9- Context dictionaries for rich error information 

10- Details dictionaries (FSM-style) for structured error data 

11- Package-specific extensions 

12 

13Example: 

14 ```python 

15 from dataknobs_common.exceptions import ValidationError, NotFoundError 

16 

17 # Simple exception 

18 raise ValidationError("Invalid email format") 

19 

20 # Context-rich exception 

21 raise NotFoundError( 

22 "User not found", 

23 context={"user_id": "123", "attempted_at": "2024-11-08"} 

24 ) 

25 

26 # Catch any dataknobs error 

27 try: 

28 operation() 

29 except DataknobsError as e: 

30 logger.error(f"Error: {e}") 

31 if e.context: 

32 logger.error(f"Context: {e.context}") 

33 ``` 

34 

35Package-Specific Extensions: 

36 ```python 

37 from dataknobs_common.exceptions import DataknobsError 

38 

39 class MyPackageError(DataknobsError): 

40 '''Base exception for mypackage.''' 

41 pass 

42 

43 class SpecificError(MyPackageError): 

44 '''Specific error with custom context.''' 

45 def __init__(self, item_id: str, message: str): 

46 super().__init__( 

47 f"Item '{item_id}': {message}", 

48 context={"item_id": item_id} 

49 ) 

50 ``` 

51""" 

52 

53from typing import Any, Dict 

54 

55 

56class DataknobsError(Exception): 

57 """Base exception for all dataknobs packages. 

58 

59 This is the root exception that all dataknobs packages should extend. 

60 It supports optional context data for rich error information, making 

61 debugging and error handling more effective. 

62 

63 Attributes: 

64 context: Dictionary containing contextual information about the error 

65 details: Alias for context (FSM-style compatibility) 

66 

67 Args: 

68 message: Human-readable error message 

69 context: Optional dictionary with error context (field names, IDs, etc.) 

70 details: Alternative to context (both are supported for compatibility) 

71 

72 Example: 

73 ```python 

74 error = DataknobsError( 

75 "Operation failed", 

76 context={"operation": "save", "item_id": "123"} 

77 ) 

78 str(error) 

79 # 'Operation failed' 

80 error.context 

81 # {'operation': 'save', 'item_id': '123'} 

82 ``` 

83 """ 

84 

85 def __init__( 

86 self, 

87 message: str, 

88 context: Dict[str, Any] | None = None, 

89 details: Dict[str, Any] | None = None, 

90 ): 

91 """Initialize the exception with optional context. 

92 

93 Args: 

94 message: Error message 

95 context: Optional context dictionary 

96 details: Optional details dictionary (merged with context) 

97 """ 

98 super().__init__(message) 

99 # Support both context and details parameters 

100 # Details takes precedence if both are provided 

101 self.context = details or context or {} 

102 # Alias for FSM-style compatibility 

103 self.details = self.context 

104 

105 

106class ValidationError(DataknobsError): 

107 """Raised when validation fails. 

108 

109 Use this exception when data or configuration fails validation checks. 

110 Common scenarios include: 

111 - Invalid input data 

112 - Schema validation failures 

113 - Constraint violations 

114 - Type mismatches 

115 

116 Example: 

117 ```python 

118 raise ValidationError( 

119 "Email format invalid", 

120 context={"field": "email", "value": "not-an-email"} 

121 ) 

122 ``` 

123 """ 

124 

125 pass 

126 

127 

128class ConfigurationError(DataknobsError): 

129 """Raised when configuration is invalid or missing. 

130 

131 Use this exception for configuration-related errors including: 

132 - Missing required configuration 

133 - Invalid configuration values 

134 - Configuration file not found 

135 - Circular references in configuration 

136 

137 Example: 

138 ```python 

139 raise ConfigurationError( 

140 "Database configuration missing", 

141 context={"config_key": "database.primary", "available_keys": ["cache", "auth"]} 

142 ) 

143 ``` 

144 """ 

145 

146 pass 

147 

148 

149class ResourceError(DataknobsError): 

150 """Raised when resource operations fail. 

151 

152 Use this exception for resource management failures including: 

153 - Resource acquisition failures 

154 - Connection errors 

155 - Resource pool exhaustion 

156 - Timeout errors 

157 

158 Example: 

159 ```python 

160 raise ResourceError( 

161 "Failed to acquire database connection", 

162 context={"pool_size": 10, "active_connections": 10, "timeout": 30} 

163 ) 

164 ``` 

165 """ 

166 

167 pass 

168 

169 

170class NotFoundError(DataknobsError): 

171 """Raised when a requested item is not found. 

172 

173 Use this exception when looking up items by ID, name, or key and they 

174 don't exist. Common scenarios include: 

175 - Record not found in database 

176 - Configuration key not found 

177 - File not found 

178 - Resource not registered 

179 

180 Example: 

181 ```python 

182 raise NotFoundError( 

183 "Record not found", 

184 context={"record_id": "user-123", "table": "users"} 

185 ) 

186 ``` 

187 """ 

188 

189 pass 

190 

191 

192class OperationError(DataknobsError): 

193 """Raised when an operation fails. 

194 

195 Use this exception for general operation failures that don't fit 

196 other categories. Common scenarios include: 

197 - Database operation failures 

198 - File I/O errors 

199 - Network operation failures 

200 - State transition errors 

201 

202 Example: 

203 ```python 

204 raise OperationError( 

205 "Failed to save record", 

206 context={"operation": "update", "backend": "postgres", "error": "connection lost"} 

207 ) 

208 ``` 

209 """ 

210 

211 pass 

212 

213 

214class ConcurrencyError(DataknobsError): 

215 """Raised when concurrent operation conflicts occur. 

216 

217 Use this exception for concurrency-related failures including: 

218 - Lock acquisition failures 

219 - Transaction conflicts 

220 - Race conditions 

221 - Optimistic locking failures 

222 

223 Example: 

224 ```python 

225 raise ConcurrencyError( 

226 "Record modified by another process", 

227 context={"record_id": "123", "expected_version": 5, "actual_version": 6} 

228 ) 

229 ``` 

230 """ 

231 

232 pass 

233 

234 

235class SerializationError(DataknobsError): 

236 """Raised when serialization or deserialization fails. 

237 

238 Use this exception for data format conversion errors including: 

239 - JSON encoding/decoding failures 

240 - Invalid data format 

241 - Schema mismatch 

242 - Type conversion errors 

243 

244 Example: 

245 ```python 

246 raise SerializationError( 

247 "Cannot deserialize data", 

248 context={"format": "json", "field": "created_at", "value": "invalid-date"} 

249 ) 

250 ``` 

251 """ 

252 

253 pass 

254 

255 

256class TimeoutError(DataknobsError): 

257 """Raised when an operation times out. 

258 

259 Use this exception when operations exceed their time limit including: 

260 - Connection timeouts 

261 - Query timeouts 

262 - Resource acquisition timeouts 

263 - Operation execution timeouts 

264 

265 Example: 

266 ```python 

267 raise TimeoutError( 

268 "Database query timed out", 

269 context={"query": "SELECT * FROM large_table", "timeout_seconds": 30} 

270 ) 

271 ``` 

272 """ 

273 

274 pass 

275 

276 

277__all__ = [ 

278 "DataknobsError", 

279 "ValidationError", 

280 "ConfigurationError", 

281 "ResourceError", 

282 "NotFoundError", 

283 "OperationError", 

284 "ConcurrencyError", 

285 "SerializationError", 

286 "TimeoutError", 

287]