# Buggy code
def create_value_transform(echo_nostr, echo_noarr):
    def value_transform(val):
        class TransformedMessage(genpy.Message):
            # These should be copy because changing these variables
            # in transforming is problematic without its untransforming.
            __slots__ = val.__slots__[:]
            _slot_types = val._slot_types[:]

        val_trans = TransformedMessage()

        fields = val.__slots__
        field_types = val._slot_types
        for index, (f, t) in enumerate(zip(fields, field_types)):
            f_val = getattr(val, f)
            if echo_noarr and "[" in t:
                setattr(
                    val_trans,
                    f,
                    "<array type: %s, length: %s>" % (t.rstrip("[]"), len(f_val)),
                )
                val_trans._slot_types[index] = "string"
            elif echo_nostr and "string" in t:
                setattr(val_trans, f, "<string length: %s>" % len(f_val))
            else:
                try:
                    msg_class = genpy.message.get_message_class(t)
                    if msg_class is None:
                        # happens for list of ROS messages like std_msgs/String[]
                        raise ValueError
                    nested_transformed = value_transform(f_val)
                    setattr(val_trans, f, nested_transformed)
                except ValueError:
                    setattr(val_trans, f, f_val)
        return val_trans

    return value_transform


# Traceback (AttributeError)
$ rostopic echo /rosout/msg -n 1
Traceback (most recent call last):
File "<ws>/lib/python2.7/dist-packages/rostopic/__init__.py", line 940, in callback
self.suffix + '\n')
File "<ws>/lib/python2.7/dist-packages/rostopic/__init__.py", line 876, in custom_strify_message
val = value_transform(val)
File "<ws>/lib/python2.7/dist-packages/rostopic/__init__.py", line 1393, in value_transform
class TransformedMessage(genpy.Message):
File "<ws>/lib/python2.7/dist-packages/rostopic/__init__.py", line 1396, in TransformedMessage
__slots__ = val.__slots__[:]
AttributeError: 'str' object has no attribute '__slots__'

$ rostopic echo /rosout/topics -n 1
Traceback (most recent call last):
File "<ws>/lib/python2.7/dist-packages/rostopic/__init__.py", line 940, in callback
self.suffix + '\n')
File "<ws>/lib/python2.7/dist-packages/rostopic/__init__.py", line 876, in custom_strify_message
val = value_transform(val)
File "<ws>/lib/python2.7/dist-packages/rostopic/__init__.py", line 1393, in value_transform
class TransformedMessage(genpy.Message):
File "<ws>/lib/python2.7/dist-packages/rostopic/__init__.py", line 1396, in TransformedMessage
__slots__ = val.__slots__[:]
AttributeError: 'list' object has no attribute '__slots__'

# Fixed code
def create_value_transform(echo_nostr, echo_noarr):
    def value_transform(val, type_information=None):
        def transform_field_value(value, value_type, echo_nostr, echo_noarr):
            if echo_noarr and "[" in value_type:
                return "<array type: %s, length: %s>" % (
                    value_type.rstrip("[]"),
                    len(value),
                )
            elif echo_nostr and value_type == "string":
                return "<string length: %s>" % len(value)
            elif echo_nostr and value_type == "string[]":
                return "<array type: string, length: %s>" % len(value)
            return value

        if not isinstance(val, genpy.Message):
            if type_information is None:
                return val
            return transform_field_value(val, type_information, echo_nostr, echo_noarr)

        class TransformedMessage(genpy.Message):
            # These should be copy because changing these variables
            # in transforming is problematic without its untransforming.
            __slots__ = val.__slots__[:]
            _slot_types = val._slot_types[:]

        val_trans = TransformedMessage()

        fields = val.__slots__
        field_types = val._slot_types
        for index, (f, t) in enumerate(zip(fields, field_types)):
            f_val = getattr(val, f)
            f_val_trans = transform_field_value(f_val, t, echo_nostr, echo_noarr)
            if f_val_trans != f_val:
                setattr(val_trans, f, f_val_trans)
                val_trans._slot_types[index] = "string"
            else:
                try:
                    msg_class = genpy.message.get_message_class(t)
                    if msg_class is None:
                        # happens for list of ROS messages like std_msgs/String[]
                        raise ValueError
                    nested_transformed = value_transform(f_val)
                    setattr(val_trans, f, nested_transformed)
                except ValueError:
                    setattr(val_trans, f, f_val)
        return val_trans

    return value_transform