Skip to content

Commit

Permalink
Make ParseDict nondestructive for Any (#20111)
Browse files Browse the repository at this point in the history
Found this bug where if `_ConvertFieldValuePair` fails while parsing an
Any from a dictionary value then the `@type` field gets removed from
the original object. Adding a simple `try/finally` to ensure we always
restore the original object.

Closes #20111

COPYBARA_INTEGRATE_REVIEW=#20111 from atulmerchia:fix-destructive-anyparser 58aea19
PiperOrigin-RevId: 721850901
  • Loading branch information
atulmerchia authored and copybara-github committed Jan 31, 2025
1 parent 61ec48f commit d59047a
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
22 changes: 22 additions & 0 deletions python/google/protobuf/internal/json_format_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1601,6 +1601,28 @@ def testParseDictAnyDescriptorPoolMissingType(self):
'TestAny.any_value.',
)

def testParseDictNestedAnyDescriptorPoolMissingType(self):
# Confirm that ParseDict nondestructive with empty pool
js_dict = {
'@type': 'type.googleapis.com/google.protobuf.Any',
'value': {
'@type': 'type.googleapis.com/protobuf_unittest.TestAny',
'any_value': {
'@type': 'type.googleapis.com/UnknownMessageType',
},
},
}
js_dict_copy = json.loads(json.dumps(js_dict))
with self.assertRaises(json_format.ParseError) as cm:
json_format.ParseDict(js_dict_copy, any_pb2.Any())
self.assertEqual(
str(cm.exception),
'Failed to parse any_value field: Can not find message descriptor by'
' type_url: type.googleapis.com/UnknownMessageType at'
' Any.value.any_value.',
)
self.assertEqual(js_dict, js_dict_copy)

def testParseDictUnknownValueType(self):
class UnknownClass(object):

Expand Down
6 changes: 4 additions & 2 deletions python/google/protobuf/json_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -734,8 +734,10 @@ def _ConvertAnyMessage(self, value, message, path):
)(self)
else:
del value['@type']
self._ConvertFieldValuePair(value, sub_message, path)
value['@type'] = type_url
try:
self._ConvertFieldValuePair(value, sub_message, path)
finally:
value['@type'] = type_url
# Sets Any message
message.value = sub_message.SerializeToString()
message.type_url = type_url
Expand Down

0 comments on commit d59047a

Please sign in to comment.