Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a nested Protobuf Struct be parsed to a Python dict?

Single level Protobuf Struct fields can be parsed to Python dicts by passing the Struct to the Python dict. However, this does not work with nested dicts. Is there an officially supported method to convert nested Protobuf structs to dicts?

from google.protobuf.struct_pb2 import Struct

simple_struct = Struct()
simple_struct.update({"hi": 1, "there": 2})
print(dict(simple_struct))

nested_struct = Struct()
nested_struct.update({"hi": 1, "over": {"there": 23}})
print(dict(nested_struct))
# Output
{'there': 2.0, 'hi': 1.0}
{'hi': 1.0, 'over': fields {
  key: "there"
  value {
    number_value: 23.0
  }
}
}
like image 366
Moritz Avatar asked Feb 14 '26 12:02

Moritz


1 Answers

I could not find any supported method, but it is possible to recursively parse Protobuf Structs and return a proper Python dict that way.

from typing import Dict, List, Union
from google.protobuf.struct_pb2 import Struct, ListValue, Value

def struct_to_dict(value: Union[Struct, ListValue, Value, None, str, float, bool]) -> Union[None, str, float, bool, Dict, List]:
    if isinstance(value, ListValue):
        return [struct_to_dict(v) for v in value.values]
    if isinstance(value, Struct):
        return {k: struct_to_dict(v) for k, v in value.items()}
    if isinstance(value, Value):
        which_oneof = value.WhichOneof('kind')
        if not which_oneof or which_oneof == 'null_value':
            return None
        return struct_to_dict(getattr(value, which_oneof))
    return value

struct = Struct()
struct.update({"hi": 1, "over": [23, 45, None, 6.7, "there", [8.9, "10"], {"key": None}]})
out = struct_to_dict(struct)

print("bad:")
print(dict(struct))

print("good:")
print(out)
# Output
bad:
{'hi': 1.0, 'over': values {
  number_value: 23
}
values {
  number_value: 45
}
values {
  null_value: NULL_VALUE
}
values {
  number_value: 6.7
}
values {
  string_value: "there"
}
values {
  list_value {
    values {
      number_value: 8.9
    }
    values {
      string_value: "10"
    }
  }
}
values {
  struct_value {
    fields {
      key: "key"
      value {
        null_value: NULL_VALUE
      }
    }
  }
}
}
good:
{'hi': 1.0, 'over': [23.0, 45.0, None, 6.7, 'there', [8.9, '10'], {'key': None}]}
like image 173
Moritz Avatar answered Feb 16 '26 01:02

Moritz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!