@@ -102,6 +102,15 @@ def handleAbilityEvent(self, event, replay):
102
102
replay::
103
103
104
104
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))
105
114
"""
106
115
def __init__ (self , plugins = []):
107
116
self ._plugins = list ()
@@ -123,8 +132,11 @@ def run(self, replay):
123
132
# remove them from this list and regenerate event handlers.
124
133
plugins = list (self ._plugins )
125
134
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 ()
128
140
129
141
# Fill event event queue with the replay events, bookmarked by Init and End events.
130
142
event_queue = collections .deque ()
@@ -141,8 +153,9 @@ def run(self, replay):
141
153
# Remove the plugin and reset the handlers.
142
154
plugins .remove (event .plugin )
143
155
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 )
146
159
147
160
# If we haven't compiled a list of handlers for this event yet, do so!
148
161
if event .name not in handlers :
@@ -152,19 +165,31 @@ def run(self, replay):
152
165
event_handlers = handlers [event .name ]
153
166
154
167
# 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 ()
157
172
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 )
162
187
event_queue .extendleft (new_events )
163
188
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.
166
191
for plugin in plugins :
167
- replay .plugins [plugin .name ] = (0 , dict ())
192
+ replay .plugin_result [plugin .name ] = (0 , dict ())
168
193
169
194
def _get_event_handlers (self , event , plugins ):
170
195
return sum ([self ._get_plugin_event_handlers (plugin , event ) for plugin in plugins ], [])
@@ -194,35 +219,3 @@ def _has_event_handler(self, plugin, event):
194
219
195
220
def _get_event_handler (self , plugin , event ):
196
221
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