|
1 | 1 | from typing import TYPE_CHECKING
|
2 | 2 |
|
| 3 | +from ..callbacks import CallbackGroup |
3 | 4 | from ..event_data import EventData
|
4 | 5 | from ..event_data import TriggerData
|
5 | 6 | from ..exceptions import InvalidDefinition
|
@@ -101,30 +102,49 @@ async def _activate(self, trigger_data: TriggerData, transition: "Transition"):
|
101 | 102 | event_data = EventData(trigger_data=trigger_data, transition=transition)
|
102 | 103 | args, kwargs = event_data.args, event_data.extended_kwargs
|
103 | 104 |
|
104 |
| - await self.sm._callbacks.async_call(transition.validators.key, *args, **kwargs) |
105 |
| - if not await self.sm._callbacks.async_all(transition.cond.key, *args, **kwargs): |
106 |
| - return False, None |
| 105 | + try: |
| 106 | + await self.sm._callbacks.async_call(transition.validators.key, *args, **kwargs) |
| 107 | + if not await self.sm._callbacks.async_all(transition.cond.key, *args, **kwargs): |
| 108 | + return False, None |
| 109 | + |
| 110 | + source = transition.source |
| 111 | + target = transition.target |
107 | 112 |
|
108 |
| - source = transition.source |
109 |
| - target = transition.target |
| 113 | + result = await self.sm._callbacks.async_call(transition.before.key, *args, **kwargs) |
| 114 | + if source is not None and not transition.internal: |
| 115 | + await self.sm._callbacks.async_call(source.exit.key, *args, **kwargs) |
110 | 116 |
|
111 |
| - result = await self.sm._callbacks.async_call(transition.before.key, *args, **kwargs) |
112 |
| - if source is not None and not transition.internal: |
113 |
| - await self.sm._callbacks.async_call(source.exit.key, *args, **kwargs) |
| 117 | + result += await self.sm._callbacks.async_call(transition.on.key, *args, **kwargs) |
114 | 118 |
|
115 |
| - result += await self.sm._callbacks.async_call(transition.on.key, *args, **kwargs) |
| 119 | + self.sm.current_state = target |
| 120 | + event_data.state = target |
| 121 | + kwargs["state"] = target |
116 | 122 |
|
117 |
| - self.sm.current_state = target |
118 |
| - event_data.state = target |
119 |
| - kwargs["state"] = target |
| 123 | + if not transition.internal: |
| 124 | + await self.sm._callbacks.async_call(target.enter.key, *args, **kwargs) |
| 125 | + await self.sm._callbacks.async_call(transition.after.key, *args, **kwargs) |
120 | 126 |
|
121 |
| - if not transition.internal: |
122 |
| - await self.sm._callbacks.async_call(target.enter.key, *args, **kwargs) |
123 |
| - await self.sm._callbacks.async_call(transition.after.key, *args, **kwargs) |
| 127 | + if len(result) == 0: |
| 128 | + result = None |
| 129 | + elif len(result) == 1: |
| 130 | + result = result[0] |
124 | 131 |
|
125 |
| - if len(result) == 0: |
126 |
| - result = None |
127 |
| - elif len(result) == 1: |
128 |
| - result = result[0] |
| 132 | + return True, result |
| 133 | + finally: |
| 134 | + # Run finalize actions regardless of success/failure |
| 135 | + await self._run_finalize_actions(event_data) |
129 | 136 |
|
130 |
| - return True, result |
| 137 | + async def _run_finalize_actions(self, event_data: EventData): |
| 138 | + """Run finalize actions after a transition attempt.""" |
| 139 | + try: |
| 140 | + args, kwargs = event_data.args, event_data.extended_kwargs |
| 141 | + await self.sm._callbacks.async_call( |
| 142 | + CallbackGroup.FINALIZE.build_key(event_data.transition._specs), |
| 143 | + *args, |
| 144 | + **kwargs, |
| 145 | + ) |
| 146 | + except Exception as e: |
| 147 | + # Log but don't re-raise finalize errors |
| 148 | + import logging |
| 149 | + |
| 150 | + logging.error(f"Error in finalize action: {e}") |
0 commit comments