protocolbuffers / protobuf

Protocol Buffers - Google's data interchange format
http://protobuf.dev
Other
65.03k stars 15.42k forks source link

Python: json_format.ParseValue #12535

Open xxgreg opened 1 year ago

xxgreg commented 1 year ago

What language does this apply to?

Python

Describe the problem you are trying to solve.

I would like to read a python value into a google.protobuf.Value type.

There is a json_format.ParseDict() function, however this only works if the top-level value is a google.protobuf.Struct.

It is already possible to use the unexported methods of the package to solve the problem, as in the example below.

Example of using unexported _Parser type to solve the problem.

def parse_value(value, target_pb):
    parser = json_format._Parser(False, None, 100)
    parser._ConvertValueMessage(value, target_pb, '')
    return value

Also - apologies if there is already a way to do this. If that is the case - treat this as a doc bug ;)

Describe the solution you'd like

One solution is to add a top-level json_format.ParseValue() function analogous to json_format.ParseDict().

Cheers team!

xxgreg commented 1 year ago

Hmmm it looks like the following works:

v = struct_pb2.Value()
json_format.ParseDict(5, v)
print(v)

So this is a doc bug - not a feature request.

Consider updating the following description to make this behaviour clear.

def ParseDict(js_dict,
              message,
              ignore_unknown_fields=False,
              descriptor_pool=None,
              max_recursion_depth=100):
  """Parses a JSON dictionary representation into a message.

  Args:
    js_dict: Dict representation of a JSON message.
    message: A protocol buffer message to merge into.
    ignore_unknown_fields: If True, do not raise errors for unknown fields.
    descriptor_pool: A Descriptor Pool for resolving types. If None use the
      default.
    max_recursion_depth: max recursion depth of JSON message to be
      deserialized. JSON messages over this depth will fail to be
      deserialized. Default value is 100.

  Returns:
    The same message passed as argument.
  """
zhangskz commented 1 year ago

Please feel free to contribute any documentation improvements that you think would make this behavior clearer here!

xxgreg commented 1 year ago

How about the following changes?

If I can get some feedback here, I'd be happy to turn this into a PR.

Add the following to def ParseDict():

In the special case where the message type is google.protobuf.Value, or google.protobuf.ListValue, the js_dict argument is the corresponding python primitive type.

Add the following to def MessageToDict():

In the special case where the message type is google.protobuf.Value, or google.protobuf.ListValue, the returned value is the corresponding python primitive type.