Spaces:
Sleeping
Sleeping
devjas1
commited on
Commit
Β·
177dc98
1
Parent(s):
566edf3
(FEAT) add centralized error handling utilty for the polymer classification app: utils/error.py
Browse filesImproves code maintainability and clarity
Lays groundwork for consistent error management across the project
- utils/errors.py +126 -0
utils/errors.py
CHANGED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Centralized error handling utility for the polymer classification app.
|
| 2 |
+
Provides consistent error logging and graceful UI error reporting"""
|
| 3 |
+
|
| 4 |
+
import streamlit as st
|
| 5 |
+
import traceback
|
| 6 |
+
|
| 7 |
+
# Define a constant for error messages
|
| 8 |
+
ERROR = "[ERROR]"
|
| 9 |
+
|
| 10 |
+
class ErrorHandler:
|
| 11 |
+
"""Centralized error handler for the application"""
|
| 12 |
+
|
| 13 |
+
@staticmethod
|
| 14 |
+
def log_error(error: Exception, context: str = "", include_traceback: bool = False) -> None:
|
| 15 |
+
"""Log error to session state for display in UI"""
|
| 16 |
+
if "log_messages" not in st.session_state:
|
| 17 |
+
st.session_state["log_messages"] = []
|
| 18 |
+
|
| 19 |
+
error_msg = f"{ERROR} {context}: {str(error)}" if context else f"{ERROR} {str(error)}"
|
| 20 |
+
|
| 21 |
+
if include_traceback:
|
| 22 |
+
error_msg += f"\nTraceback: {traceback.format_exc()}"
|
| 23 |
+
|
| 24 |
+
st.session_state["log_messages"].append(error_msg)
|
| 25 |
+
|
| 26 |
+
@staticmethod
|
| 27 |
+
def log_warning(message: str, context: str = "") -> None:
|
| 28 |
+
"""Log warning to session state"""
|
| 29 |
+
if "log_messages" not in st.session_state:
|
| 30 |
+
st.session_state["log_messages"] = []
|
| 31 |
+
|
| 32 |
+
warning_msg = f"[WARNING] {context}: {message}" if context else f"[WARNING] {message}"
|
| 33 |
+
st.session_state["log_messages"].append(warning_msg)
|
| 34 |
+
|
| 35 |
+
@staticmethod
|
| 36 |
+
def log_info(message: str, context: str = "") -> None:
|
| 37 |
+
"""Log info message to session state"""
|
| 38 |
+
if "log_messages" not in st.session_state:
|
| 39 |
+
st.session_state["log_messages"] = []
|
| 40 |
+
|
| 41 |
+
info_msg = f"[INFO] {context}: {message}" if context else f"[INFO] {message}"
|
| 42 |
+
st.session_state["log_messages"].append(info_msg)
|
| 43 |
+
|
| 44 |
+
@staticmethod
|
| 45 |
+
def handle_file_error(filename: str, error: Exception) -> str:
|
| 46 |
+
"""Handle file processing errors and return user-friendly message"""
|
| 47 |
+
ErrorHandler.log_error(error, f"File processing: {filename}")
|
| 48 |
+
|
| 49 |
+
if isinstance(error, FileNotFoundError):
|
| 50 |
+
return f"β File not found: {filename}"
|
| 51 |
+
elif isinstance(error, PermissionError):
|
| 52 |
+
return f"β Permission denied accessing: {filename}"
|
| 53 |
+
elif isinstance(error, (ValueError, TypeError)):
|
| 54 |
+
return f"β Invalid file format in: {filename}. Please ensure it contains wavenumber and intensity columns."
|
| 55 |
+
else:
|
| 56 |
+
return f"β Error processing file: {filename}. {str(error)}"
|
| 57 |
+
|
| 58 |
+
@staticmethod
|
| 59 |
+
def handle_inference_error(model_name: str, error: Exception) -> str:
|
| 60 |
+
"""Handle model inference errors and return user-friendly message"""
|
| 61 |
+
ErrorHandler.log_error(error, f"Model inference: {model_name}")
|
| 62 |
+
|
| 63 |
+
if "CUDA" in str(error) or "device" in str(error).lower():
|
| 64 |
+
return f"β Device error with model {model_name}. Falling back to CPU."
|
| 65 |
+
elif "shape" in str(error).lower() or "dimension" in str(error).lower():
|
| 66 |
+
return f"β Input shape mismatch for model {model_name}. Please check spectrum data format."
|
| 67 |
+
else:
|
| 68 |
+
return f"β Inference failed for model {model_name}: {str(error)}"
|
| 69 |
+
|
| 70 |
+
@staticmethod
|
| 71 |
+
def handle_parsing_error(filename: str, error: Exception) -> str:
|
| 72 |
+
"""Handle spectrum parsing errors and return user-friendly message"""
|
| 73 |
+
ErrorHandler.log_error(error, f"Spectrum parsing: {filename}")
|
| 74 |
+
|
| 75 |
+
if "could not convert" in str(error).lower():
|
| 76 |
+
return f"β Invalid data format in {filename}. Expected numeric wavenumber and intensity columns."
|
| 77 |
+
elif "empty" in str(error).lower():
|
| 78 |
+
return f"β File {filename} appears to be empty or contains no valid data."
|
| 79 |
+
elif "columns" in str(error).lower():
|
| 80 |
+
return f"β File {filename} must contain exactly 2 columns (wavenumber, intensity)."
|
| 81 |
+
else:
|
| 82 |
+
return f"β Failed to parse spectrum data from {filename}: {str(error)}"
|
| 83 |
+
|
| 84 |
+
@staticmethod
|
| 85 |
+
def clear_logs() -> None:
|
| 86 |
+
"""Clear all logged messages"""
|
| 87 |
+
st.session_state["log_messages"] = []
|
| 88 |
+
|
| 89 |
+
@staticmethod
|
| 90 |
+
def get_logs() -> list[str]:
|
| 91 |
+
"""Get all logged messages"""
|
| 92 |
+
return st.session_state.get("log_messages", [])
|
| 93 |
+
|
| 94 |
+
@staticmethod
|
| 95 |
+
def display_error_ui(error_message: str, show_details: bool = False) -> None:
|
| 96 |
+
"""Display error in Streamlit UI with optional details"""
|
| 97 |
+
st.error(error_message)
|
| 98 |
+
|
| 99 |
+
if show_details and st.session_state.get("log_messages"):
|
| 100 |
+
with st.expander("Error Details", expanded=False):
|
| 101 |
+
for msg in st.session_state["log_messages"][-5:]: # Show last 5 log entries
|
| 102 |
+
st.text(msg)
|
| 103 |
+
|
| 104 |
+
def safe_execute(func, *args, error_context: str = "", show_error: bool = True, **kwargs):
|
| 105 |
+
"""
|
| 106 |
+
Safely execute a function with error handling
|
| 107 |
+
|
| 108 |
+
Args:
|
| 109 |
+
func: Function to execute
|
| 110 |
+
*args: Arguments for the function
|
| 111 |
+
error_context: Context description for error logging
|
| 112 |
+
show_error: Whether to show error in UI
|
| 113 |
+
**kwargs: Keyword arguments for the function
|
| 114 |
+
|
| 115 |
+
Returns:
|
| 116 |
+
Tuple of (result, success_flag)
|
| 117 |
+
"""
|
| 118 |
+
try:
|
| 119 |
+
result = func(*args, **kwargs)
|
| 120 |
+
return result, True
|
| 121 |
+
except Exception as e:
|
| 122 |
+
ErrorHandler.log_error(e, error_context)
|
| 123 |
+
if show_error:
|
| 124 |
+
error_msg = f"Error in {error_context}: {str(e)}" if error_context else str(e)
|
| 125 |
+
st.error(error_msg)
|
| 126 |
+
return None, False
|