@@ -200,59 +200,76 @@ def get_keyword_documentation(self, name):
200
200
201
201
202
202
class KeywordRunner (object ):
203
- _generic_exceptions = (AssertionError , RuntimeError , Exception )
204
- _fatal_exceptions = (SystemExit , KeyboardInterrupt )
205
203
206
204
def __init__ (self , keyword ):
207
205
self ._keyword = keyword
208
206
209
207
def run_keyword (self , args , kwargs = None ):
210
208
args , kwargs = self ._handle_binary_args (args , kwargs or {})
211
- result = { 'status' : 'FAIL' }
209
+ result = KeywordResult ()
212
210
self ._intercept_std_streams ()
213
211
try :
214
212
return_value = self ._keyword (* args , ** kwargs )
215
- except :
216
- exc_type , exc_value , exc_tb = sys .exc_info ()
217
- if exc_type in self ._fatal_exceptions :
218
- self ._restore_std_streams ()
219
- raise
220
- self ._add_to_result (result , 'error' ,
221
- self ._get_error_message (exc_type , exc_value ))
222
- self ._add_to_result (result , 'traceback' ,
223
- self ._get_error_traceback (exc_tb ))
224
- self ._add_to_result (result , 'continuable' ,
225
- self ._get_error_attribute (exc_value , 'CONTINUE' ),
226
- default = False )
227
- self ._add_to_result (result , 'fatal' ,
228
- self ._get_error_attribute (exc_value , 'EXIT' ),
229
- default = False )
213
+ except Exception :
214
+ result .set_error (* sys .exc_info ())
230
215
else :
231
216
try :
232
- self ._add_to_result (result , 'return' ,
233
- self ._handle_return_value (return_value ))
234
- except :
235
- exc_type , exc_value , _ = sys .exc_info ()
236
- self ._add_to_result (result , 'error' ,
237
- self ._get_error_message (exc_type , exc_value ))
217
+ result .set_return (return_value )
218
+ except Exception :
219
+ result .set_error (* sys .exc_info ()[:2 ])
238
220
else :
239
- result ['status' ] = 'PASS'
240
- self ._add_to_result (result , 'output' , self ._restore_std_streams ())
241
- return result
221
+ result .set_status ('PASS' )
222
+ finally :
223
+ result .set_output (self ._restore_std_streams ())
224
+ return result .data
242
225
243
226
def _handle_binary_args (self , args , kwargs ):
244
227
args = [self ._handle_binary_arg (a ) for a in args ]
245
228
kwargs = dict ((k , self ._handle_binary_arg (v )) for k , v in kwargs .items ())
246
229
return args , kwargs
247
230
248
231
def _handle_binary_arg (self , arg ):
249
- if isinstance (arg , Binary ):
250
- return arg .data
251
- return arg
232
+ return arg if not isinstance (arg , Binary ) else arg .data
233
+
234
+ def _intercept_std_streams (self ):
235
+ sys .stdout = StringIO ()
236
+ sys .stderr = StringIO ()
237
+
238
+ def _restore_std_streams (self ):
239
+ stdout = sys .stdout .getvalue ()
240
+ stderr = sys .stderr .getvalue ()
241
+ close = [sys .stdout , sys .stderr ]
242
+ sys .stdout = sys .__stdout__
243
+ sys .stderr = sys .__stderr__
244
+ for stream in close :
245
+ stream .close ()
246
+ if stdout and stderr :
247
+ if not stderr .startswith (('*TRACE*' , '*DEBUG*' , '*INFO*' , '*HTML*' ,
248
+ '*WARN*' , '*ERROR*' )):
249
+ stderr = '*INFO* %s' % stderr
250
+ if not stdout .endswith ('\n ' ):
251
+ stdout += '\n '
252
+ return stdout + stderr
253
+
252
254
253
- def _add_to_result (self , result , key , value , default = '' ):
255
+ class KeywordResult (object ):
256
+ _generic_exceptions = (AssertionError , RuntimeError , Exception )
257
+
258
+ def __init__ (self ):
259
+ self .data = {'status' : 'FAIL' }
260
+
261
+ def set_error (self , exc_type , exc_value , exc_tb = None ):
262
+ self ._add ('error' , self ._get_error_message (exc_type , exc_value ))
263
+ if exc_tb :
264
+ self ._add ('traceback' , self ._get_error_traceback (exc_tb ))
265
+ self ._add ('continuable' , self ._get_error_attribute (exc_value , 'CONTINUE' ),
266
+ default = False )
267
+ self ._add ('fatal' , self ._get_error_attribute (exc_value , 'EXIT' ),
268
+ default = False )
269
+
270
+ def _add (self , key , value , default = '' ):
254
271
if value != default :
255
- result [key ] = value
272
+ self . data [key ] = value
256
273
257
274
def _get_error_message (self , exc_type , exc_value ):
258
275
name = exc_type .__name__
@@ -282,6 +299,9 @@ def _get_error_traceback(self, exc_tb):
282
299
def _get_error_attribute (self , exc_value , name ):
283
300
return bool (getattr (exc_value , 'ROBOT_%s_ON_FAILURE' % name , False ))
284
301
302
+ def set_return (self , value ):
303
+ self ._add ('return' , self ._handle_return_value (value ))
304
+
285
305
def _handle_return_value (self , ret ):
286
306
if isinstance (ret , (str , unicode , bytes )):
287
307
return self ._handle_binary_result (ret )
@@ -323,25 +343,12 @@ def _str(self, item, handle_binary=True):
323
343
item = self ._handle_binary_result (item )
324
344
return item
325
345
326
- def _intercept_std_streams (self ):
327
- sys .stdout = StringIO ()
328
- sys .stderr = StringIO ()
346
+ def set_status (self , status ):
347
+ self .data ['status' ] = status
329
348
330
- def _restore_std_streams (self ):
331
- stdout = sys .stdout .getvalue ()
332
- stderr = sys .stderr .getvalue ()
333
- close = [sys .stdout , sys .stderr ]
334
- sys .stdout = sys .__stdout__
335
- sys .stderr = sys .__stderr__
336
- for stream in close :
337
- stream .close ()
338
- if stdout and stderr :
339
- if not stderr .startswith (('*TRACE*' , '*DEBUG*' , '*INFO*' , '*HTML*' ,
340
- '*WARN*' , '*ERROR*' )):
341
- stderr = '*INFO* %s' % stderr
342
- if not stdout .endswith ('\n ' ):
343
- stdout += '\n '
344
- return self ._handle_binary_result (stdout + stderr )
349
+ def set_output (self , output ):
350
+ if output :
351
+ self .data ['output' ] = self ._handle_binary_result (output )
345
352
346
353
347
354
if __name__ == '__main__' :
0 commit comments