mrradix commited on
Commit
c358a13
·
verified ·
1 Parent(s): 1c0efba

Update utils/error_handling.py

Browse files
Files changed (1) hide show
  1. utils/error_handling.py +37 -281
utils/error_handling.py CHANGED
@@ -1,25 +1,9 @@
1
- """
2
- Error handling module for the MONA application.
3
-
4
- This module provides standardized error handling patterns and custom exceptions
5
- for consistent error management across the application.
6
- """
7
-
8
- import traceback
9
- from functools import wraps
10
-
11
- from utils.logging import get_logger, log_error
12
-
13
- # Initialize logger
14
- logger = get_logger(__name__)
15
- # utils/error_handling.py
16
- import streamlit as st
17
  import traceback
18
  from typing import Any, Callable
19
  import functools
20
 
21
  # Import your logging utilities
22
- from utils.logging import get_logger
23
 
24
  # Custom exception classes
25
  class DataError(Exception):
@@ -30,8 +14,8 @@ class ValidationError(Exception):
30
  """Custom exception for validation errors"""
31
  pass
32
 
33
- # Get logger without passing __name__ if get_logger() doesn't accept arguments
34
- logger = get_logger() # Remove __name__ argument
35
 
36
  def handle_data_exceptions(func: Callable) -> Callable:
37
  """
@@ -48,13 +32,14 @@ def handle_data_exceptions(func: Callable) -> Callable:
48
  try:
49
  return func(*args, **kwargs)
50
  except (DataError, ValidationError) as e:
51
- logger.error(f"Data handling error in {func.__name__}: {str(e)}")
52
- st.error(f"Data Error: {str(e)}")
 
53
  return None
54
  except Exception as e:
55
- logger.error(f"Unexpected error in {func.__name__}: {str(e)}")
56
- logger.error(f"Traceback: {traceback.format_exc()}")
57
- st.error(f"An unexpected error occurred: {str(e)}")
58
  return None
59
 
60
  return wrapper
@@ -77,11 +62,14 @@ def validate_data(data: Any, data_type: str) -> bool:
77
  raise ValidationError(f"Data cannot be None for type: {data_type}")
78
 
79
  if data_type == "dataframe":
80
- import pandas as pd
81
- if not isinstance(data, pd.DataFrame):
82
- raise ValidationError("Expected pandas DataFrame")
83
- if data.empty:
84
- raise ValidationError("DataFrame cannot be empty")
 
 
 
85
 
86
  elif data_type == "list":
87
  if not isinstance(data, list):
@@ -97,264 +85,32 @@ def validate_data(data: Any, data_type: str) -> bool:
97
 
98
  return True
99
 
100
- # Custom exceptions
101
- class MonaError(Exception):
102
- """Base exception class for all MONA application errors."""
103
- def __init__(self, message, details=None):
104
- self.message = message
105
- self.details = details
106
- super().__init__(self.message)
107
-
108
-
109
- class DataError(MonaError):
110
- """Exception raised for errors related to data operations."""
111
- pass
112
-
113
-
114
- class AIModelError(MonaError):
115
- """Exception raised for errors related to AI model operations."""
116
- pass
117
-
118
-
119
- class ValidationError(MonaError):
120
- """Exception raised for validation errors."""
121
- pass
122
-
123
-
124
- class IntegrationError(MonaError):
125
- """Exception raised for errors related to external integrations."""
126
- pass
127
-
128
-
129
- class ConfigurationError(MonaError):
130
- """Exception raised for configuration errors."""
131
- pass
132
-
133
-
134
- class UserInputError(MonaError):
135
- """Exception raised for invalid user input."""
136
- pass
137
-
138
-
139
- # Error handling decorators
140
- def handle_exceptions(func):
141
- """
142
- Decorator to handle exceptions in a standardized way.
143
-
144
- Args:
145
- func (callable): The function to decorate.
146
-
147
- Returns:
148
- callable: The decorated function.
149
- """
150
- @wraps(func)
151
- def wrapper(*args, **kwargs):
152
- try:
153
- return func(*args, **kwargs)
154
- except MonaError as e:
155
- # Log the custom exception
156
- log_error(f"{type(e).__name__}: {e.message}", exc_info=e)
157
- # Return a user-friendly error message
158
- return {
159
- "success": False,
160
- "error": {
161
- "type": type(e).__name__,
162
- "message": e.message,
163
- "details": e.details
164
- }
165
- }
166
- except Exception as e:
167
- # Log unexpected exceptions
168
- log_error(f"Unexpected error in {func.__name__}: {str(e)}", exc_info=e)
169
- # Return a generic error message
170
- return {
171
- "success": False,
172
- "error": {
173
- "type": "UnexpectedError",
174
- "message": "An unexpected error occurred. Please try again later.",
175
- "details": str(e) if __debug__ else None
176
- }
177
- }
178
- return wrapper
179
-
180
-
181
- def handle_ui_exceptions(func):
182
  """
183
- Decorator to handle exceptions in UI components.
184
-
185
- Args:
186
- func (callable): The function to decorate.
187
-
188
- Returns:
189
- callable: The decorated function.
190
- """
191
- @wraps(func)
192
- def wrapper(*args, **kwargs):
193
- try:
194
- return func(*args, **kwargs)
195
- except MonaError as e:
196
- # Log the custom exception
197
- log_error(f"UI Error - {type(e).__name__}: {e.message}", exc_info=e)
198
- # Return a user-friendly error message for UI display
199
- return f"Error: {e.message}"
200
- except Exception as e:
201
- # Log unexpected exceptions
202
- log_error(f"Unexpected UI error in {func.__name__}: {str(e)}", exc_info=e)
203
- # Return a generic error message for UI display
204
- return "An unexpected error occurred. Please try again later."
205
- return wrapper
206
-
207
-
208
- def handle_data_exceptions(func):
209
  """
210
- Decorator to handle exceptions in data operations.
211
-
212
- Args:
213
- func (callable): The function to decorate.
214
-
215
- Returns:
216
- callable: The decorated function.
217
- """
218
- @wraps(func)
219
- def wrapper(*args, **kwargs):
220
- try:
221
- return func(*args, **kwargs)
222
- except (FileNotFoundError, PermissionError, IOError) as e:
223
- # Convert to custom exception
224
- raise DataError(f"Data access error: {str(e)}", {
225
- "original_error": str(e),
226
- "traceback": traceback.format_exc()
227
- }) from e
228
- except Exception as e:
229
- # Convert to custom exception
230
- raise DataError(f"Unexpected data error: {str(e)}", {
231
- "original_error": str(e),
232
- "traceback": traceback.format_exc()
233
- }) from e
234
- return wrapper
235
-
236
-
237
- def handle_ai_model_exceptions(func):
238
- """
239
- Decorator to handle exceptions in AI model operations.
240
-
241
- Args:
242
- func (callable): The function to decorate.
243
-
244
- Returns:
245
- callable: The decorated function.
246
- """
247
- @wraps(func)
248
- def wrapper(*args, **kwargs):
249
- try:
250
- return func(*args, **kwargs)
251
- except Exception as e:
252
- # Convert to custom exception
253
- raise AIModelError(f"AI model error: {str(e)}", {
254
- "original_error": str(e),
255
- "traceback": traceback.format_exc()
256
- }) from e
257
- return wrapper
258
-
259
-
260
- # Validation functions
261
- def validate_input(data, schema):
262
- """
263
- Validate input data against a schema.
264
-
265
- Args:
266
- data (dict): The input data to validate.
267
- schema (dict): The schema to validate against.
268
-
269
- Raises:
270
- ValidationError: If validation fails.
271
- """
272
- errors = []
273
-
274
- # Check required fields
275
- for field in schema.get("required", []):
276
- if field not in data:
277
- errors.append(f"Missing required field: {field}")
278
-
279
- # Check field types
280
- for field, field_schema in schema.get("properties", {}).items():
281
- if field in data and data[field] is not None:
282
- expected_type = field_schema.get("type")
283
- if expected_type == "string" and not isinstance(data[field], str):
284
- errors.append(f"Field {field} must be a string")
285
- elif expected_type == "number" and not isinstance(data[field], (int, float)):
286
- errors.append(f"Field {field} must be a number")
287
- elif expected_type == "integer" and not isinstance(data[field], int):
288
- errors.append(f"Field {field} must be an integer")
289
- elif expected_type == "boolean" and not isinstance(data[field], bool):
290
- errors.append(f"Field {field} must be a boolean")
291
- elif expected_type == "array" and not isinstance(data[field], list):
292
- errors.append(f"Field {field} must be an array")
293
- elif expected_type == "object" and not isinstance(data[field], dict):
294
- errors.append(f"Field {field} must be an object")
295
-
296
- if errors:
297
- raise ValidationError("Validation failed", {"errors": errors})
298
-
299
-
300
- def safe_get(dictionary, key, default=None):
301
- """Safely get a value from dict/object with fallback."""
302
  try:
303
- return dictionary[key]
304
- except KeyError:
305
- return default
306
- """
307
- Safely get a value from a nested dictionary.
308
-
309
- Args:
310
- data (dict): The dictionary to get the value from.
311
- path (str): The path to the value, using dot notation (e.g., "user.profile.name").
312
- default: The default value to return if the path doesn't exist.
313
-
314
- Returns:
315
- The value at the specified path, or the default value if the path doesn't exist.
316
- """
317
- keys = path.split('.')
318
- result = data
319
-
320
- try:
321
- for key in keys:
322
- if isinstance(result, dict):
323
- result = result.get(key, default)
324
- else:
325
- return default
326
- return result
327
- except Exception:
328
- return default
329
-
330
 
331
- # Error formatting functions
332
- def format_error_for_user(error):
333
  """
334
- Format an error for user display.
335
-
336
- Args:
337
- error (Exception): The error to format.
338
-
339
- Returns:
340
- str: A user-friendly error message.
341
  """
342
- if isinstance(error, MonaError):
343
- return error.message
344
- return "An unexpected error occurred. Please try again later."
345
-
 
346
 
347
- def format_error_for_log(error):
348
  """
349
- Format an error for logging.
350
-
351
- Args:
352
- error (Exception): The error to format.
353
-
354
- Returns:
355
- str: A detailed error message for logging.
356
  """
357
- if isinstance(error, MonaError):
358
- details = error.details if error.details else {}
359
- return f"{type(error).__name__}: {error.message} - {details}"
360
- return f"{type(error).__name__}: {str(error)}\n{traceback.format_exc()}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import traceback
2
  from typing import Any, Callable
3
  import functools
4
 
5
  # Import your logging utilities
6
+ from utils.logging import get_logger, log_error
7
 
8
  # Custom exception classes
9
  class DataError(Exception):
 
14
  """Custom exception for validation errors"""
15
  pass
16
 
17
+ # Get logger
18
+ logger = get_logger(__name__)
19
 
20
  def handle_data_exceptions(func: Callable) -> Callable:
21
  """
 
32
  try:
33
  return func(*args, **kwargs)
34
  except (DataError, ValidationError) as e:
35
+ log_error(logger, f"Data handling error in {func.__name__}: {str(e)}")
36
+ # Instead of streamlit error, we'll raise the exception or return None
37
+ print(f"Data Error: {str(e)}")
38
  return None
39
  except Exception as e:
40
+ log_error(logger, f"Unexpected error in {func.__name__}: {str(e)}")
41
+ log_error(logger, f"Traceback: {traceback.format_exc()}")
42
+ print(f"An unexpected error occurred: {str(e)}")
43
  return None
44
 
45
  return wrapper
 
62
  raise ValidationError(f"Data cannot be None for type: {data_type}")
63
 
64
  if data_type == "dataframe":
65
+ try:
66
+ import pandas as pd
67
+ if not isinstance(data, pd.DataFrame):
68
+ raise ValidationError("Expected pandas DataFrame")
69
+ if data.empty:
70
+ raise ValidationError("DataFrame cannot be empty")
71
+ except ImportError:
72
+ raise ValidationError("pandas not available for DataFrame validation")
73
 
74
  elif data_type == "list":
75
  if not isinstance(data, list):
 
85
 
86
  return True
87
 
88
+ def show_error(message: str):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  """
90
+ Display error message (streamlit-safe)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  try:
93
+ import streamlit as st
94
+ st.error(message)
95
+ except ImportError:
96
+ print(f"ERROR: {message}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
+ def show_warning(message: str):
 
99
  """
100
+ Display warning message (streamlit-safe)
 
 
 
 
 
 
101
  """
102
+ try:
103
+ import streamlit as st
104
+ st.warning(message)
105
+ except ImportError:
106
+ print(f"WARNING: {message}")
107
 
108
+ def show_success(message: str):
109
  """
110
+ Display success message (streamlit-safe)
 
 
 
 
 
 
111
  """
112
+ try:
113
+ import streamlit as st
114
+ st.success(message)
115
+ except ImportError:
116
+ print(f"SUCCESS: {message}")