1
- # Copyright 2008-2014 Nokia Solutions and Networks
1
+ # Copyright 2008-2015 Nokia Solutions and Networks
2
+ # Copyright 2016- Robot Framework Foundation
2
3
#
3
4
# Licensed under the Apache License, Version 2.0 (the "License");
4
5
# you may not use this file except in compliance with the License.
12
13
# See the License for the specific language governing permissions and
13
14
# limitations under the License.
14
15
15
- __version__ = 'devel'
16
+ from __future__ import print_function
16
17
18
+ from collections import Mapping
17
19
import errno
20
+ import inspect
18
21
import re
22
+ import signal
19
23
import select
20
24
import sys
21
- import inspect
22
25
import traceback
23
- from StringIO import StringIO
24
- from SimpleXMLRPCServer import SimpleXMLRPCServer
25
- from xmlrpclib import Binary
26
- try :
27
- import signal
28
- except ImportError :
29
- signal = None
30
- try :
31
- from collections import Mapping
32
- except ImportError :
33
- Mapping = dict
34
26
27
+ if sys .version_info < (3 ,):
28
+ from StringIO import StringIO
29
+ from SimpleXMLRPCServer import SimpleXMLRPCServer
30
+ from xmlrpclib import Binary
31
+ PY3 = False
32
+ else :
33
+ from io import StringIO
34
+ from xmlrpc .client import Binary
35
+ from xmlrpc .server import SimpleXMLRPCServer
36
+ PY3 = True
37
+ unicode = str
38
+ long = int
39
+
40
+
41
+ __version__ = 'devel'
35
42
36
43
BINARY = re .compile ('[\x00 -\x08 \x0B \x0C \x0E -\x1F ]' )
37
44
NON_ASCII = re .compile ('[\x80 -\xff ]' )
@@ -86,11 +93,8 @@ def _announce_start(self, port_file=None):
86
93
self ._log ('Robot Framework remote server at %s:%s starting.'
87
94
% (host , port ))
88
95
if port_file :
89
- pf = open (port_file , 'w' )
90
- try :
96
+ with open (port_file , 'w' ) as pf :
91
97
pf .write (str (port ))
92
- finally :
93
- pf .close ()
94
98
95
99
def serve_forever (self ):
96
100
if hasattr (self , 'timeout' ):
@@ -100,7 +104,7 @@ def serve_forever(self):
100
104
while not self ._shutdown :
101
105
try :
102
106
self .handle_request ()
103
- except (OSError , select .error ), err :
107
+ except (OSError , select .error ) as err :
104
108
if err .args [0 ] != errno .EINTR :
105
109
raise
106
110
@@ -114,8 +118,8 @@ def stop_remote_server(self):
114
118
return self ._shutdown
115
119
116
120
def get_keyword_names (self ):
117
- get_kw_names = getattr (self ._library , 'get_keyword_names' , None ) or \
118
- getattr (self ._library , 'getKeywordNames' , None )
121
+ get_kw_names = ( getattr (self ._library , 'get_keyword_names' , None ) or
122
+ getattr (self ._library , 'getKeywordNames' , None ) )
119
123
if self ._is_function_or_method (get_kw_names ):
120
124
names = get_kw_names ()
121
125
else :
@@ -124,8 +128,6 @@ def get_keyword_names(self):
124
128
return names + ['stop_remote_server' ]
125
129
126
130
def _is_function_or_method (self , item ):
127
- # Cannot use inspect.isroutine because it returns True for
128
- # object().__init__ with Jython and IronPython
129
131
return inspect .isfunction (item ) or inspect .ismethod (item )
130
132
131
133
def run_keyword (self , name , args , kwargs = None ):
@@ -136,6 +138,9 @@ def run_keyword(self, name, args, kwargs=None):
136
138
return_value = self ._get_keyword (name )(* args , ** kwargs )
137
139
except :
138
140
exc_type , exc_value , exc_tb = sys .exc_info ()
141
+ if exc_type in self ._fatal_exceptions :
142
+ self ._restore_std_streams ()
143
+ raise
139
144
self ._add_to_result (result , 'error' ,
140
145
self ._get_error_message (exc_type , exc_value ))
141
146
self ._add_to_result (result , 'traceback' ,
@@ -161,7 +166,7 @@ def run_keyword(self, name, args, kwargs=None):
161
166
162
167
def _handle_binary_args (self , args , kwargs ):
163
168
args = [self ._handle_binary_arg (a ) for a in args ]
164
- kwargs = dict ([ (k , self ._handle_binary_arg (v )) for k , v in kwargs .items ()] )
169
+ kwargs = dict ((k , self ._handle_binary_arg (v )) for k , v in kwargs .items ())
165
170
return args , kwargs
166
171
167
172
def _handle_binary_arg (self , arg ):
@@ -208,9 +213,6 @@ def _get_keyword(self, name):
208
213
return kw
209
214
210
215
def _get_error_message (self , exc_type , exc_value ):
211
- if exc_type in self ._fatal_exceptions :
212
- self ._restore_std_streams ()
213
- raise
214
216
name = exc_type .__name__
215
217
message = self ._get_message_from_exception (exc_value )
216
218
if not message :
@@ -222,10 +224,11 @@ def _get_error_message(self, exc_type, exc_value):
222
224
223
225
def _get_message_from_exception (self , value ):
224
226
# UnicodeError occurs below 2.6 and if message contains non-ASCII bytes
227
+ # TODO: Can try/except be removed here?
225
228
try :
226
229
msg = unicode (value )
227
230
except UnicodeError :
228
- msg = ' ' .join ([ self ._str (a , handle_binary = False ) for a in value .args ] )
231
+ msg = ' ' .join (self ._str (a , handle_binary = False ) for a in value .args )
229
232
return self ._handle_binary_result (msg )
230
233
231
234
def _get_error_traceback (self , exc_tb ):
@@ -238,13 +241,13 @@ def _get_error_attribute(self, exc_value, name):
238
241
return bool (getattr (exc_value , 'ROBOT_%s_ON_FAILURE' % name , False ))
239
242
240
243
def _handle_return_value (self , ret ):
241
- if isinstance (ret , basestring ):
244
+ if isinstance (ret , ( str , unicode , bytes ) ):
242
245
return self ._handle_binary_result (ret )
243
246
if isinstance (ret , (int , long , float )):
244
247
return ret
245
248
if isinstance (ret , Mapping ):
246
- return dict ([ (self ._str (key ), self ._handle_return_value (value ))
247
- for key , value in ret .items ()] )
249
+ return dict ((self ._str (key ), self ._handle_return_value (value ))
250
+ for key , value in ret .items ())
248
251
try :
249
252
return [self ._handle_return_value (item ) for item in ret ]
250
253
except TypeError :
@@ -253,23 +256,29 @@ def _handle_return_value(self, ret):
253
256
def _handle_binary_result (self , result ):
254
257
if not self ._contains_binary (result ):
255
258
return result
256
- try :
259
+ if not isinstance (result , bytes ):
260
+ try :
261
+ result = result .encode ('ASCII' )
262
+ except UnicodeError :
263
+ raise ValueError ("Cannot represent %r as binary." % result )
264
+ # With IronPython Binary cannot be sent if it contains "real" bytes.
265
+ if sys .platform == 'cli' :
257
266
result = str (result )
258
- except UnicodeError :
259
- raise ValueError ("Cannot represent %r as binary." % result )
260
267
return Binary (result )
261
268
262
269
def _contains_binary (self , result ):
263
- return (BINARY .search (result ) or isinstance (result , str ) and
264
- sys .platform != 'cli' and NON_ASCII .search (result ))
270
+ if PY3 :
271
+ return isinstance (result , bytes ) or BINARY .search (result )
272
+ return (isinstance (result , bytes ) and NON_ASCII .search (result ) or
273
+ BINARY .search (result ))
265
274
266
275
def _str (self , item , handle_binary = True ):
267
276
if item is None :
268
277
return ''
269
- if not isinstance (item , basestring ):
278
+ if not isinstance (item , ( str , unicode , bytes ) ):
270
279
item = unicode (item )
271
280
if handle_binary :
272
- return self ._handle_binary_result (item )
281
+ item = self ._handle_binary_result (item )
273
282
return item
274
283
275
284
def _intercept_std_streams (self ):
@@ -286,7 +295,7 @@ def _restore_std_streams(self):
286
295
stream .close ()
287
296
if stdout and stderr :
288
297
if not stderr .startswith (('*TRACE*' , '*DEBUG*' , '*INFO*' , '*HTML*' ,
289
- '*WARN*' )):
298
+ '*WARN*' , '*ERROR*' )):
290
299
stderr = '*INFO* %s' % stderr
291
300
if not stdout .endswith ('\n ' ):
292
301
stdout += '\n '
@@ -310,18 +319,18 @@ def _write_to_stream(self, msg, stream):
310
319
def stop (uri ):
311
320
server = test (uri , log_success = False )
312
321
if server is not None :
313
- print 'Stopping remote server at %s.' % uri
322
+ print ( 'Stopping remote server at %s.' % uri )
314
323
server .stop_remote_server ()
315
324
316
325
def test (uri , log_success = True ):
317
326
server = xmlrpclib .ServerProxy (uri )
318
327
try :
319
328
server .get_keyword_names ()
320
329
except :
321
- print 'No remote server running at %s.' % uri
330
+ print ( 'No remote server running at %s.' % uri )
322
331
return None
323
332
if log_success :
324
- print 'Remote server running at %s.' % uri
333
+ print ( 'Remote server running at %s.' % uri )
325
334
return server
326
335
327
336
def parse_args (args ):
0 commit comments