Skip to content

Struct sub-fields cannot be JSON or dict marshaled #535

@aabmass

Description

@aabmass

Environment details

  • Programming language: Python 3.13
  • OS: Linux
  • Language runtime version: 3.13
  • Package version: proto-plus==1.26.0

Steps to reproduce

There is no way to marshal just a subfield of a message into JSON or a dict. Here's an example

import proto
from google.protobuf import json_format, struct_pb2


# Taken from VertexAI GAPIC client
# https://github.com/googleapis/python-aiplatform/blob/58fbabdeeefd1ccf1a9d0c22eeb5606aeb9c2266/google/cloud/aiplatform_v1beta1/types/tool.py#L293
class FunctionCall(proto.Message):
    name: str = proto.Field(
        proto.STRING,
        number=1,
    )
    args: struct_pb2.Struct = proto.Field(
        proto.MESSAGE,
        number=2,
        message=struct_pb2.Struct,
    )


function_call = FunctionCall()
function_call.name = "foo"

args = struct_pb2.Struct()
args.update({"arg1": "value1", "nest": [{"foo": "bar", "baz": "bar"}]})

# Works fine on the Struct class
print(json_format.MessageToDict(args))

# Fails with AttributeError: 'MapComposite' object has no attribute 'DESCRIPTOR'
function_call.args = args
print(json_format.MessageToDict(function_call.args))
Details

$ python repro.py
{'arg1': 'value1', 'nest': [{'foo': 'bar', 'baz': 'bar'}]}
Traceback (most recent call last):
  File "/usr/local/google/home/aaronabbott/repo/opentelemetry-python-contrib/instrumentation-genai/opentelemetry-instrumentation-vertexai/repro.py", line 30, in <module>
    print(json_format.MessageToDict(function_call.args))
          ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/google/home/aaronabbott/repo/opentelemetry-python-contrib/.venv/lib/python3.13/site-packages/google/protobuf/json_format.py", line 162, in MessageToDict
    return printer._MessageToJsonObject(message)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/local/google/home/aaronabbott/repo/opentelemetry-python-contrib/.venv/lib/python3.13/site-packages/google/protobuf/json_format.py", line 203, in _MessageToJsonObject
    message_descriptor = message.DESCRIPTOR
                         ^^^^^^^^^^^^^^^^^^
AttributeError: 'MapComposite' object has no attribute 'DESCRIPTOR'

The issue is that the StructRule.to_python() returns a MapComposite instead of the google.protobuf.struct_pb2.Struct

return (
None if absent else maps.MapComposite(value.fields, marshal=self._marshal)
)

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions