Coverage for src/dataknobs_fsm/core/context_factory.py: 23%
71 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-20 16:46 -0600
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-20 16:46 -0600
1"""Factory for creating and configuring ExecutionContext instances.
3This module provides a centralized factory for creating execution contexts,
4eliminating duplication between Simple and Advanced APIs.
5"""
7from typing import Any, Dict, Union
8from dataknobs_data import Record
10from ..core.fsm import FSM
11from ..core.state import StateInstance, StateDefinition, StateType
12from ..core.modes import ProcessingMode, TransactionMode
13from ..execution.context import ExecutionContext
14from ..resources.manager import ResourceManager
17class ContextFactory:
18 """Factory for creating and configuring ExecutionContext instances."""
20 @staticmethod
21 def create_context(
22 fsm: FSM,
23 data: Union[Dict[str, Any], Record],
24 initial_state: str | None = None,
25 data_mode: ProcessingMode = ProcessingMode.SINGLE,
26 transaction_mode: TransactionMode = TransactionMode.NONE,
27 resources: Dict[str, Any] | None = None,
28 resource_manager: ResourceManager | None = None
29 ) -> ExecutionContext:
30 """Create and configure an ExecutionContext.
32 Args:
33 fsm: The FSM instance
34 data: Input data as dict or Record
35 initial_state: Optional initial state name
36 data_mode: Processing mode (single, batch, stream)
37 transaction_mode: Transaction mode
38 resources: Resource configuration dict
39 resource_manager: Optional resource manager instance
41 Returns:
42 Configured ExecutionContext ready for execution
43 """
44 # Create base context
45 context = ExecutionContext(
46 data_mode=data_mode,
47 transaction_mode=transaction_mode,
48 resources=resources or {}
49 )
51 # Convert and set data
52 if isinstance(data, Record):
53 context.data = data.to_dict()
54 else:
55 context.data = data
57 # Determine initial state
58 state_name, state_def = ContextFactory._resolve_initial_state(
59 fsm, initial_state
60 )
62 # Set state in context
63 context.current_state = state_name
64 if state_def:
65 context.current_state_instance = StateInstance(
66 definition=state_def,
67 data=context.data.copy() if isinstance(context.data, dict) else {}
68 )
70 # Add resource manager reference if provided
71 if resource_manager:
72 context.resource_manager = resource_manager
74 return context
76 @staticmethod
77 def _resolve_initial_state(
78 fsm: FSM,
79 state_name: str | None = None
80 ) -> tuple[str, StateDefinition | None]:
81 """Resolve the initial state for execution.
83 Args:
84 fsm: The FSM instance
85 state_name: Optional requested state name
87 Returns:
88 Tuple of (state_name, state_definition)
89 """
90 state_def = None
92 if state_name:
93 # Try to get the requested state
94 if hasattr(fsm, 'get_state'):
95 try:
96 state_def = fsm.get_state(state_name)
97 except (KeyError, AttributeError):
98 pass
100 # If not found, search in networks
101 if not state_def and hasattr(fsm, 'networks'):
102 for network in fsm.networks.values():
103 if hasattr(network, 'states') and state_name in network.states:
104 state_def = network.states[state_name]
105 break
106 else:
107 # Find the start state
108 if hasattr(fsm, 'get_start_state'):
109 state_def = fsm.get_start_state()
110 if state_def:
111 state_name = state_def.name
113 # Fallback: search networks for start state
114 if not state_def and hasattr(fsm, 'networks'):
115 for network in fsm.networks.values():
116 if hasattr(network, 'states'):
117 for state in network.states.values():
118 if hasattr(state, 'is_start_state') and state.is_start_state():
119 state_def = state
120 state_name = state.name
121 break
122 if state_def:
123 break
125 # Final fallback
126 if not state_name:
127 state_name = 'start'
129 # Create minimal state definition if needed
130 if not state_def and state_name:
131 state_def = StateDefinition(
132 name=state_name,
133 type=StateType.START if state_name == 'start' else StateType.NORMAL
134 )
136 return state_name, state_def
138 @staticmethod
139 def create_batch_context(
140 fsm: FSM,
141 batch_data: list,
142 data_mode: ProcessingMode = ProcessingMode.BATCH,
143 resources: Dict[str, Any] | None = None
144 ) -> ExecutionContext:
145 """Create a context for batch processing.
147 Args:
148 fsm: The FSM instance
149 batch_data: List of data items to process
150 data_mode: Processing mode (defaults to BATCH)
151 resources: Resource configuration
153 Returns:
154 ExecutionContext configured for batch processing
155 """
156 context = ExecutionContext(
157 data_mode=data_mode,
158 resources=resources or {}
159 )
161 # Set batch data
162 context.batch_data = batch_data
164 # Find start state
165 state_name, state_def = ContextFactory._resolve_initial_state(fsm, None)
166 context.current_state = state_name
168 if state_def:
169 context.current_state_instance = StateInstance(
170 definition=state_def,
171 data={}
172 )
174 return context
176 @staticmethod
177 def create_stream_context(
178 fsm: FSM,
179 stream_context,
180 resources: Dict[str, Any] | None = None
181 ) -> ExecutionContext:
182 """Create a context for stream processing.
184 Args:
185 fsm: The FSM instance
186 stream_context: Stream context object
187 resources: Resource configuration
189 Returns:
190 ExecutionContext configured for stream processing
191 """
192 context = ExecutionContext(
193 data_mode=ProcessingMode.STREAM,
194 resources=resources or {},
195 stream_context=stream_context
196 )
198 # Find start state
199 state_name, state_def = ContextFactory._resolve_initial_state(fsm, None)
200 context.current_state = state_name
202 if state_def:
203 context.current_state_instance = StateInstance(
204 definition=state_def,
205 data={}
206 )
208 return context