#!/usr/bin/env python # -*- coding: utf-8 -*- """ Error Handler - 统一的错误处理器 提供统一的错误处理机制,将技术错误转换为用户友好的消息 """ import logging import traceback from tkinter import messagebox from typing import Optional, Type import sys logger = logging.getLogger(__name__) class ErrorHandler: """ 统一的错误处理器 将技术错误转换为用户友好的消息,并记录详细日志 """ # 错误类型到用户消息的映射 ERROR_MESSAGE_MAP = { ConnectionError: "无法连接到服务器,请检查网络连接", PermissionError: "权限不足,请联系管理员", FileNotFoundError: "找不到指定的文件", ValueError: "输入数据格式不正确", TypeError: "数据类型错误,请检查输入", KeyError: "数据缺失,请检查输入完整性", TimeoutError: "操作超时,请重试", RuntimeError: "运行时错误,请查看日志了解详情", } @staticmethod def handle( error: Exception, context: str = "", show_user: bool = True, parent=None ): """ 处理错误 记录详细日志,并可选择向用户显示友好的错误消息 Args: error: 异常对象 context: 错误发生的上下文信息 show_user: 是否向用户显示错误消息 parent: 父窗口(用于显示消息框) """ # 记录详细日志 error_message = str(error) if context: logger.error(f"{context}: {error_message}", exc_info=error) else: logger.error(error_message, exc_info=error) # 显示用户友好的错误信息 if show_user: user_message = ErrorHandler._get_user_message(error) if context: user_message = f"[{context}]\n{user_message}" if parent: messagebox.showerror("操作失败", user_message, parent=parent) else: messagebox.showerror("操作失败", user_message) @staticmethod def _get_user_message(error: Exception) -> str: """ 将技术错误转换为用户友好的消息 Args: error: 异常对象 Returns: 用户友好的错误消息 """ # 检查是否为已知错误类型 for error_type, message in ErrorHandler.ERROR_MESSAGE_MAP.items(): if isinstance(error, error_type): return message # 未知错误类型 error_name = type(error).__name__ error_msg = str(error) # 如果错误消息为空或只包含类名,返回通用消息 if not error_msg or error_msg == error_name: return "操作失败,请查看日志了解详情" # 返回简化的错误消息(不包含技术细节) # 限制长度以避免消息过长 if len(error_msg) > 200: return f"{error_msg[:200]}..." return error_msg @staticmethod def handle_with_retry( error: Exception, context: str = "", retry_callback: Optional[callable] = None, parent=None ) -> bool: """ 处理错误并提供重试选项 Args: error: 异常对象 context: 错误发生的上下文信息 retry_callback: 重试回调函数 parent: 父窗口 Returns: True 如果用户选择重试,False 否则 """ user_message = ErrorHandler._get_user_message(error) if context: user_message = f"[{context}]\n{user_message}" user_message += "\n\n是否重试?" if parent: result = messagebox.askyesno("操作失败", user_message, parent=parent) else: result = messagebox.askyesno("操作失败", user_message) if result and retry_callback: try: retry_callback() return True except Exception as e: ErrorHandler.handle(e, f"{context} (重试)", True, parent) return False return result @staticmethod def log_exception(error: Exception, context: str = ""): """ 仅记录异常到日志,不显示用户消息 Args: error: 异常对象 context: 错误发生的上下文信息 """ error_message = str(error) if context: logger.error(f"{context}: {error_message}", exc_info=error) else: logger.error(error_message, exc_info=error) @staticmethod def show_warning(message: str, parent=None): """ 显示警告消息 Args: message: 警告消息 parent: 父窗口 """ if parent: messagebox.showwarning("警告", message, parent=parent) else: messagebox.showwarning("警告", message) @staticmethod def show_info(message: str, parent=None): """ 显示信息消息 Args: message: 信息消息 parent: 父窗口 """ if parent: messagebox.showinfo("信息", message, parent=parent) else: messagebox.showinfo("信息", message) @staticmethod def ask_confirmation(message: str, parent=None) -> bool: """ 询问用户确认 Args: message: 确认消息 parent: 父窗口 Returns: True 如果用户确认,False 否则 """ if parent: return messagebox.askyesno("确认", message, parent=parent) else: return messagebox.askyesno("确认", message)