示例#1
0
文件: generator.py 项目: haas85/genpy
def serializer_generator(msg_context, spec, serialize, is_numpy):
    """
    Python generator that yields un-indented python code for
    (de)serializing MsgSpec. The code this yields is meant to be
    included in a class method and cannot be used
    standalone. serialize_fn_generator and deserialize_fn_generator
    wrap method to provide appropriate class field initializations.

    :param serialize: if True, yield serialization
      code. Otherwise, yield deserialization code. ``bool``
    :param is_numpy: if True, generate serializer code for numpy datatypes instead of Python lists. ``bool``
    """
    # Break spec into chunks of simple (primitives) vs. complex (arrays, etc...)
    # Simple types are batch serialized using the python struct module.
    # Complex types are individually serialized
    if spec is None:
        raise MsgGenerationException("spec is none")
    names, types = spec.names, spec.types
    if serialize and not len(names): #Empty
        yield "pass"
        return

    _max_chunk = 255
    # iterate through types. whenever we encounter a non-simple type,
    # yield serializer for any simple types we've encountered until
    # then, then yield the complex type serializer
    curr = 0
    for (i, full_type) in enumerate(types):
        if not is_simple(full_type):
            if i != curr: #yield chunk of simples
                for _start in range(curr, i, _max_chunk):
                    _end = min(_start + _max_chunk, i)
                    for y in simple_serializer_generator(msg_context, spec, _start, _end, serialize):
                        yield y
            curr = i+1
            for y in complex_serializer_generator(msg_context, spec.package, full_type, names[i], serialize, is_numpy):
                yield y
    if curr < len(types): #yield rest of simples
        for _start in range(curr, len(types), _max_chunk):
            _end = min(_start + _max_chunk, len(types))
            for y in simple_serializer_generator(msg_context, spec, _start, _end, serialize):
                yield y
示例#2
0
文件: message.py 项目: haas85/genpy
def check_type(field_name, field_type, field_val):
    """
    Dynamic type checker that maps ROS .msg types to python types and
    verifies the python value.  check_type() is not designed to be
    fast and is targeted at error diagnosis. This type checker is not
    designed to run fast and is meant only for error diagnosis.

    :param field_name: ROS .msg field name, ``str``
    :param field_type: ROS .msg field type, ``str``
    :param field_val: field value, ``Any``
    :raises: :exc:`SerializationError` If typecheck fails
    """
    if is_simple(field_type):
        # check sign and width
        if field_type in ['byte', 'int8', 'int16', 'int32', 'int64']:
            if type(field_val) not in [long, int]:
                raise SerializationError('field %s must be an integer type' %
                                         field_name)
            maxval = int(math.pow(2, _widths[field_type] - 1))
            if field_val >= maxval or field_val <= -maxval:
                raise SerializationError(
                    'field %s exceeds specified width [%s]' %
                    (field_name, field_type))
        elif field_type in ['char', 'uint8', 'uint16', 'uint32', 'uint64']:
            if type(field_val) not in [long, int] or field_val < 0:
                raise SerializationError(
                    'field %s must be unsigned integer type' % field_name)
            maxval = int(math.pow(2, _widths[field_type]))
            if field_val >= maxval:
                raise SerializationError(
                    'field %s exceeds specified width [%s]' %
                    (field_name, field_type))
        elif field_type == 'bool':
            if field_val not in [True, False, 0, 1]:
                raise SerializationError('field %s is not a bool' %
                                         (field_name))
    elif field_type == 'string':
        if sys.hexversion > 0x03000000:
            if type(field_val) == str:
                try:
                    field_val.encode('ascii')
                except UnicodeEncodeError:
                    raise SerializationError('field %s is a non-ascii string' %
                                             field_name)
            elif not type(field_val) == bytes:
                raise SerializationError(
                    'field %s must be of type bytes or 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 not isstring(field_val):
                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)
    elif field_type == 'duration':
        if not isinstance(field_val, Duration):
            raise SerializationError('field %s must be of type Duration' %
                                     field_name)

    elif field_type.endswith(']'):  # array type
        # use index to generate error if '[' not present
        base_type = field_type[:field_type.index('[')]

        if type(field_val) == str:
            if not base_type in ['char', 'uint8']:
                raise SerializationError(
                    'field %s must be a list or tuple type. Only uint8[] can be a string'
                    % field_name)
            else:
                #It's a string so its already in byte format and we
                #don't need to check the individual bytes in the
                #string.
                return

        if not type(field_val) in [list, tuple]:
            raise SerializationError('field %s must be a list or tuple type' %
                                     field_name)
        for v in field_val:
            check_type(field_name + "[]", base_type, v)
    else:
        if isinstance(field_val, Message):
            # roslib/Header is the old location of Header. We check it for backwards compat
            if field_val._type in ['std_msgs/Header', 'roslib/Header']:
                if field_type not in [
                        'Header', 'std_msgs/Header', 'roslib/Header'
                ]:
                    raise SerializationError(
                        "field %s must be a Header instead of a %s" %
                        (field_name, field_val._type))
            elif field_val._type != field_type:
                raise SerializationError(
                    "field %s must be of type %s instead of %s" %
                    (field_name, field_type, field_val._type))
            for n, t in zip(field_val.__slots__, field_val._get_types()):
                check_type("%s.%s" % (field_name, n), t, getattr(field_val, n))
        else:
            raise SerializationError("field %s must be of type [%s]" %
                                     (field_name, field_type))
示例#3
0
文件: generator.py 项目: haas85/genpy
def array_serializer_generator(msg_context, package, type_, name, serialize, is_numpy):
    """
    Generator for array types

    :raises: :exc:`MsgGenerationException` If array spec is invalid
    """
    base_type, is_array, array_len = genmsg.msgs.parse_type(type_)
    if not is_array:
        raise MsgGenerationException("Invalid array spec: %s"%type_)
    var_length = array_len is None

    # handle fixed-size byte arrays could be slightly more efficient
    # as we recalculated the length in the generated code.
    if base_type in ['char', 'uint8']: #treat unsigned int8 arrays as string type
        for y in string_serializer_generator(package, type_, name, serialize):
            yield y
        return

    var = _serial_context+name
    # yield length serialization, if necessary
    if var_length:
        for y in len_serializer_generator(var, False, serialize):
            yield y #serialize array length
        length = None
    else:
        length = array_len

    #optimization for simple arrays
    if is_simple(base_type):
        if var_length:
            pattern = compute_struct_pattern([base_type])
            yield "pattern = '<%%s%s'%%length"%pattern
            if serialize:
                if is_numpy:
                    yield pack_numpy(var)
                else:
                    yield pack2('pattern', "*"+var)
            else:
                yield "start = end"
                yield "end += struct.calcsize(pattern)"
                if is_numpy:
                    dtype = NUMPY_DTYPE[base_type]
                    yield unpack_numpy(var, 'length', dtype, 'str[start:end]')
                else:
                    yield unpack2(var, 'pattern', 'str[start:end]')
        else:
            pattern = "%s%s"%(length, compute_struct_pattern([base_type]))
            if serialize:
                if is_numpy:
                    yield pack_numpy(var)
                else:
                    yield pack(pattern, "*"+var)
            else:
                yield "start = end"
                yield "end += %s"%struct.calcsize('<%s'%pattern)
                if is_numpy:
                    dtype = NUMPY_DTYPE[base_type]
                    yield unpack_numpy(var, length, dtype, 'str[start:end]')
                else:
                    yield unpack(var, pattern, 'str[start:end]')
        if not serialize and base_type == 'bool':
            # convert uint8 to bool
            if base_type == 'bool':
                yield "%s = map(bool, %s)"%(var, var)

    else:
        #generic recursive serializer
        #NOTE: this is functionally equivalent to the is_registered branch of complex_serializer_generator

        # choose a unique temporary variable for iterating
        loop_var = 'val%s'%len(_context_stack)

        # compute the variable context and factory to use
        if base_type == 'string':
            push_context('')
            factory = string_serializer_generator(package, base_type, loop_var, serialize)
        else:
            push_context('%s.'%loop_var)
            factory = serializer_generator(msg_context, get_registered_ex(msg_context, base_type), serialize, is_numpy)

        if serialize:
            yield 'for %s in %s:'%(loop_var, var)
        else:
            yield '%s = []'%var
            if var_length:
                yield 'for i in range(0, length):'
            else:
                yield 'for i in range(0, %s):'%length
            if base_type != 'string':
                yield INDENT + '%s = %s'%(loop_var, compute_constructor(msg_context, package, base_type))
        for y in factory:
            yield INDENT + y
        if not serialize:
            yield INDENT + '%s.append(%s)'%(var, loop_var)
        pop_context()
示例#4
0
def check_type(field_name, field_type, field_val):
    """
    Dynamic type checker that maps ROS .msg types to python types and
    verifies the python value.  check_type() is not designed to be
    fast and is targeted at error diagnosis. This type checker is not
    designed to run fast and is meant only for error diagnosis.

    :param field_name: ROS .msg field name, ``str``
    :param field_type: ROS .msg field type, ``str``
    :param field_val: field value, ``Any``
    :raises: :exc:`SerializationError` If typecheck fails
    """
    if is_simple(field_type):
        # check sign and width
        if field_type in ['byte', 'int8', 'int16', 'int32', 'int64']:
            if type(field_val) not in [long, int]:
                raise SerializationError('field %s must be an integer type'%field_name)
            maxval = int(math.pow(2, _widths[field_type]-1))
            if field_val >= maxval or field_val <= -maxval:
                raise SerializationError('field %s exceeds specified width [%s]'%(field_name, field_type))
        elif field_type in ['char', 'uint8', 'uint16', 'uint32', 'uint64']:
            if type(field_val) not in [long, int] or field_val < 0:
                raise SerializationError('field %s must be unsigned integer type'%field_name)
            maxval = int(math.pow(2, _widths[field_type]))
            if field_val >= maxval:
                raise SerializationError('field %s exceeds specified width [%s]'%(field_name, field_type))
        elif field_type == 'bool':
            if field_val not in [True, False, 0, 1]:
                raise SerializationError('field %s is not a bool'%(field_name))
    elif field_type == 'string':
        if sys.hexversion > 0x03000000:
            if type(field_val) == str:
                try:
                    field_val.encode('ascii')
                except UnicodeEncodeError:
                    raise SerializationError('field %s is a non-ascii string'%field_name)
            elif not type(field_val) == bytes:
                raise SerializationError('field %s must be of type bytes or 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 not isstring(field_val):
                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)
    elif field_type == 'duration':
        if not isinstance(field_val, Duration):
            raise SerializationError('field %s must be of type Duration'%field_name)

    elif field_type.endswith(']'): # array type
        # use index to generate error if '[' not present
        base_type = field_type[:field_type.index('[')]

        if type(field_val) == str:
            if not base_type in ['char', 'uint8']:
                raise SerializationError('field %s must be a list or tuple type. Only uint8[] can be a string' % field_name);
            else:
                #It's a string so its already in byte format and we
                #don't need to check the individual bytes in the
                #string.
                return

        if not type(field_val) in [list, tuple]:
            raise SerializationError('field %s must be a list or tuple type'%field_name)
        for v in field_val:
            check_type(field_name+"[]", base_type, v)
    else:
        if isinstance(field_val, Message):
            # roslib/Header is the old location of Header. We check it for backwards compat
            if field_val._type in ['std_msgs/Header', 'roslib/Header']:
                if field_type not in ['Header', 'std_msgs/Header', 'roslib/Header']:
                    raise SerializationError("field %s must be a Header instead of a %s"%(field_name, field_val._type))
            elif field_val._type != field_type:
                raise SerializationError("field %s must be of type %s instead of %s"%(field_name, field_type, field_val._type))
            for n, t in zip(field_val.__slots__, field_val._get_types()):
                check_type("%s.%s"%(field_name,n), t, getattr(field_val, n))
        else:
            raise SerializationError("field %s must be of type [%s]"%(field_name, field_type))