-
Notifications
You must be signed in to change notification settings - Fork 37
Closed
Labels
priority: p2Moderately-important priority. Fix may not be included in next release.Moderately-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.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Description
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
Metadata
Metadata
Assignees
Labels
priority: p2Moderately-important priority. Fix may not be included in next release.Moderately-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.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.