|
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