@@ -102,6 +102,15 @@ def handleAbilityEvent(self, event, replay):
102102 replay::
103103
104104 code, details = replay.plugins['MyPlugin']
105+
106+ If your plugin depends on another plugin, it is a good idea to implement handlePluginExit
107+ and be alerted if the plugin that you require fails. This way you can exit gracefully. You
108+ can also check to see if the plugin name is in ``replay.plugin_failures``::
109+
110+ if 'RequiredPlugin' in replay.plugin_failures:
111+ code, details = replay.plugins['RequiredPlugin']
112+ message = "RequiredPlugin failed with code: {0}. Cannot continue.".format(code)
113+ yield PluginExit(self, code=1, details=dict(msg=message))
105114 """
106115 def __init__ (self , plugins = []):
107116 self ._plugins = list ()
@@ -126,8 +135,11 @@ def run(self, replay):
126135 # remove them from this list and regenerate event handlers.
127136 plugins = list (self ._plugins )
128137
129- # Create a dict for storing plugin exit codes and details
130- replay .plugins = dict ()
138+ # Create a dict for storing plugin exit codes and details.
139+ replay .plugin_result = replay .plugins = dict ()
140+
141+ # Create a list storing replay.plugins keys for failures.
142+ replay .plugin_failures = list ()
131143
132144 # Fill event event queue with the replay events, bookmarked by Init and End events.
133145 event_queue = collections .deque ()
@@ -144,8 +156,9 @@ def run(self, replay):
144156 # Remove the plugin and reset the handlers.
145157 plugins .remove (event .plugin )
146158 handlers .clear ()
147- replay .plugins [event .plugin .name ] = (event .code , event .details )
148- continue
159+ replay .plugin_result [event .plugin .name ] = (event .code , event .details )
160+ if event .code != 0 :
161+ replay .plugin_failures .append (event .plugin .name )
149162
150163 # If we haven't compiled a list of handlers for this event yet, do so!
151164 if event .name not in handlers :
@@ -155,19 +168,31 @@ def run(self, replay):
155168 event_handlers = handlers [event .name ]
156169
157170 # Events have the option of yielding one or more additional events
158- # which get processed after the current event finishes.
159- new_events = list ()
171+ # which get processed after the current event finishes. The new_events
172+ # batch is constructed in reverse order because extendleft reverses
173+ # the order again with a series of appendlefts.
174+ new_events = collections .deque ()
160175 for event_handler in event_handlers :
161- new_events .extend (event_handler (event , replay ) or [])
162-
163- # extendleft does a series of appendlefts and reverses the order so we
164- # need to reverse the list first to have them added in order.
176+ try :
177+ for new_event in (event_handler (event , replay ) or []):
178+ if new_event .name == 'PluginExit' :
179+ new_events .append (new_event )
180+ break
181+ else :
182+ new_events .appendleft (new_event )
183+ except Exception as e :
184+ if event_handler .im_self .name in ['ContextLoader' ]:
185+ # Certain built in plugins should probably still cause total failure
186+ raise # Maybe??
187+ else :
188+ new_event = PluginExit (event_handler .im_self , code = 1 , details = dict (error = e ))
189+ new_events .append (new_event )
165190 event_queue .extendleft (new_events )
166191
167- # For any plugins that didn't yield a PluginExit event, record a successful
168- # completion.
192+ # For any plugins that didn't yield a PluginExit event or throw unexpected exceptions,
193+ # record a successful completion.
169194 for plugin in plugins :
170- replay .plugins [plugin .name ] = (0 , dict ())
195+ replay .plugin_result [plugin .name ] = (0 , dict ())
171196
172197 def _get_event_handlers (self , event , plugins ):
173198 return sum ([self ._get_plugin_event_handlers (plugin , event ) for plugin in plugins ], [])
@@ -197,35 +222,3 @@ def _has_event_handler(self, plugin, event):
197222
198223 def _get_event_handler (self , plugin , event ):
199224 return getattr (plugin , 'handle' + event .name , None )
200-
201-
202- if __name__ == '__main__' :
203- from sc2reader .events import UserOptionsEvent , GameStartEvent , PlayerLeaveEvent
204-
205- class TestEvent (object ):
206- name = 'TestEvent'
207-
208- def __init__ (self , source ):
209- self .source = source
210-
211- class TestPlugin (object ):
212- yields = TestEvent
213-
214- def handleInitGame (self , event , replay ,):
215- yield TestEvent (event .name )
216-
217- def handleTestEvent (self , event , replay ):
218- print (event .source )
219-
220- def handleGameStartEvent (self , event , replay ):
221- yield TestEvent (event .name )
222-
223- def handleEndGame (self , event , replay ):
224- yield TestEvent (event .name )
225-
226- class TestReplay (object ):
227- events = [UserOptionsEvent , UserOptionsEvent , GameStartEvent , PlayerLeaveEvent ]
228-
229- engine = GameEngine ()
230- engine .register_plugin (TestPlugin ())
231- events = engine .run (TestReplay )
0 commit comments