#3576: integrating patch from michikarg for py3k compatibility. made some fixes to (str, str) check as well as some list/tuple conversions that were lost

This commit is contained in:
Ken Conley 2011-08-05 17:53:27 +00:00
parent 58e45fb920
commit b58c47a718
1 changed files with 48 additions and 15 deletions

View File

@ -43,6 +43,7 @@ import math
import itertools
import traceback
import struct
import sys
import roslib.exceptions
from roslib.rostime import Time, Duration, TVal
@ -50,8 +51,21 @@ from roslib.rostime import Time, Duration, TVal
# common struct pattern singletons for msgs to use. Although this
# would better placed in a generator-specific module, we don't want to
# add another import to messages (which incurs higher import cost)
if sys.version > '3':
long = int
struct_I = struct.Struct('<I')
def isstring(s):
"""Small helper version to check an object is a string in a way that works
for both Python 2 and 3
"""
try:
return isinstance(s, basestring)
except NameError:
return isinstance(s, str)
class ROSMessageException(roslib.exceptions.ROSLibException):
"""
Exception type for errors in roslib.message routines
@ -166,10 +180,11 @@ def strify_message(val, indent='', time_offset=None, current_time=None, field_fi
@return: string (YAML) representation of message
@rtype: str
"""
type_ = type(val)
if type_ in (int, long, float, bool):
return str(val)
elif type_ in (str, unicode):
elif isstring(val):
#TODO: need to escape strings correctly
if not val:
return "''"
@ -201,8 +216,12 @@ def strify_message(val, indent='', time_offset=None, current_time=None, field_fi
p = '%s%%s: %%s'%(indent)
ni = ' '+indent
vals = '\n'.join([p%(f,
strify_message(_convert_getattr(val, f, t), ni, time_offset, current_time, field_filter)) for f,t in itertools.izip(val.__slots__, val._slot_types) if f in fields])
if sys.hexversion > 0x03000000: #Python3
vals = '\n'.join([p%(f,
strify_message(_convert_getattr(val, f, t), ni, time_offset, current_time, field_filter)) for f,t in zip(val.__slots__, val._slot_types) if f in fields])
else: #Python2
vals = '\n'.join([p%(f,
strify_message(_convert_getattr(val, f, t), ni, time_offset, current_time, field_filter)) for f,t in itertools.izip(val.__slots__, val._slot_types) if f in fields])
if indent:
return '\n'+vals
else:
@ -217,7 +236,7 @@ def _convert_getattr(val, f, t):
to convert uint8[] fields back to an array type.
"""
attr = getattr(val, f)
if type(attr) in (str, unicode) and 'uint8[' in t:
if isstring(attr) and 'uint8[' in t:
return [ord(x) for x in attr]
else:
return attr
@ -271,10 +290,15 @@ def check_type(field_name, field_type, field_val):
if field_val not in [True, False, 0, 1]:
raise SerializationError('field %s is not a bool'%(field_name))
elif field_type == 'string':
if type(field_val) == unicode:
raise SerializationError('field %s is a unicode string instead of an ascii string'%field_name)
elif type(field_val) != str:
raise SerializationError('field %s must be of type str'%field_name)
if sys.hexversion > 0x03000000:
if type(field_val) == str:
raise SerializationError('field %s is a unicode string instead of an ascii string'%field_name)
else:
if type(field_val) == unicode:
raise SerializationError('field %s is a unicode string instead of an ascii string'%field_name)
elif type(field_val) != str:
raise SerializationError('field %s must be of type str'%field_name)
elif field_type == 'time':
if not isinstance(field_val, Time):
raise SerializationError('field %s must be of type Time'%field_name)
@ -336,12 +360,12 @@ class Message(object):
raise TypeError("Message constructor may only use args OR keywords, not both")
if args:
if len(args) != len(self.__slots__):
raise TypeError, "Invalid number of arguments, args should be %s"%str(self.__slots__)+" args are"+str(args)
raise TypeError("Invalid number of arguments, args should be %s"%str(self.__slots__)+" args are"+str(args))
for i, k in enumerate(self.__slots__):
setattr(self, k, args[i])
else:
# validate kwds
for k,v in kwds.iteritems():
for k,v in kwds.items():
if not k in self.__slots__:
raise AttributeError("%s is not an attribute of %s"%(k, self.__class__.__name__))
# iterate through slots so all fields are initialized.
@ -363,7 +387,7 @@ class Message(object):
"""
support for Python pickling
"""
for x, val in itertools.izip(self.__slots__, state):
for x, val in zip(self.__slots__, state):
setattr(self, x, val)
def _get_types(self):
@ -440,9 +464,18 @@ def get_printable_message_args(msg, buff=None, prefix=''):
@return: printable representation of msg args
@rtype: str
"""
import cStringIO
try:
from cStringIO import StringIO # Python 2.x
python3 = 0
except ImportError:
from io import BytesIO # Python 3.x
python3 = 1
if buff is None:
buff = cStringIO.StringIO()
if python3 == 1:
buff = BytesIO()
else:
buff = StringIO()
for f in msg.__slots__:
if isinstance(getattr(msg, f), Message):
get_printable_message_args(getattr(msg, f), buff=buff, prefix=(prefix+f+'.'))
@ -529,7 +562,7 @@ def _fill_message_args(msg, msg_args, keys, prefix=''):
#print "DICT ARGS", msg_args
#print "ACTIVE SLOTS",msg.__slots__
for f, v in msg_args.iteritems():
for f, v in msg_args.items():
# assume that an empty key is actually an empty string
if v == None:
v = ''
@ -544,7 +577,7 @@ def _fill_message_args(msg, msg_args, keys, prefix=''):
elif len(msg_args) < len(msg.__slots__):
raise ROSMessageException("Not enough arguments:\n * Given: %s\n * Expected: %s"%(msg_args, msg.__slots__))
for f, v in itertools.izip(msg.__slots__, msg_args):
for f, v in zip(msg.__slots__, msg_args):
_fill_val(msg, f, v, keys, prefix)
else:
raise ValueError("invalid msg_args type: %s"%str(msg_args))