diff --git a/python/google/protobuf/internal/factory_test1.proto b/python/google/protobuf/internal/factory_test1.proto index 5e729f5b08..a18efcea74 100644 --- a/python/google/protobuf/internal/factory_test1.proto +++ b/python/google/protobuf/internal/factory_test1.proto @@ -52,6 +52,7 @@ message Factory1Message { optional NestedFactory1Message nested_factory_1_message = 3; optional int32 scalar_value = 4; repeated string list_value = 5; + map map_field = 6; extensions 1000 to max; } diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py index 0d132828bd..7138b98202 100644 --- a/python/google/protobuf/internal/message_factory_test.py +++ b/python/google/protobuf/internal/message_factory_test.py @@ -33,6 +33,7 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' import unittest +import gc from google.protobuf import descriptor_pb2 from google.protobuf.internal import api_implementation @@ -285,5 +286,29 @@ class MessageFactoryTest(unittest.TestCase): self.assertEqual(345, m.Extensions[ext2].setting) + def testOndemandCreateMetaClass(self): + def loadFile(): + f = descriptor_pb2.FileDescriptorProto.FromString( + factory_test1_pb2.DESCRIPTOR.serialized_pb) + return message_factory.GetMessages([f]) + + messages = loadFile() + data = factory_test1_pb2.Factory1Message() + data.map_field['hello'] = 'welcome' + # Force GC to collect. UPB python will clean up the map entry class. + # cpp extension and pure python will still keep the map entry class. + gc.collect() + message = messages['google.protobuf.python.internal.Factory1Message']() + message.ParseFromString(data.SerializeToString()) + value = message.map_field + values = [ + # The entry class will be created on demand in upb python. + value.GetEntryClass()(key=k, value=value[k]) for k in sorted(value) + ] + gc.collect() + self.assertEqual(1, len(values)) + self.assertEqual('hello', values[0].key) + self.assertEqual('welcome', values[0].value) + if __name__ == '__main__': unittest.main()