Update utils/error_handling.py
Browse files- utils/error_handling.py +128 -51
utils/error_handling.py
CHANGED
@@ -1,56 +1,133 @@
|
|
|
|
|
|
|
|
1 |
import logging
|
2 |
-
import
|
3 |
-
from
|
4 |
-
from
|
5 |
-
|
6 |
-
# Global logger configuration
|
7 |
-
LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
8 |
-
LOG_LEVEL = logging.INFO
|
9 |
-
|
10 |
-
def setup_logging(log_level=LOG_LEVEL):
|
11 |
-
"""Setup logging configuration"""
|
12 |
-
logging.basicConfig(
|
13 |
-
level=log_level,
|
14 |
-
format=LOG_FORMAT,
|
15 |
-
handlers=[
|
16 |
-
logging.StreamHandler(sys.stdout),
|
17 |
-
]
|
18 |
-
)
|
19 |
-
|
20 |
-
def get_logger(name):
|
21 |
-
"""Get a logger instance"""
|
22 |
-
return logging.getLogger(name)
|
23 |
-
|
24 |
-
def log_error(logger, error_msg, exception=None, context=None):
|
25 |
-
"""Log error with additional context"""
|
26 |
-
full_msg = f"{error_msg}"
|
27 |
-
if context:
|
28 |
-
full_msg += f" | Context: {context}"
|
29 |
-
if exception:
|
30 |
-
full_msg += f" | Exception: {str(exception)}"
|
31 |
-
|
32 |
-
logger.error(full_msg)
|
33 |
|
34 |
-
def log_info(logger, msg, context=None):
|
35 |
-
"""Log info with additional context"""
|
36 |
-
full_msg = f"{msg}"
|
37 |
-
if context:
|
38 |
-
full_msg += f" | Context: {context}"
|
39 |
-
|
40 |
-
logger.info(full_msg)
|
41 |
|
42 |
-
|
43 |
-
"""
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Error handling utilities for the application
|
3 |
+
"""
|
4 |
import logging
|
5 |
+
import traceback
|
6 |
+
from functools import wraps
|
7 |
+
from typing import Any, Callable, Optional, Union
|
8 |
+
import streamlit as st
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
+
class DataError(Exception):
|
12 |
+
"""Custom exception for data-related errors"""
|
13 |
+
pass
|
14 |
+
|
15 |
+
|
16 |
+
class ValidationError(Exception):
|
17 |
+
"""Custom exception for validation errors"""
|
18 |
+
pass
|
19 |
+
|
20 |
+
|
21 |
+
class ProcessingError(Exception):
|
22 |
+
"""Custom exception for processing errors"""
|
23 |
+
pass
|
24 |
+
|
25 |
+
|
26 |
+
def handle_data_exceptions(func: Callable) -> Callable:
|
27 |
+
"""
|
28 |
+
Decorator to handle data-related exceptions
|
29 |
+
"""
|
30 |
+
@wraps(func)
|
31 |
+
def wrapper(*args, **kwargs):
|
32 |
+
try:
|
33 |
+
return func(*args, **kwargs)
|
34 |
+
except (DataError, ValidationError, ProcessingError) as e:
|
35 |
+
logging.error(f"Data error in {func.__name__}: {str(e)}")
|
36 |
+
st.error(f"Data error: {str(e)}")
|
37 |
+
return None
|
38 |
+
except FileNotFoundError as e:
|
39 |
+
logging.error(f"File not found in {func.__name__}: {str(e)}")
|
40 |
+
st.error(f"File not found: {str(e)}")
|
41 |
+
return None
|
42 |
+
except PermissionError as e:
|
43 |
+
logging.error(f"Permission error in {func.__name__}: {str(e)}")
|
44 |
+
st.error(f"Permission error: {str(e)}")
|
45 |
+
return None
|
46 |
+
except Exception as e:
|
47 |
+
logging.error(f"Unexpected error in {func.__name__}: {str(e)}")
|
48 |
+
logging.error(traceback.format_exc())
|
49 |
+
st.error(f"An unexpected error occurred: {str(e)}")
|
50 |
+
return None
|
51 |
+
return wrapper
|
52 |
+
|
53 |
+
|
54 |
+
def handle_api_exceptions(func: Callable) -> Callable:
|
55 |
+
"""
|
56 |
+
Decorator to handle API-related exceptions
|
57 |
+
"""
|
58 |
+
@wraps(func)
|
59 |
+
def wrapper(*args, **kwargs):
|
60 |
+
try:
|
61 |
+
return func(*args, **kwargs)
|
62 |
+
except ConnectionError as e:
|
63 |
+
logging.error(f"Connection error in {func.__name__}: {str(e)}")
|
64 |
+
st.error("Connection error. Please check your internet connection.")
|
65 |
+
return None
|
66 |
+
except TimeoutError as e:
|
67 |
+
logging.error(f"Timeout error in {func.__name__}: {str(e)}")
|
68 |
+
st.error("Request timed out. Please try again.")
|
69 |
+
return None
|
70 |
+
except Exception as e:
|
71 |
+
logging.error(f"API error in {func.__name__}: {str(e)}")
|
72 |
+
st.error(f"API error: {str(e)}")
|
73 |
+
return None
|
74 |
+
return wrapper
|
75 |
|
76 |
+
|
77 |
+
def log_error(message: str, error: Optional[Exception] = None):
|
78 |
+
"""
|
79 |
+
Log an error message with optional exception details
|
80 |
+
"""
|
81 |
+
if error:
|
82 |
+
logging.error(f"{message}: {str(error)}")
|
83 |
+
logging.error(traceback.format_exc())
|
84 |
+
else:
|
85 |
+
logging.error(message)
|
86 |
+
|
87 |
+
|
88 |
+
def display_error(message: str, error_type: str = "error"):
|
89 |
+
"""
|
90 |
+
Display an error message in the Streamlit interface
|
91 |
+
"""
|
92 |
+
if error_type == "warning":
|
93 |
+
st.warning(message)
|
94 |
+
elif error_type == "info":
|
95 |
+
st.info(message)
|
96 |
+
else:
|
97 |
+
st.error(message)
|
98 |
+
|
99 |
+
|
100 |
+
def validate_input(value: Any, value_type: type, field_name: str) -> bool:
|
101 |
+
"""
|
102 |
+
Validate input value and type
|
103 |
+
"""
|
104 |
+
if value is None:
|
105 |
+
raise ValidationError(f"{field_name} cannot be None")
|
106 |
|
107 |
+
if not isinstance(value, value_type):
|
108 |
+
raise ValidationError(f"{field_name} must be of type {value_type.__name__}")
|
109 |
+
|
110 |
+
return True
|
111 |
+
|
112 |
+
|
113 |
+
def safe_execute(func: Callable, *args, **kwargs) -> tuple[bool, Any]:
|
114 |
+
"""
|
115 |
+
Safely execute a function and return success status and result
|
116 |
+
"""
|
117 |
+
try:
|
118 |
+
result = func(*args, **kwargs)
|
119 |
+
return True, result
|
120 |
+
except Exception as e:
|
121 |
+
log_error(f"Error executing {func.__name__}", e)
|
122 |
+
return False, str(e)
|
123 |
+
|
124 |
+
|
125 |
+
# Configure logging
|
126 |
+
logging.basicConfig(
|
127 |
+
level=logging.INFO,
|
128 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
129 |
+
handlers=[
|
130 |
+
logging.FileHandler('app.log'),
|
131 |
+
logging.StreamHandler()
|
132 |
+
]
|
133 |
+
)
|