Coverage for frappe_manager / exceptions.py: 92%
24 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-07-02 18:13 +0530
« prev ^ index » next coverage.py v7.13.5, created at 2026-07-02 18:13 +0530
1"""
2Frappe Manager exception hierarchy.
4All custom exceptions inherit from FrappeManagerException to allow
5catching all FM-specific errors in one place. This enables consistent
6error handling across different interfaces (CLI, API, WebSocket, etc.).
7"""
9from typing import Any
12class FrappeManagerException(Exception):
13 """
14 Base exception for all Frappe Manager errors.
16 All custom exceptions should inherit from this to enable:
17 - Consistent error handling across different interfaces
18 - Easy differentiation from third-party exceptions
19 - Structured error information for API responses
20 """
22 def __init__(self, message: str, details: dict[str, Any] | None = None):
23 """
24 Initialize exception with message and optional details.
26 Args:
27 message: Human-readable error message
28 details: Optional dictionary with additional context (for logging/API)
29 """
30 self.message = message
31 self.details = details or {}
32 super().__init__(self.message)
34 def to_dict(self) -> dict[str, Any]:
35 """
36 Convert exception to dictionary for API responses.
38 Returns:
39 Dictionary with error_type, message, and details
40 """
41 return {"error_type": self.__class__.__name__, "message": self.message, "details": self.details}
44class ValidationError(FrappeManagerException):
45 """Raised when input validation fails."""
48class OperationAborted(FrappeManagerException):
49 """Raised when an operation is aborted by user or system."""
52class ServiceNotAvailable(FrappeManagerException):
53 """Raised when a required service is not available."""
56class BenchOperationError(FrappeManagerException):
57 """Raised when a bench operation fails."""
60class SSLCertificateError(FrappeManagerException):
61 """Raised when SSL certificate operations fail."""
64class DockerOperationError(FrappeManagerException):
65 """Raised when Docker operations fail."""
68class MigrationError(FrappeManagerException):
69 """Raised when migrations fail."""
72class ConfigurationError(FrappeManagerException):
73 """Raised when configuration is invalid or missing."""
76class DependencyError(FrappeManagerException):
77 """Raised when external dependencies are missing."""
80class NonInteractiveError(FrappeManagerException):
81 """Raised when interactive input required but CLI is non-interactive."""
83 def __init__(self, message: str, suggestions: list[str] | None = None):
84 """
85 Initialize with error message and optional suggestions.
87 Args:
88 message: Human-readable error description
89 suggestions: List of suggested solutions for the user
90 """
91 if suggestions:
92 solutions_text = "\n".join(f" • {s}" for s in suggestions)
93 full_message = f"{message}\n\nSolutions:\n{solutions_text}"
94 else:
95 full_message = (
96 f"{message}\n\n"
97 "Solutions:\n"
98 " • Provide required arguments explicitly\n"
99 " • Run without --non-interactive for prompts\n"
100 " • Use --help for available options"
101 )
102 super().__init__(full_message)