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

1""" 

2Frappe Manager exception hierarchy. 

3 

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""" 

8 

9from typing import Any 

10 

11 

12class FrappeManagerException(Exception): 

13 """ 

14 Base exception for all Frappe Manager errors. 

15 

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 """ 

21 

22 def __init__(self, message: str, details: dict[str, Any] | None = None): 

23 """ 

24 Initialize exception with message and optional details. 

25 

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) 

33 

34 def to_dict(self) -> dict[str, Any]: 

35 """ 

36 Convert exception to dictionary for API responses. 

37 

38 Returns: 

39 Dictionary with error_type, message, and details 

40 """ 

41 return {"error_type": self.__class__.__name__, "message": self.message, "details": self.details} 

42 

43 

44class ValidationError(FrappeManagerException): 

45 """Raised when input validation fails.""" 

46 

47 

48class OperationAborted(FrappeManagerException): 

49 """Raised when an operation is aborted by user or system.""" 

50 

51 

52class ServiceNotAvailable(FrappeManagerException): 

53 """Raised when a required service is not available.""" 

54 

55 

56class BenchOperationError(FrappeManagerException): 

57 """Raised when a bench operation fails.""" 

58 

59 

60class SSLCertificateError(FrappeManagerException): 

61 """Raised when SSL certificate operations fail.""" 

62 

63 

64class DockerOperationError(FrappeManagerException): 

65 """Raised when Docker operations fail.""" 

66 

67 

68class MigrationError(FrappeManagerException): 

69 """Raised when migrations fail.""" 

70 

71 

72class ConfigurationError(FrappeManagerException): 

73 """Raised when configuration is invalid or missing.""" 

74 

75 

76class DependencyError(FrappeManagerException): 

77 """Raised when external dependencies are missing.""" 

78 

79 

80class NonInteractiveError(FrappeManagerException): 

81 """Raised when interactive input required but CLI is non-interactive.""" 

82 

83 def __init__(self, message: str, suggestions: list[str] | None = None): 

84 """ 

85 Initialize with error message and optional suggestions. 

86 

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)