@@ -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 ()
@@ -123,8 +132,11 @@ def run(self, replay):
123132 # remove them from this list and regenerate event handlers.
124133 plugins = list (self ._plugins )
125134
126- # Create a dict for storing plugin exit codes and details
127- replay .plugins = dict ()
135+ # Create a dict for storing plugin exit codes and details.
136+ replay .plugin_result = replay .plugins = dict ()
137+
138+ # Create a list storing replay.plugins keys for failures.
139+ replay .plugin_failures = list ()
128140
129141 # Fill event event queue with the replay events, bookmarked by Init and End events.
130142 event_queue = collections .deque ()
@@ -141,8 +153,9 @@ def run(self, replay):
141153 # Remove the plugin and reset the handlers.
142154 plugins .remove (event .plugin )
143155 handlers .clear ()
144- replay .plugins [event .plugin .name ] = (event .code , event .details )
145- continue
156+ replay .plugin_result [event .plugin .name ] = (event .code , event .details )
157+ if event .code != 0 :
158+ replay .plugin_failures .append (event .plugin .name )
146159
147160 # If we haven't compiled a list of handlers for this event yet, do so!
148161 if event .name not in handlers :
@@ -152,19 +165,31 @@ def run(self, replay):
152165 event_handlers = handlers [event .name ]
153166
154167 # Events have the option of yielding one or more additional events
155- # which get processed after the current event finishes.
156- new_events = list ()
168+ # which get processed after the current event finishes. The new_events
169+ # batch is constructed in reverse order because extendleft reverses
170+ # the order again with a series of appendlefts.
171+ new_events = collections .deque ()
157172 for event_handler in event_handlers :
158- new_events .extend (event_handler (event , replay ) or [])
159-
160- # extendleft does a series of appendlefts and reverses the order so we
161- # need to reverse the list first to have them added in order.
173+ try :
174+ for new_event in (event_handler (event , replay ) or []):
175+ if new_event .name == 'PluginExit' :
176+ new_events .append (new_event )
177+ break
178+ else :
179+ new_events .appendleft (new_event )
180+ except Exception as e :
181+ if event_handler .im_self .name in ['ContextLoader' ]:
182+ # Certain built in plugins should probably still cause total failure
183+ raise # Maybe??
184+ else :
185+ new_event = PluginExit (event_handler .im_self , code = 1 , details = dict (error = e ))
186+ new_events .append (new_event )
162187 event_queue .extendleft (new_events )
163188
164- # For any plugins that didn't yield a PluginExit event, record a successful
165- # completion.
189+ # For any plugins that didn't yield a PluginExit event or throw unexpected exceptions,
190+ # record a successful completion.
166191 for plugin in plugins :
167- replay .plugins [plugin .name ] = (0 , dict ())
192+ replay .plugin_result [plugin .name ] = (0 , dict ())
168193
169194 def _get_event_handlers (self , event , plugins ):
170195 return sum ([self ._get_plugin_event_handlers (plugin , event ) for plugin in plugins ], [])
@@ -194,35 +219,3 @@ def _has_event_handler(self, plugin, event):
194219
195220 def _get_event_handler (self , plugin , event ):
196221 return getattr (plugin , 'handle' + event .name , None )
197-
198-
199- if __name__ == '__main__' :
200- from sc2reader .events import UserOptionsEvent , GameStartEvent , PlayerLeaveEvent
201-
202- class TestEvent (object ):
203- name = 'TestEvent'
204-
205- def __init__ (self , source ):
206- self .source = source
207-
208- class TestPlugin (object ):
209- yields = TestEvent
210-
211- def handleInitGame (self , event , replay ,):
212- yield TestEvent (event .name )
213-
214- def handleTestEvent (self , event , replay ):
215- print (event .source )
216-
217- def handleGameStartEvent (self , event , replay ):
218- yield TestEvent (event .name )
219-
220- def handleEndGame (self , event , replay ):
221- yield TestEvent (event .name )
222-
223- class TestReplay (object ):
224- events = [UserOptionsEvent , UserOptionsEvent , GameStartEvent , PlayerLeaveEvent ]
225-
226- engine = GameEngine ()
227- engine .register_plugin (TestPlugin ())
228- events = engine .run (TestReplay )
0 commit comments