"""
Custom Exception Hierarchy
Defines a comprehensive exception hierarchy for the Commit Helper MCP
with context-rich error information and recovery suggestions.
"""
from typing import Dict, Any, Optional, List
from dataclasses import dataclass, field
@dataclass
class ErrorContext:
"""Rich error context information."""
operation: str
component: str
details: Dict[str, Any] = field(default_factory=dict)
suggestions: List[str] = field(default_factory=list)
recovery_actions: List[str] = field(default_factory=list)
user_message: Optional[str] = None
class CommitHelperMCPError(Exception):
"""Base exception for all Commit Helper MCP errors."""
def __init__(
self,
message: str,
context: Optional[ErrorContext] = None,
cause: Optional[Exception] = None,
):
super().__init__(message)
self.context = context or ErrorContext(operation="unknown", component="unknown")
self.cause = cause
def to_dict(self) -> Dict[str, Any]:
"""Convert exception to dictionary for serialization."""
return {
"error_type": self.__class__.__name__,
"message": str(self),
"context": {
"operation": self.context.operation,
"component": self.context.component,
"details": self.context.details,
"suggestions": self.context.suggestions,
"recovery_actions": self.context.recovery_actions,
"user_message": self.context.user_message,
},
"cause": str(self.cause) if self.cause else None,
}
def get_user_message(self) -> str:
"""Get user-friendly error message."""
return self.context.user_message or str(self)
def get_suggestions(self) -> List[str]:
"""Get error recovery suggestions."""
return self.context.suggestions
def get_recovery_actions(self) -> List[str]:
"""Get specific recovery actions."""
return self.context.recovery_actions
class GitOperationError(CommitHelperMCPError):
"""Errors related to git operations."""
def __init__(
self,
message: str,
git_command: Optional[str] = None,
repo_path: Optional[str] = None,
cause: Optional[Exception] = None,
):
context = ErrorContext(
operation="git_operation",
component="git_service",
details={"git_command": git_command, "repo_path": repo_path},
suggestions=[
"Check if the repository exists and is accessible",
"Verify git is installed and configured",
"Ensure you have proper permissions for the repository",
],
)
super().__init__(message, context, cause)
class ValidationError(CommitHelperMCPError):
"""Errors related to validation (commit messages, inputs, etc.)."""
def __init__(
self,
message: str,
validation_type: Optional[str] = None,
invalid_value: Optional[str] = None,
expected_format: Optional[str] = None,
cause: Optional[Exception] = None,
):
context = ErrorContext(
operation="validation",
component="validation_service",
details={
"validation_type": validation_type,
"invalid_value": invalid_value,
"expected_format": expected_format,
},
suggestions=[
"Check the format requirements",
"Review the validation rules",
"Use the get_commit_types tool to see valid options",
],
)
super().__init__(message, context, cause)
class ConfigurationError(CommitHelperMCPError):
"""Errors related to configuration loading and validation."""
def __init__(
self,
message: str,
config_file: Optional[str] = None,
config_key: Optional[str] = None,
cause: Optional[Exception] = None,
):
context = ErrorContext(
operation="configuration",
component="config_service",
details={"config_file": config_file, "config_key": config_key},
suggestions=[
"Check if configuration files exist and are readable",
"Verify configuration syntax is correct",
"Review environment variable settings",
],
)
super().__init__(message, context, cause)
class RepositoryError(CommitHelperMCPError):
"""Errors related to repository access and validation."""
def __init__(
self,
message: str,
repo_path: Optional[str] = None,
cause: Optional[Exception] = None,
):
context = ErrorContext(
operation="repository_access",
component="repository_manager",
details={"repo_path": repo_path},
suggestions=[
"Verify the repository path exists",
"Check if it's a valid git repository",
"Ensure proper file permissions",
],
)
super().__init__(message, context, cause)
class PluginError(CommitHelperMCPError):
"""Errors related to Commitizen plugin operations."""
def __init__(
self,
message: str,
plugin_name: Optional[str] = None,
cause: Optional[Exception] = None,
):
context = ErrorContext(
operation="plugin_operation",
component="plugin_service",
details={"plugin_name": plugin_name},
suggestions=[
"Check if the plugin is installed",
"Verify plugin configuration is correct",
"Try refreshing the configuration",
],
)
super().__init__(message, context, cause)
class ServiceError(CommitHelperMCPError):
"""Errors related to service initialization and operation."""
def __init__(
self,
message: str,
service_name: Optional[str] = None,
cause: Optional[Exception] = None,
):
context = ErrorContext(
operation="service_operation",
component=service_name or "unknown_service",
details={"service_name": service_name},
suggestions=[
"Check service dependencies are available",
"Verify service configuration",
"Try restarting the service",
],
)
super().__init__(message, context, cause)
# Convenience functions for creating specific errors
def create_git_error(
message: str,
git_command: str = None,
repo_path: str = None,
cause: Exception = None,
) -> GitOperationError:
"""Create a GitOperationError with context."""
return GitOperationError(message, git_command, repo_path, cause)
def create_validation_error(
message: str,
validation_type: str = None,
invalid_value: str = None,
expected_format: str = None,
cause: Exception = None,
) -> ValidationError:
"""Create a ValidationError with context."""
return ValidationError(
message, validation_type, invalid_value, expected_format, cause
)
def create_config_error(
message: str,
config_file: str = None,
config_key: str = None,
cause: Exception = None,
) -> ConfigurationError:
"""Create a ConfigurationError with context."""
return ConfigurationError(message, config_file, config_key, cause)