Coverage for src/dataknobs_fsm/core/exceptions.py: 85%

1"""FSM Core Exceptions Module.

2

3 This module defines core exception types used throughout the FSM system.

4 Now built on the common exception framework from dataknobs_common.

5"""

6

7 from typing import Any, Dict

8

9 from dataknobs_common import (

10 ConcurrencyError as BaseConcurrencyError,

11 ConfigurationError,

12 DataknobsError,

13 OperationError,

14 ResourceError as BaseResourceError,

15 TimeoutError as BaseTimeoutError,

16 ValidationError as BaseValidationError,

17)

18

19# Create FSMError as alias to DataknobsError for backward compatibility

20 FSMError = DataknobsError

21

22

23 class InvalidConfigurationError(ConfigurationError):

24 """Raised when FSM configuration is invalid."""

25 pass

26

27

28 class StateExecutionError(OperationError):

29 """Raised when state execution fails."""

30

31 def __init__(self, state_name: str, message: str, details: Dict[str, Any] | None = None):

32 super().__init__(

33 f"State '{state_name}' execution failed: {message}",

34 context=details

35 )

36 self.state_name = state_name

37

38

39 class TransitionError(OperationError):

40 """Raised when state transition fails."""

41

42 def __init__(self, from_state: str, to_state: str, message: str, details: Dict[str, Any] | None = None):

43 super().__init__(

44 f"Transition from '{from_state}' to '{to_state}' failed: {message}",

45 context=details

46 )

47 self.from_state = from_state

48 self.to_state = to_state

49

50

51 class ResourceError(BaseResourceError):

52 """FSM-specific resource error with resource_id tracking.

53

54 Extends the common ResourceError with FSM-specific resource tracking.

55 """

56

57 def __init__(self, resource_id: str, message: str, details: Dict[str, Any] | None = None):

58 super().__init__(

59 f"Resource '{resource_id}' error: {message}",

60 context=details

61 )

62 self.resource_id = resource_id

63

64

65# Use common ValidationError directly (no FSM-specific behavior needed)

66 ValidationError = BaseValidationError

67

68

69 class FunctionError(OperationError):

70 """Raised when a function execution fails.

71

72 This represents deterministic failures in user-defined functions

73 (transforms, validators, conditions) that should not be retried.

74 These are code errors, not transient failures.

75 """

76

77 def __init__(

78 self,

79 message: str,

80 function_name: str | None = None,

81 from_state: str | None = None,

82 to_state: str | None = None,

83 details: Dict[str, Any] | None = None,

84 ):

85 if function_name:

86 message = f"Function '{function_name}' failed: {message}"

87 super().__init__(message, context=details)

88 self.function_name = function_name

89 self.from_state = from_state

90 self.to_state = to_state

91

92

93# Use common TimeoutError directly (no FSM-specific behavior needed)

94 TimeoutError = BaseTimeoutError

95

96

97# Use common ConcurrencyError directly (no FSM-specific behavior needed)

98 ConcurrencyError = BaseConcurrencyError

99

100

101 class CircuitBreakerError(BaseConcurrencyError):

102 """Raised when circuit breaker is open."""

103

104 def __init__(self, wait_time: float | None = None, details: Dict[str, Any] | None = None):

105 if wait_time:

106 message = f"Circuit breaker is open (wait {wait_time:.1f}s)"

107 else:

108 message = "Circuit breaker is open"

109 super().__init__(message, context=details)

110 self.wait_time = wait_time

111

112

113 class ETLError(OperationError):

114 """Raised when ETL operations fail."""

115 pass

116

117

118 class BulkheadTimeoutError(BaseTimeoutError):

119 """Raised when bulkhead queue times out."""

120 pass