Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constructing message from dictionary fails when message has nested Struct #424

Closed
Ark-kun opened this issue Jan 23, 2024 · 1 comment
Closed
Assignees
Labels
priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.

Comments

@Ark-kun
Copy link

Ark-kun commented Jan 23, 2024

Usually, if a certain dictionary can be used to initialize a message, then the same dictionary can be used inside a bigger dictionary to initialize a field of a bigger message.

However this invariant fails for the Struct message when it's nested more than once:

from google.protobuf import struct_pb2
import proto

class Msg1(proto.Message):
    struct_field: struct_pb2.Struct = proto.Field(
        proto.MESSAGE,
        number=1,
        message=struct_pb2.Struct,
    )

class Msg2(proto.Message):
    msg1_field: Msg1 = proto.Field(
        proto.MESSAGE,
        number=1,
        message=Msg1,
    )

# This succeeds
Msg1({"struct_field": {"foo": "bar"}})

# This fails:
Msg2({"msg1_field": {"struct_field": {"foo": "bar"}}})
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
[/usr/local/lib/python3.10/dist-packages/proto/message.py](https://localhost:8080/#) in __init__(self, mapping, ignore_unknown_fields, **kwargs)
    580             try:
--> 581                 pb_value = marshal.to_proto(pb_type, value)
    582             except ValueError:

5 frames
[/usr/local/lib/python3.10/dist-packages/proto/marshal/marshal.py](https://localhost:8080/#) in to_proto(self, proto_type, value, strict)
    227 
--> 228         pb_value = self.get_rule(proto_type=proto_type).to_proto(value)
    229 

[/usr/local/lib/python3.10/dist-packages/proto/marshal/rules/message.py](https://localhost:8080/#) in to_proto(self, value)
     35                 # Try the fast path first.
---> 36                 return self._descriptor(**value)
     37             except TypeError as ex:

ValueError: Protocol message Struct has no "foo" field.

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
[<ipython-input-6-ccab0235a57d>](https://localhost:8080/#) in <cell line: 1>()
----> 1 Msg2({"msg1_field": {"struct_field": {"foo": "bar"}}})

[/usr/local/lib/python3.10/dist-packages/proto/message.py](https://localhost:8080/#) in __init__(self, mapping, ignore_unknown_fields, **kwargs)
    607                         value[f"{item}_"] = value.pop(item)
    608 
--> 609                 pb_value = marshal.to_proto(pb_type, value)
    610 
    611             if pb_value is not None:

[/usr/local/lib/python3.10/dist-packages/proto/marshal/marshal.py](https://localhost:8080/#) in to_proto(self, proto_type, value, strict)
    226             return {k: self.to_proto(recursive_type, v) for k, v in value.items()}
    227 
--> 228         pb_value = self.get_rule(proto_type=proto_type).to_proto(value)
    229 
    230         # Sanity check: If we are in strict mode, did we get the value we want?

[/usr/local/lib/python3.10/dist-packages/proto/marshal/rules/message.py](https://localhost:8080/#) in to_proto(self, value)
     34             try:
     35                 # Try the fast path first.
---> 36                 return self._descriptor(**value)
     37             except TypeError as ex:
     38                 # If we have a type error,

ValueError: Protocol message Struct has no "foo" field.

Trying to work around the issue leads to incorrect values:

# This produces incorrect value:
Msg2({"msg1_field": {"struct_field": {"fields": {"foo": "bar"}}}})
msg1_field {
  struct_field {
    fields {
      key: "fields"
      value {
        struct_value {
          fields {
            key: "foo"
            value {
              string_value: "bar"
            }
          }
        }
      }
    }
  }
}

See how "fields" is duplicated. First as a Struct.fields, then as a string map key.

  • Package version: 1.23.0
@Ark-kun Ark-kun added priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns. labels Jan 23, 2024
copybara-service bot pushed a commit to googleapis/python-aiplatform that referenced this issue Mar 13, 2024
…ionResponse`, `Candidate`, `Content`, `Part`)

Workaround for issue in the proto-plus library: googleapis/proto-plus-python#424

Fixes #3194

PiperOrigin-RevId: 604893347
copybara-service bot pushed a commit to googleapis/python-aiplatform that referenced this issue Mar 13, 2024
…ionResponse`, `Candidate`, `Content`, `Part`)

Workaround for issue in the proto-plus library: googleapis/proto-plus-python#424

Fixes #3194

PiperOrigin-RevId: 615334182
@ohmayr
Copy link
Contributor

ohmayr commented Aug 5, 2024

This issue has been addressed in #479.

@ohmayr ohmayr closed this as completed Aug 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Projects
None yet
Development

No branches or pull requests

2 participants