OLD | NEW |
1 # Protocol Buffers - Google's data interchange format | 1 # Protocol Buffers - Google's data interchange format |
2 # Copyright 2008 Google Inc. All rights reserved. | 2 # Copyright 2008 Google Inc. All rights reserved. |
3 # https://developers.google.com/protocol-buffers/ | 3 # https://developers.google.com/protocol-buffers/ |
4 # | 4 # |
5 # Redistribution and use in source and binary forms, with or without | 5 # Redistribution and use in source and binary forms, with or without |
6 # modification, are permitted provided that the following conditions are | 6 # modification, are permitted provided that the following conditions are |
7 # met: | 7 # met: |
8 # | 8 # |
9 # * Redistributions of source code must retain the above copyright | 9 # * Redistributions of source code must retain the above copyright |
10 # notice, this list of conditions and the following disclaimer. | 10 # notice, this list of conditions and the following disclaimer. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 output by the protocol compiler at compile-time. | 44 output by the protocol compiler at compile-time. |
45 | 45 |
46 The upshot of all this is that the real implementation | 46 The upshot of all this is that the real implementation |
47 details for ALL pure-Python protocol buffers are *here in | 47 details for ALL pure-Python protocol buffers are *here in |
48 this file*. | 48 this file*. |
49 """ | 49 """ |
50 | 50 |
51 __author__ = 'robinson@google.com (Will Robinson)' | 51 __author__ = 'robinson@google.com (Will Robinson)' |
52 | 52 |
53 from io import BytesIO | 53 from io import BytesIO |
| 54 import sys |
54 import struct | 55 import struct |
55 import sys | |
56 import weakref | 56 import weakref |
57 | 57 |
58 import six | 58 import six |
59 try: | 59 try: |
60 import six.moves.copyreg as copyreg | 60 import six.moves.copyreg as copyreg |
61 except ImportError: | 61 except ImportError: |
62 # On some platforms, for example gMac, we run native Python because there is | 62 # On some platforms, for example gMac, we run native Python because there is |
63 # nothing like hermetic Python. This means lesser control on the system and | 63 # nothing like hermetic Python. This means lesser control on the system and |
64 # the six.moves package may be missing (is missing on 20150321 on gMac). Be | 64 # the six.moves package may be missing (is missing on 20150321 on gMac). Be |
65 # extra conservative and try to load the old replacement if it fails. | 65 # extra conservative and try to load the old replacement if it fails. |
66 try: | 66 import copy_reg as copyreg |
67 import copy_reg as copyreg #PY26 | |
68 except ImportError: | |
69 import copyreg | |
70 | 67 |
71 # We use "as" to avoid name collisions with variables. | 68 # We use "as" to avoid name collisions with variables. |
72 from google.protobuf.internal import containers | 69 from google.protobuf.internal import containers |
73 from google.protobuf.internal import decoder | 70 from google.protobuf.internal import decoder |
74 from google.protobuf.internal import encoder | 71 from google.protobuf.internal import encoder |
75 from google.protobuf.internal import enum_type_wrapper | 72 from google.protobuf.internal import enum_type_wrapper |
76 from google.protobuf.internal import message_listener as message_listener_mod | 73 from google.protobuf.internal import message_listener as message_listener_mod |
77 from google.protobuf.internal import type_checkers | 74 from google.protobuf.internal import type_checkers |
78 from google.protobuf.internal import well_known_types | 75 from google.protobuf.internal import well_known_types |
79 from google.protobuf.internal import wire_format | 76 from google.protobuf.internal import wire_format |
80 from google.protobuf import descriptor as descriptor_mod | 77 from google.protobuf import descriptor as descriptor_mod |
81 from google.protobuf import message as message_mod | 78 from google.protobuf import message as message_mod |
| 79 from google.protobuf import symbol_database |
82 from google.protobuf import text_format | 80 from google.protobuf import text_format |
83 | 81 |
84 _FieldDescriptor = descriptor_mod.FieldDescriptor | 82 _FieldDescriptor = descriptor_mod.FieldDescriptor |
85 _AnyFullTypeName = 'google.protobuf.Any' | 83 _AnyFullTypeName = 'google.protobuf.Any' |
86 | 84 |
87 | 85 |
88 class GeneratedProtocolMessageType(type): | 86 class GeneratedProtocolMessageType(type): |
89 | 87 |
90 """Metaclass for protocol message classes created at runtime from Descriptors. | 88 """Metaclass for protocol message classes created at runtime from Descriptors. |
91 | 89 |
92 We add implementations for all methods described in the Message class. We | 90 We add implementations for all methods described in the Message class. We |
93 also create properties to allow getting/setting all fields in the protocol | 91 also create properties to allow getting/setting all fields in the protocol |
94 message. Finally, we create slots to prevent users from accidentally | 92 message. Finally, we create slots to prevent users from accidentally |
95 "setting" nonexistent fields in the protocol message, which then wouldn't get | 93 "setting" nonexistent fields in the protocol message, which then wouldn't get |
96 serialized / deserialized properly. | 94 serialized / deserialized properly. |
97 | 95 |
98 The protocol compiler currently uses this metaclass to create protocol | 96 The protocol compiler currently uses this metaclass to create protocol |
99 message classes at runtime. Clients can also manually create their own | 97 message classes at runtime. Clients can also manually create their own |
100 classes at runtime, as in this example: | 98 classes at runtime, as in this example: |
101 | 99 |
102 mydescriptor = Descriptor(.....) | 100 mydescriptor = Descriptor(.....) |
103 factory = symbol_database.Default() | 101 class MyProtoClass(Message): |
104 factory.pool.AddDescriptor(mydescriptor) | 102 __metaclass__ = GeneratedProtocolMessageType |
105 MyProtoClass = factory.GetPrototype(mydescriptor) | 103 DESCRIPTOR = mydescriptor |
106 myproto_instance = MyProtoClass() | 104 myproto_instance = MyProtoClass() |
107 myproto.foo_field = 23 | 105 myproto.foo_field = 23 |
108 ... | 106 ... |
| 107 |
| 108 The above example will not work for nested types. If you wish to include them, |
| 109 use reflection.MakeClass() instead of manually instantiating the class in |
| 110 order to create the appropriate class structure. |
109 """ | 111 """ |
110 | 112 |
111 # Must be consistent with the protocol-compiler code in | 113 # Must be consistent with the protocol-compiler code in |
112 # proto2/compiler/internal/generator.*. | 114 # proto2/compiler/internal/generator.*. |
113 _DESCRIPTOR_KEY = 'DESCRIPTOR' | 115 _DESCRIPTOR_KEY = 'DESCRIPTOR' |
114 | 116 |
115 def __new__(cls, name, bases, dictionary): | 117 def __new__(cls, name, bases, dictionary): |
116 """Custom allocation for runtime-generated class types. | 118 """Custom allocation for runtime-generated class types. |
117 | 119 |
118 We override __new__ because this is apparently the only place | 120 We override __new__ because this is apparently the only place |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 bases: Base classes of the class we're constructing. | 157 bases: Base classes of the class we're constructing. |
156 (Should be message.Message). We ignore this field, but | 158 (Should be message.Message). We ignore this field, but |
157 it's required by the metaclass protocol | 159 it's required by the metaclass protocol |
158 dictionary: The class dictionary of the class we're | 160 dictionary: The class dictionary of the class we're |
159 constructing. dictionary[_DESCRIPTOR_KEY] must contain | 161 constructing. dictionary[_DESCRIPTOR_KEY] must contain |
160 a Descriptor object describing this protocol message | 162 a Descriptor object describing this protocol message |
161 type. | 163 type. |
162 """ | 164 """ |
163 descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] | 165 descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] |
164 cls._decoders_by_tag = {} | 166 cls._decoders_by_tag = {} |
| 167 cls._extensions_by_name = {} |
| 168 cls._extensions_by_number = {} |
165 if (descriptor.has_options and | 169 if (descriptor.has_options and |
166 descriptor.GetOptions().message_set_wire_format): | 170 descriptor.GetOptions().message_set_wire_format): |
167 cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = ( | 171 cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = ( |
168 decoder.MessageSetItemDecoder(descriptor), None) | 172 decoder.MessageSetItemDecoder(cls._extensions_by_number), None) |
169 | 173 |
170 # Attach stuff to each FieldDescriptor for quick lookup later on. | 174 # Attach stuff to each FieldDescriptor for quick lookup later on. |
171 for field in descriptor.fields: | 175 for field in descriptor.fields: |
172 _AttachFieldHelpers(cls, field) | 176 _AttachFieldHelpers(cls, field) |
173 | 177 |
174 descriptor._concrete_class = cls # pylint: disable=protected-access | 178 descriptor._concrete_class = cls # pylint: disable=protected-access |
175 _AddEnumValues(descriptor, cls) | 179 _AddEnumValues(descriptor, cls) |
176 _AddInitMethod(descriptor, cls) | 180 _AddInitMethod(descriptor, cls) |
177 _AddPropertiesForFields(descriptor, cls) | 181 _AddPropertiesForFields(descriptor, cls) |
178 _AddPropertiesForExtensions(descriptor, cls) | 182 _AddPropertiesForExtensions(descriptor, cls) |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 if field.label != _FieldDescriptor.LABEL_REPEATED: | 378 if field.label != _FieldDescriptor.LABEL_REPEATED: |
375 raise ValueError('map_entry set on non-repeated field %s' % ( | 379 raise ValueError('map_entry set on non-repeated field %s' % ( |
376 field.name)) | 380 field.name)) |
377 fields_by_name = field.message_type.fields_by_name | 381 fields_by_name = field.message_type.fields_by_name |
378 key_checker = type_checkers.GetTypeChecker(fields_by_name['key']) | 382 key_checker = type_checkers.GetTypeChecker(fields_by_name['key']) |
379 | 383 |
380 value_field = fields_by_name['value'] | 384 value_field = fields_by_name['value'] |
381 if _IsMessageMapField(field): | 385 if _IsMessageMapField(field): |
382 def MakeMessageMapDefault(message): | 386 def MakeMessageMapDefault(message): |
383 return containers.MessageMap( | 387 return containers.MessageMap( |
384 message._listener_for_children, value_field.message_type, key_checker, | 388 message._listener_for_children, value_field.message_type, key_checker) |
385 field.message_type) | |
386 return MakeMessageMapDefault | 389 return MakeMessageMapDefault |
387 else: | 390 else: |
388 value_checker = type_checkers.GetTypeChecker(value_field) | 391 value_checker = type_checkers.GetTypeChecker(value_field) |
389 def MakePrimitiveMapDefault(message): | 392 def MakePrimitiveMapDefault(message): |
390 return containers.ScalarMap( | 393 return containers.ScalarMap( |
391 message._listener_for_children, key_checker, value_checker, | 394 message._listener_for_children, key_checker, value_checker) |
392 field.message_type) | |
393 return MakePrimitiveMapDefault | 395 return MakePrimitiveMapDefault |
394 | 396 |
395 def _DefaultValueConstructorForField(field): | 397 def _DefaultValueConstructorForField(field): |
396 """Returns a function which returns a default value for a field. | 398 """Returns a function which returns a default value for a field. |
397 | 399 |
398 Args: | 400 Args: |
399 field: FieldDescriptor object for this field. | 401 field: FieldDescriptor object for this field. |
400 | 402 |
401 The returned function has one argument: | 403 The returned function has one argument: |
402 message: Message instance containing this field, or a weakref proxy | 404 message: Message instance containing this field, or a weakref proxy |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
738 setattr(cls, property_name, property(getter, setter, doc=doc)) | 740 setattr(cls, property_name, property(getter, setter, doc=doc)) |
739 | 741 |
740 | 742 |
741 def _AddPropertiesForExtensions(descriptor, cls): | 743 def _AddPropertiesForExtensions(descriptor, cls): |
742 """Adds properties for all fields in this protocol message type.""" | 744 """Adds properties for all fields in this protocol message type.""" |
743 extension_dict = descriptor.extensions_by_name | 745 extension_dict = descriptor.extensions_by_name |
744 for extension_name, extension_field in extension_dict.items(): | 746 for extension_name, extension_field in extension_dict.items(): |
745 constant_name = extension_name.upper() + "_FIELD_NUMBER" | 747 constant_name = extension_name.upper() + "_FIELD_NUMBER" |
746 setattr(cls, constant_name, extension_field.number) | 748 setattr(cls, constant_name, extension_field.number) |
747 | 749 |
748 # TODO(amauryfa): Migrate all users of these attributes to functions like | |
749 # pool.FindExtensionByNumber(descriptor). | |
750 if descriptor.file is not None: | |
751 # TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available. | |
752 pool = descriptor.file.pool | |
753 cls._extensions_by_number = pool._extensions_by_number[descriptor] | |
754 cls._extensions_by_name = pool._extensions_by_name[descriptor] | |
755 | 750 |
756 def _AddStaticMethods(cls): | 751 def _AddStaticMethods(cls): |
757 # TODO(robinson): This probably needs to be thread-safe(?) | 752 # TODO(robinson): This probably needs to be thread-safe(?) |
758 def RegisterExtension(extension_handle): | 753 def RegisterExtension(extension_handle): |
759 extension_handle.containing_type = cls.DESCRIPTOR | 754 extension_handle.containing_type = cls.DESCRIPTOR |
760 # TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available. | |
761 cls.DESCRIPTOR.file.pool.AddExtensionDescriptor(extension_handle) | |
762 _AttachFieldHelpers(cls, extension_handle) | 755 _AttachFieldHelpers(cls, extension_handle) |
| 756 |
| 757 # Try to insert our extension, failing if an extension with the same number |
| 758 # already exists. |
| 759 actual_handle = cls._extensions_by_number.setdefault( |
| 760 extension_handle.number, extension_handle) |
| 761 if actual_handle is not extension_handle: |
| 762 raise AssertionError( |
| 763 'Extensions "%s" and "%s" both try to extend message type "%s" with ' |
| 764 'field number %d.' % |
| 765 (extension_handle.full_name, actual_handle.full_name, |
| 766 cls.DESCRIPTOR.full_name, extension_handle.number)) |
| 767 |
| 768 cls._extensions_by_name[extension_handle.full_name] = extension_handle |
| 769 |
| 770 handle = extension_handle # avoid line wrapping |
| 771 if _IsMessageSetExtension(handle): |
| 772 # MessageSet extension. Also register under type name. |
| 773 cls._extensions_by_name[ |
| 774 extension_handle.message_type.full_name] = extension_handle |
| 775 |
763 cls.RegisterExtension = staticmethod(RegisterExtension) | 776 cls.RegisterExtension = staticmethod(RegisterExtension) |
764 | 777 |
765 def FromString(s): | 778 def FromString(s): |
766 message = cls() | 779 message = cls() |
767 message.MergeFromString(s) | 780 message.MergeFromString(s) |
768 return message | 781 return message |
769 cls.FromString = staticmethod(FromString) | 782 cls.FromString = staticmethod(FromString) |
770 | 783 |
771 | 784 |
772 def _IsPresent(item): | 785 def _IsPresent(item): |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
906 This internal method is differnt from public Any Unpack method which takes | 919 This internal method is differnt from public Any Unpack method which takes |
907 the target message as argument. _InternalUnpackAny method does not have | 920 the target message as argument. _InternalUnpackAny method does not have |
908 target message type and need to find the message type in descriptor pool. | 921 target message type and need to find the message type in descriptor pool. |
909 | 922 |
910 Args: | 923 Args: |
911 msg: An Any message to be unpacked. | 924 msg: An Any message to be unpacked. |
912 | 925 |
913 Returns: | 926 Returns: |
914 The unpacked message. | 927 The unpacked message. |
915 """ | 928 """ |
916 # TODO(amauryfa): Don't use the factory of generated messages. | |
917 # To make Any work with custom factories, use the message factory of the | |
918 # parent message. | |
919 # pylint: disable=g-import-not-at-top | |
920 from google.protobuf import symbol_database | |
921 factory = symbol_database.Default() | |
922 | |
923 type_url = msg.type_url | 929 type_url = msg.type_url |
| 930 db = symbol_database.Default() |
924 | 931 |
925 if not type_url: | 932 if not type_url: |
926 return None | 933 return None |
927 | 934 |
928 # TODO(haberman): For now we just strip the hostname. Better logic will be | 935 # TODO(haberman): For now we just strip the hostname. Better logic will be |
929 # required. | 936 # required. |
930 type_name = type_url.split('/')[-1] | 937 type_name = type_url.split("/")[-1] |
931 descriptor = factory.pool.FindMessageTypeByName(type_name) | 938 descriptor = db.pool.FindMessageTypeByName(type_name) |
932 | 939 |
933 if descriptor is None: | 940 if descriptor is None: |
934 return None | 941 return None |
935 | 942 |
936 message_class = factory.GetPrototype(descriptor) | 943 message_class = db.GetPrototype(descriptor) |
937 message = message_class() | 944 message = message_class() |
938 | 945 |
939 message.ParseFromString(msg.value) | 946 message.ParseFromString(msg.value) |
940 return message | 947 return message |
941 | 948 |
942 | |
943 def _AddEqualsMethod(message_descriptor, cls): | 949 def _AddEqualsMethod(message_descriptor, cls): |
944 """Helper for _AddMessageMethods().""" | 950 """Helper for _AddMessageMethods().""" |
945 def __eq__(self, other): | 951 def __eq__(self, other): |
946 if (not isinstance(other, message_mod.Message) or | 952 if (not isinstance(other, message_mod.Message) or |
947 other.DESCRIPTOR != self.DESCRIPTOR): | 953 other.DESCRIPTOR != self.DESCRIPTOR): |
948 return False | 954 return False |
949 | 955 |
950 if self is other: | 956 if self is other: |
951 return True | 957 return True |
952 | 958 |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1210 | 1216 |
1211 | 1217 |
1212 def _AddMergeFromMethod(cls): | 1218 def _AddMergeFromMethod(cls): |
1213 LABEL_REPEATED = _FieldDescriptor.LABEL_REPEATED | 1219 LABEL_REPEATED = _FieldDescriptor.LABEL_REPEATED |
1214 CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE | 1220 CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE |
1215 | 1221 |
1216 def MergeFrom(self, msg): | 1222 def MergeFrom(self, msg): |
1217 if not isinstance(msg, cls): | 1223 if not isinstance(msg, cls): |
1218 raise TypeError( | 1224 raise TypeError( |
1219 "Parameter to MergeFrom() must be instance of same class: " | 1225 "Parameter to MergeFrom() must be instance of same class: " |
1220 'expected %s got %s.' % (cls.__name__, msg.__class__.__name__)) | 1226 "expected %s got %s." % (cls.__name__, type(msg).__name__)) |
1221 | 1227 |
1222 assert msg is not self | 1228 assert msg is not self |
1223 self._Modified() | 1229 self._Modified() |
1224 | 1230 |
1225 fields = self._fields | 1231 fields = self._fields |
1226 | 1232 |
1227 for field, value in msg._fields.items(): | 1233 for field, value in msg._fields.items(): |
1228 if field.label == LABEL_REPEATED: | 1234 if field.label == LABEL_REPEATED: |
1229 field_value = fields.get(field) | 1235 field_value = fields.get(field) |
1230 if field_value is None: | 1236 if field_value is None: |
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1533 def _FindExtensionByNumber(self, number): | 1539 def _FindExtensionByNumber(self, number): |
1534 """Tries to find a known extension with the field number. | 1540 """Tries to find a known extension with the field number. |
1535 | 1541 |
1536 Args: | 1542 Args: |
1537 number: Extension field number. | 1543 number: Extension field number. |
1538 | 1544 |
1539 Returns: | 1545 Returns: |
1540 Extension field descriptor. | 1546 Extension field descriptor. |
1541 """ | 1547 """ |
1542 return self._extended_message._extensions_by_number.get(number, None) | 1548 return self._extended_message._extensions_by_number.get(number, None) |
OLD | NEW |