MogensR commited on
Commit
ae9fc35
·
1 Parent(s): b06a17f

Create exceptions.py

Browse files
Files changed (1) hide show
  1. exceptions.py +287 -0
exceptions.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Custom Exception Classes
3
+ Provides specific exception types for better error handling and debugging
4
+ """
5
+
6
+ from typing import Optional, Any, Dict
7
+
8
+ class VideoProcessingError(Exception):
9
+ """Base exception for video processing errors"""
10
+
11
+ def __init__(self, message: str, error_code: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
12
+ super().__init__(message)
13
+ self.message = message
14
+ self.error_code = error_code
15
+ self.details = details or {}
16
+
17
+ def __str__(self):
18
+ base_msg = self.message
19
+ if self.error_code:
20
+ base_msg = f"[{self.error_code}] {base_msg}"
21
+ if self.details:
22
+ details_str = ", ".join(f"{k}: {v}" for k, v in self.details.items())
23
+ base_msg = f"{base_msg} ({details_str})"
24
+ return base_msg
25
+
26
+ class ModelLoadingError(VideoProcessingError):
27
+ """Exception raised when model loading fails"""
28
+
29
+ def __init__(self, model_name: str, message: str, original_error: Optional[Exception] = None):
30
+ super().__init__(
31
+ message=f"Failed to load {model_name}: {message}",
32
+ error_code="MODEL_LOAD_FAILED",
33
+ details={
34
+ "model_name": model_name,
35
+ "original_error": str(original_error) if original_error else None
36
+ }
37
+ )
38
+ self.model_name = model_name
39
+ self.original_error = original_error
40
+
41
+ class DeviceError(VideoProcessingError):
42
+ """Exception raised when device-related operations fail"""
43
+
44
+ def __init__(self, device_type: str, message: str, available_devices: Optional[list] = None):
45
+ super().__init__(
46
+ message=f"Device error ({device_type}): {message}",
47
+ error_code="DEVICE_ERROR",
48
+ details={
49
+ "device_type": device_type,
50
+ "available_devices": available_devices
51
+ }
52
+ )
53
+ self.device_type = device_type
54
+ self.available_devices = available_devices or []
55
+
56
+ class MemoryError(VideoProcessingError):
57
+ """Exception raised when memory operations fail"""
58
+
59
+ def __init__(self, operation: str, message: str, memory_usage: Optional[Dict[str, Any]] = None):
60
+ super().__init__(
61
+ message=f"Memory error during {operation}: {message}",
62
+ error_code="MEMORY_ERROR",
63
+ details={
64
+ "operation": operation,
65
+ "memory_usage": memory_usage
66
+ }
67
+ )
68
+ self.operation = operation
69
+ self.memory_usage = memory_usage or {}
70
+
71
+ class VideoFileError(VideoProcessingError):
72
+ """Exception raised when video file operations fail"""
73
+
74
+ def __init__(self, file_path: str, operation: str, message: str):
75
+ super().__init__(
76
+ message=f"Video file error ({operation}): {message}",
77
+ error_code="VIDEO_FILE_ERROR",
78
+ details={
79
+ "file_path": file_path,
80
+ "operation": operation
81
+ }
82
+ )
83
+ self.file_path = file_path
84
+ self.operation = operation
85
+
86
+ class BackgroundProcessingError(VideoProcessingError):
87
+ """Exception raised when background processing fails"""
88
+
89
+ def __init__(self, background_type: str, message: str, background_path: Optional[str] = None):
90
+ super().__init__(
91
+ message=f"Background processing error ({background_type}): {message}",
92
+ error_code="BACKGROUND_ERROR",
93
+ details={
94
+ "background_type": background_type,
95
+ "background_path": background_path
96
+ }
97
+ )
98
+ self.background_type = background_type
99
+ self.background_path = background_path
100
+
101
+ class SegmentationError(VideoProcessingError):
102
+ """Exception raised when person segmentation fails"""
103
+
104
+ def __init__(self, frame_number: int, message: str, segmentation_method: Optional[str] = None):
105
+ super().__init__(
106
+ message=f"Segmentation error at frame {frame_number}: {message}",
107
+ error_code="SEGMENTATION_ERROR",
108
+ details={
109
+ "frame_number": frame_number,
110
+ "segmentation_method": segmentation_method
111
+ }
112
+ )
113
+ self.frame_number = frame_number
114
+ self.segmentation_method = segmentation_method
115
+
116
+ class AudioProcessingError(VideoProcessingError):
117
+ """Exception raised when audio processing fails"""
118
+
119
+ def __init__(self, operation: str, message: str, input_file: Optional[str] = None, output_file: Optional[str] = None):
120
+ super().__init__(
121
+ message=f"Audio processing error ({operation}): {message}",
122
+ error_code="AUDIO_ERROR",
123
+ details={
124
+ "operation": operation,
125
+ "input_file": input_file,
126
+ "output_file": output_file
127
+ }
128
+ )
129
+ self.operation = operation
130
+ self.input_file = input_file
131
+ self.output_file = output_file
132
+
133
+ class ConfigurationError(VideoProcessingError):
134
+ """Exception raised when configuration is invalid"""
135
+
136
+ def __init__(self, config_key: str, value: Any, expected: str):
137
+ super().__init__(
138
+ message=f"Invalid configuration: {config_key} = {value}, expected {expected}",
139
+ error_code="CONFIG_ERROR",
140
+ details={
141
+ "config_key": config_key,
142
+ "value": value,
143
+ "expected": expected
144
+ }
145
+ )
146
+ self.config_key = config_key
147
+ self.value = value
148
+ self.expected = expected
149
+
150
+ class ProcessingCancelledError(VideoProcessingError):
151
+ """Exception raised when processing is cancelled by user"""
152
+
153
+ def __init__(self, stage: str, processed_frames: int = 0, total_frames: int = 0):
154
+ super().__init__(
155
+ message=f"Processing cancelled at {stage}",
156
+ error_code="PROCESSING_CANCELLED",
157
+ details={
158
+ "stage": stage,
159
+ "processed_frames": processed_frames,
160
+ "total_frames": total_frames,
161
+ "completion_percentage": (processed_frames / total_frames * 100) if total_frames > 0 else 0
162
+ }
163
+ )
164
+ self.stage = stage
165
+ self.processed_frames = processed_frames
166
+ self.total_frames = total_frames
167
+
168
+ class TwoStageProcessingError(VideoProcessingError):
169
+ """Exception raised during two-stage processing"""
170
+
171
+ def __init__(self, stage: str, message: str, chroma_preset: Optional[str] = None):
172
+ super().__init__(
173
+ message=f"Two-stage processing error ({stage}): {message}",
174
+ error_code="TWO_STAGE_ERROR",
175
+ details={
176
+ "stage": stage,
177
+ "chroma_preset": chroma_preset
178
+ }
179
+ )
180
+ self.stage = stage
181
+ self.chroma_preset = chroma_preset
182
+
183
+ class ResourceExhaustionError(VideoProcessingError):
184
+ """Exception raised when system resources are exhausted"""
185
+
186
+ def __init__(self, resource_type: str, current_usage: float, limit: float, unit: str = ""):
187
+ super().__init__(
188
+ message=f"Resource exhaustion: {resource_type} usage {current_usage}{unit} exceeds limit {limit}{unit}",
189
+ error_code="RESOURCE_EXHAUSTION",
190
+ details={
191
+ "resource_type": resource_type,
192
+ "current_usage": current_usage,
193
+ "limit": limit,
194
+ "unit": unit
195
+ }
196
+ )
197
+ self.resource_type = resource_type
198
+ self.current_usage = current_usage
199
+ self.limit = limit
200
+ self.unit = unit
201
+
202
+ class ValidationError(VideoProcessingError):
203
+ """Exception raised when input validation fails"""
204
+
205
+ def __init__(self, validation_type: str, message: str, invalid_value: Any = None):
206
+ super().__init__(
207
+ message=f"Validation error ({validation_type}): {message}",
208
+ error_code="VALIDATION_ERROR",
209
+ details={
210
+ "validation_type": validation_type,
211
+ "invalid_value": invalid_value
212
+ }
213
+ )
214
+ self.validation_type = validation_type
215
+ self.invalid_value = invalid_value
216
+
217
+ # Utility functions for error handling
218
+
219
+ def handle_processing_error(func):
220
+ """Decorator to handle common processing errors"""
221
+ def wrapper(*args, **kwargs):
222
+ try:
223
+ return func(*args, **kwargs)
224
+ except VideoProcessingError:
225
+ # Re-raise our custom exceptions
226
+ raise
227
+ except MemoryError as e:
228
+ raise MemoryError("memory_operation", str(e)) from e
229
+ except FileNotFoundError as e:
230
+ raise VideoFileError(str(e.filename) if e.filename else "unknown", "file_access", str(e)) from e
231
+ except PermissionError as e:
232
+ raise VideoFileError(str(e.filename) if e.filename else "unknown", "file_permission", str(e)) from e
233
+ except Exception as e:
234
+ raise VideoProcessingError(f"Unexpected error in {func.__name__}: {str(e)}") from e
235
+ return wrapper
236
+
237
+ def create_error_context(operation: str, **context) -> Dict[str, Any]:
238
+ """Create error context dictionary"""
239
+ return {
240
+ "operation": operation,
241
+ "timestamp": __import__('time').time(),
242
+ **context
243
+ }
244
+
245
+ def log_error_with_context(logger, error: VideoProcessingError, additional_context: Optional[Dict[str, Any]] = None):
246
+ """Log error with full context information"""
247
+ context = error.details.copy()
248
+ if additional_context:
249
+ context.update(additional_context)
250
+
251
+ logger.error(f"{error} | Context: {context}")
252
+
253
+ # Log original error if available
254
+ if hasattr(error, 'original_error') and error.original_error:
255
+ logger.error(f"Original error: {error.original_error}")
256
+
257
+ def is_recoverable_error(error: Exception) -> bool:
258
+ """Determine if an error is potentially recoverable"""
259
+ recoverable_errors = (
260
+ MemoryError,
261
+ ResourceExhaustionError,
262
+ DeviceError
263
+ )
264
+
265
+ # Check if it's a recoverable error type
266
+ if isinstance(error, recoverable_errors):
267
+ return True
268
+
269
+ # Check if it's a processing error with specific codes that might be recoverable
270
+ if isinstance(error, VideoProcessingError):
271
+ recoverable_codes = ["MEMORY_ERROR", "DEVICE_ERROR", "RESOURCE_EXHAUSTION"]
272
+ return error.error_code in recoverable_codes
273
+
274
+ return False
275
+
276
+ def get_error_severity(error: Exception) -> str:
277
+ """Get error severity level"""
278
+ if isinstance(error, ProcessingCancelledError):
279
+ return "INFO"
280
+ elif isinstance(error, ValidationError):
281
+ return "WARNING"
282
+ elif isinstance(error, (ModelLoadingError, DeviceError)):
283
+ return "CRITICAL"
284
+ elif isinstance(error, VideoProcessingError):
285
+ return "ERROR"
286
+ else:
287
+ return "UNKNOWN"