def print_gpb_kv_field_data(name, data, datatype, time, indent):
    """
    Print a single row for a TelemetryField message
    """
    if name == "":
        name = "<no name>"
    print_at_indent("{}: {} ({}) {}".format(name, data, datatype, time), indent)
def print_gpb_kv_field_data(name, data, datatype, time, indent):
    """
    Print a single row for a TelemetryField message
    """
    if name == "":
        name = "<no name>"
    print_at_indent("{}: {} ({}) {}".format(name, data, datatype, time),
                    indent)
def print_gpb_kv_field(field, indent):
    """
    Pretty-print a TelemtryField message
    """
    # Decode the timestamp if there is one
    if field.timestamp != 0:
        time = timestamp_to_string(field.timestamp)
    else:
        time = ""

    # Find the datatype and print it
    datatypes = [
        "bytes_value",
        "string_value",
        "bool_value",
        "uint32_value",
        "uint64_value",
        "sint32_value",
        "sint64_value",
        "double_value",
        "float_value",
    ]
    for d in datatypes:
        datatype = d[:-6]
        if field.HasField(d):
            if datatype == "bytes":
                print_gpb_kv_field_data(field.name, bytes_to_string(field.bytes_value), datatype, time, indent)
            else:
                print_gpb_kv_field_data(field.name, getattr(field, d), datatype, time, indent)

    # If 'fields' is used then recursively call this function to decode
    if len(field.fields) > 0:
        print_gpb_kv_field_data(
            field.name, "fields", "items {}".format(len(field.fields)), "{} {{".format(time), indent
        )

        for f in field.fields:
            print_gpb_kv_field(f, indent + 1)
        print_at_indent("}", indent)
def print_gpb_kv_field(field, indent):
    """
    Pretty-print a TelemtryField message
    """
    # Decode the timestamp if there is one
    if field.timestamp != 0:
        time = timestamp_to_string(field.timestamp)
    else:
        time = ""

    # Find the datatype and print it
    datatypes = [
        "bytes_value", "string_value", "bool_value", "uint32_value",
        "uint64_value", "sint32_value", "sint64_value", "double_value",
        "float_value"
    ]
    for d in datatypes:
        datatype = d[:-6]
        if field.HasField(d):
            if datatype == "bytes":
                print_gpb_kv_field_data(field.name,
                                        bytes_to_string(field.bytes_value),
                                        datatype, time, indent)
            else:
                print_gpb_kv_field_data(field.name, getattr(field, d),
                                        datatype, time, indent)

    # If 'fields' is used then recursively call this function to decode
    if len(field.fields) > 0:
        print_gpb_kv_field_data(field.name, "fields",
                                "items {}".format(len(field.fields)),
                                "{} {{".format(time), indent)

        for f in field.fields:
            print_gpb_kv_field(f, indent + 1)
        print_at_indent("}", indent)
def print_gpb_compact_msg(field, indent, args):
    """
    Recursively iterate over a compactGPB obejct, displaying all fields at an 
    appropriate indent.
    Argument: field
      The object to print.
    Argument: indent
      The indent level to start printing at.
    """
    for descriptor in field.DESCRIPTOR.fields:
        value = getattr(field, descriptor.name)
        if descriptor.type == descriptor.TYPE_MESSAGE:
            #
            # If the value is a sub-message then recursively call this function
            # to decode it. If the message is repeated then iterate over each
            # item.
            #
            if descriptor.label == descriptor.LABEL_REPEATED:
                print_at_indent("{} ({} items) [".format(descriptor.name, len(value)), indent)
                for i, item in enumerate(value):
                    print_at_indent("{} {} {{".format(descriptor.name, i), indent)
                    print_gpb_compact_msg(item, indent + 1, args)
                    print_at_indent("}", indent)
                    if not args.print_all:
                        # Stop after the first item unless all have been
                        # requested
                        break
                print_at_indent("]", indent)
            else:
                print_at_indent("{} {{".format(descriptor.name), indent)
                print_gpb_compact_msg(value, indent + 1, args)
                print_at_indent("}", indent)
        elif descriptor.type == descriptor.TYPE_ENUM:
            #
            # For enum types print the enum name
            #
            enum_name = descriptor.enum_type.values[value].name
            print_at_indent("{}: {}".format(descriptor.name, enum_name), indent)
        elif descriptor.type == descriptor.TYPE_BYTES:
            print_at_indent("{}: {}".format(descriptor.name, bytes_to_string(value)), indent)
        else:
            #
            # For everything else just print the value
            #
            print_at_indent("{}: {}".format(descriptor.name, value), indent)
def print_json_data(obj, indent, args):
    """
    Print the body of a JSON message
    """
    if type(obj) == dict:
        for key in list(obj.keys()):
            child = obj[key]
            # If the child object is a list or dictionary then indent using
            # braces. If the child is a leaf then just print on a single line.
            if type(child) == dict:
                print_at_indent("{} {{".format(key), indent)
                print_json_data(obj[key], indent + 1, args)
                print_at_indent("}", indent)
            elif type(child) == list:
                if not args.print_all:
                    warning = " - displaying first entry only"
                else:
                    warning = ""
                print_at_indent(
                    "{} ({} items{}) [".format(key, len(child), warning),
                    indent)
                print_json_data(obj[key], indent + 1, args)
                print_at_indent("]", indent)
            elif key == "CollectionTime":
                # Pretty-print collection timestamp
                print_at_indent(
                    "{}: {}".format(key, timestamp_to_string(child)), indent)
            else:
                # Try printing values as a string and if that fails print
                # it as bytes
                try:
                    print_at_indent("{}: {}".format(key, str(child)), indent)
                except Exception:
                    print_at_indent(
                        "{}: {}".format(key, bytes_to_string(child)), indent)
    elif type(obj) == list:
        for i, item in enumerate(obj):
            print_at_indent("[{}]".format(i), indent)
            print_json_data(item, indent + 1, args)
            if not args.print_all:
                # Stop after first item
                break
    else:
        print_at_indent("{}".format(str(obj)), indent)
def print_json_data(obj, indent, args):
    """
    Print the body of a JSON message
    """
    if type(obj) == dict:
        for key in list(obj.keys()):
            child = obj[key]
            # If the child object is a list or dictionary then indent using
            # braces. If the child is a leaf then just print on a single line.
            if type(child) == dict:
                print_at_indent("{} {{".format(key), indent)
                print_json_data(obj[key], indent + 1, args)
                print_at_indent("}", indent)
            elif type(child) == list:
                if not args.print_all:
                    warning = " - displaying first entry only"
                else:
                    warning = ""
                print_at_indent("{} ({} items{}) [".format(key, len(child), warning), indent)
                print_json_data(obj[key], indent + 1, args)
                print_at_indent("]", indent)
            elif key == "CollectionTime":
                # Pretty-print collection timestamp
                print_at_indent("{}: {}".format(key, timestamp_to_string(child)), indent)
            else:
                # Try printing values as a string and if that fails print
                # it as bytes
                try:
                    print_at_indent("{}: {}".format(key, str(child)), indent)
                except Exception:
                    print_at_indent("{}: {}".format(key, bytes_to_string(child)), indent)
    elif type(obj) == list:
        for i, item in enumerate(obj):
            print_at_indent("[{}]".format(i), indent)
            print_json_data(item, indent + 1, args)
            if not args.print_all:
                # Stop after first item
                break
    else:
        print_at_indent("{}".format(str(obj)), indent)
def print_gpb_compact_msg(field, indent, args):
    """
    Recursively iterate over a compactGPB obejct, displaying all fields at an 
    appropriate indent.
    Argument: field
      The object to print.
    Argument: indent
      The indent level to start printing at.
    """
    for descriptor in field.DESCRIPTOR.fields:
        value = getattr(field, descriptor.name)
        if descriptor.type == descriptor.TYPE_MESSAGE:
            #
            # If the value is a sub-message then recursively call this function
            # to decode it. If the message is repeated then iterate over each
            # item.
            #
            if descriptor.label == descriptor.LABEL_REPEATED:
                print_at_indent(
                    "{} ({} items) [".format(descriptor.name, len(value)),
                    indent)
                for i, item in enumerate(value):
                    print_at_indent("{} {} {{".format(descriptor.name, i),
                                    indent)
                    print_gpb_compact_msg(item, indent + 1, args)
                    print_at_indent("}", indent)
                    if not args.print_all:
                        # Stop after the first item unless all have been
                        # requested
                        break
                print_at_indent("]", indent)
            else:
                print_at_indent("{} {{".format(descriptor.name), indent)
                print_gpb_compact_msg(value, indent + 1, args)
                print_at_indent("}", indent)
        elif descriptor.type == descriptor.TYPE_ENUM:
            #
            # For enum types print the enum name
            #
            enum_name = descriptor.enum_type.values[value].name
            print_at_indent("{}: {}".format(descriptor.name, enum_name),
                            indent)
        elif descriptor.type == descriptor.TYPE_BYTES:
            print_at_indent(
                "{}: {}".format(descriptor.name, bytes_to_string(value)),
                indent)
        else:
            #
            # For everything else just print the value
            #
            print_at_indent("{}: {}".format(descriptor.name, value), indent)