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 struct |
54 import sys | 55 import sys |
55 import struct | |
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 import copy_reg as copyreg | 66 try: |
| 67 import copy_reg as copyreg #PY26 |
| 68 except ImportError: |
| 69 import copyreg |
67 | 70 |
68 # We use "as" to avoid name collisions with variables. | 71 # We use "as" to avoid name collisions with variables. |
69 from google.protobuf.internal import containers | 72 from google.protobuf.internal import containers |
70 from google.protobuf.internal import decoder | 73 from google.protobuf.internal import decoder |
71 from google.protobuf.internal import encoder | 74 from google.protobuf.internal import encoder |
72 from google.protobuf.internal import enum_type_wrapper | 75 from google.protobuf.internal import enum_type_wrapper |
73 from google.protobuf.internal import message_listener as message_listener_mod | 76 from google.protobuf.internal import message_listener as message_listener_mod |
74 from google.protobuf.internal import type_checkers | 77 from google.protobuf.internal import type_checkers |
75 from google.protobuf.internal import well_known_types | 78 from google.protobuf.internal import well_known_types |
76 from google.protobuf.internal import wire_format | 79 from google.protobuf.internal import wire_format |
77 from google.protobuf import descriptor as descriptor_mod | 80 from google.protobuf import descriptor as descriptor_mod |
78 from google.protobuf import message as message_mod | 81 from google.protobuf import message as message_mod |
79 from google.protobuf import symbol_database | |
80 from google.protobuf import text_format | 82 from google.protobuf import text_format |
81 | 83 |
82 _FieldDescriptor = descriptor_mod.FieldDescriptor | 84 _FieldDescriptor = descriptor_mod.FieldDescriptor |
83 _AnyFullTypeName = 'google.protobuf.Any' | 85 _AnyFullTypeName = 'google.protobuf.Any' |
84 | 86 |
85 | 87 |
86 class GeneratedProtocolMessageType(type): | 88 class GeneratedProtocolMessageType(type): |
87 | 89 |
88 """Metaclass for protocol message classes created at runtime from Descriptors. | 90 """Metaclass for protocol message classes created at runtime from Descriptors. |
89 | 91 |
90 We add implementations for all methods described in the Message class. We | 92 We add implementations for all methods described in the Message class. We |
91 also create properties to allow getting/setting all fields in the protocol | 93 also create properties to allow getting/setting all fields in the protocol |
92 message. Finally, we create slots to prevent users from accidentally | 94 message. Finally, we create slots to prevent users from accidentally |
93 "setting" nonexistent fields in the protocol message, which then wouldn't get | 95 "setting" nonexistent fields in the protocol message, which then wouldn't get |
94 serialized / deserialized properly. | 96 serialized / deserialized properly. |
95 | 97 |
96 The protocol compiler currently uses this metaclass to create protocol | 98 The protocol compiler currently uses this metaclass to create protocol |
97 message classes at runtime. Clients can also manually create their own | 99 message classes at runtime. Clients can also manually create their own |
98 classes at runtime, as in this example: | 100 classes at runtime, as in this example: |
99 | 101 |
100 mydescriptor = Descriptor(.....) | 102 mydescriptor = Descriptor(.....) |
101 class MyProtoClass(Message): | 103 factory = symbol_database.Default() |
102 __metaclass__ = GeneratedProtocolMessageType | 104 factory.pool.AddDescriptor(mydescriptor) |
103 DESCRIPTOR = mydescriptor | 105 MyProtoClass = factory.GetPrototype(mydescriptor) |
104 myproto_instance = MyProtoClass() | 106 myproto_instance = MyProtoClass() |
105 myproto.foo_field = 23 | 107 myproto.foo_field = 23 |
106 ... | 108 ... |
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. | |
111 """ | 109 """ |
112 | 110 |
113 # Must be consistent with the protocol-compiler code in | 111 # Must be consistent with the protocol-compiler code in |
114 # proto2/compiler/internal/generator.*. | 112 # proto2/compiler/internal/generator.*. |
115 _DESCRIPTOR_KEY = 'DESCRIPTOR' | 113 _DESCRIPTOR_KEY = 'DESCRIPTOR' |
116 | 114 |
117 def __new__(cls, name, bases, dictionary): | 115 def __new__(cls, name, bases, dictionary): |
118 """Custom allocation for runtime-generated class types. | 116 """Custom allocation for runtime-generated class types. |
119 | 117 |
120 We override __new__ because this is apparently the only place | 118 We override __new__ because this is apparently the only place |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 bases: Base classes of the class we're constructing. | 155 bases: Base classes of the class we're constructing. |
158 (Should be message.Message). We ignore this field, but | 156 (Should be message.Message). We ignore this field, but |
159 it's required by the metaclass protocol | 157 it's required by the metaclass protocol |
160 dictionary: The class dictionary of the class we're | 158 dictionary: The class dictionary of the class we're |
161 constructing. dictionary[_DESCRIPTOR_KEY] must contain | 159 constructing. dictionary[_DESCRIPTOR_KEY] must contain |
162 a Descriptor object describing this protocol message | 160 a Descriptor object describing this protocol message |
163 type. | 161 type. |
164 """ | 162 """ |
165 descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] | 163 descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] |
166 cls._decoders_by_tag = {} | 164 cls._decoders_by_tag = {} |
167 cls._extensions_by_name = {} | |
168 cls._extensions_by_number = {} | |
169 if (descriptor.has_options and | 165 if (descriptor.has_options and |
170 descriptor.GetOptions().message_set_wire_format): | 166 descriptor.GetOptions().message_set_wire_format): |
171 cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = ( | 167 cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = ( |
172 decoder.MessageSetItemDecoder(cls._extensions_by_number), None) | 168 decoder.MessageSetItemDecoder(descriptor), None) |
173 | 169 |
174 # Attach stuff to each FieldDescriptor for quick lookup later on. | 170 # Attach stuff to each FieldDescriptor for quick lookup later on. |
175 for field in descriptor.fields: | 171 for field in descriptor.fields: |
176 _AttachFieldHelpers(cls, field) | 172 _AttachFieldHelpers(cls, field) |
177 | 173 |
178 descriptor._concrete_class = cls # pylint: disable=protected-access | 174 descriptor._concrete_class = cls # pylint: disable=protected-access |
179 _AddEnumValues(descriptor, cls) | 175 _AddEnumValues(descriptor, cls) |
180 _AddInitMethod(descriptor, cls) | 176 _AddInitMethod(descriptor, cls) |
181 _AddPropertiesForFields(descriptor, cls) | 177 _AddPropertiesForFields(descriptor, cls) |
182 _AddPropertiesForExtensions(descriptor, cls) | 178 _AddPropertiesForExtensions(descriptor, cls) |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 if field.label != _FieldDescriptor.LABEL_REPEATED: | 374 if field.label != _FieldDescriptor.LABEL_REPEATED: |
379 raise ValueError('map_entry set on non-repeated field %s' % ( | 375 raise ValueError('map_entry set on non-repeated field %s' % ( |
380 field.name)) | 376 field.name)) |
381 fields_by_name = field.message_type.fields_by_name | 377 fields_by_name = field.message_type.fields_by_name |
382 key_checker = type_checkers.GetTypeChecker(fields_by_name['key']) | 378 key_checker = type_checkers.GetTypeChecker(fields_by_name['key']) |
383 | 379 |
384 value_field = fields_by_name['value'] | 380 value_field = fields_by_name['value'] |
385 if _IsMessageMapField(field): | 381 if _IsMessageMapField(field): |
386 def MakeMessageMapDefault(message): | 382 def MakeMessageMapDefault(message): |
387 return containers.MessageMap( | 383 return containers.MessageMap( |
388 message._listener_for_children, value_field.message_type, key_checker) | 384 message._listener_for_children, value_field.message_type, key_checker, |
| 385 field.message_type) |
389 return MakeMessageMapDefault | 386 return MakeMessageMapDefault |
390 else: | 387 else: |
391 value_checker = type_checkers.GetTypeChecker(value_field) | 388 value_checker = type_checkers.GetTypeChecker(value_field) |
392 def MakePrimitiveMapDefault(message): | 389 def MakePrimitiveMapDefault(message): |
393 return containers.ScalarMap( | 390 return containers.ScalarMap( |
394 message._listener_for_children, key_checker, value_checker) | 391 message._listener_for_children, key_checker, value_checker, |
| 392 field.message_type) |
395 return MakePrimitiveMapDefault | 393 return MakePrimitiveMapDefault |
396 | 394 |
397 def _DefaultValueConstructorForField(field): | 395 def _DefaultValueConstructorForField(field): |
398 """Returns a function which returns a default value for a field. | 396 """Returns a function which returns a default value for a field. |
399 | 397 |
400 Args: | 398 Args: |
401 field: FieldDescriptor object for this field. | 399 field: FieldDescriptor object for this field. |
402 | 400 |
403 The returned function has one argument: | 401 The returned function has one argument: |
404 message: Message instance containing this field, or a weakref proxy | 402 message: Message instance containing this field, or a weakref proxy |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 setattr(cls, property_name, property(getter, setter, doc=doc)) | 738 setattr(cls, property_name, property(getter, setter, doc=doc)) |
741 | 739 |
742 | 740 |
743 def _AddPropertiesForExtensions(descriptor, cls): | 741 def _AddPropertiesForExtensions(descriptor, cls): |
744 """Adds properties for all fields in this protocol message type.""" | 742 """Adds properties for all fields in this protocol message type.""" |
745 extension_dict = descriptor.extensions_by_name | 743 extension_dict = descriptor.extensions_by_name |
746 for extension_name, extension_field in extension_dict.items(): | 744 for extension_name, extension_field in extension_dict.items(): |
747 constant_name = extension_name.upper() + "_FIELD_NUMBER" | 745 constant_name = extension_name.upper() + "_FIELD_NUMBER" |
748 setattr(cls, constant_name, extension_field.number) | 746 setattr(cls, constant_name, extension_field.number) |
749 | 747 |
| 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] |
750 | 755 |
751 def _AddStaticMethods(cls): | 756 def _AddStaticMethods(cls): |
752 # TODO(robinson): This probably needs to be thread-safe(?) | 757 # TODO(robinson): This probably needs to be thread-safe(?) |
753 def RegisterExtension(extension_handle): | 758 def RegisterExtension(extension_handle): |
754 extension_handle.containing_type = cls.DESCRIPTOR | 759 extension_handle.containing_type = cls.DESCRIPTOR |
| 760 # TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available. |
| 761 cls.DESCRIPTOR.file.pool.AddExtensionDescriptor(extension_handle) |
755 _AttachFieldHelpers(cls, extension_handle) | 762 _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 | |
776 cls.RegisterExtension = staticmethod(RegisterExtension) | 763 cls.RegisterExtension = staticmethod(RegisterExtension) |
777 | 764 |
778 def FromString(s): | 765 def FromString(s): |
779 message = cls() | 766 message = cls() |
780 message.MergeFromString(s) | 767 message.MergeFromString(s) |
781 return message | 768 return message |
782 cls.FromString = staticmethod(FromString) | 769 cls.FromString = staticmethod(FromString) |
783 | 770 |
784 | 771 |
785 def _IsPresent(item): | 772 def _IsPresent(item): |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
919 This internal method is differnt from public Any Unpack method which takes | 906 This internal method is differnt from public Any Unpack method which takes |
920 the target message as argument. _InternalUnpackAny method does not have | 907 the target message as argument. _InternalUnpackAny method does not have |
921 target message type and need to find the message type in descriptor pool. | 908 target message type and need to find the message type in descriptor pool. |
922 | 909 |
923 Args: | 910 Args: |
924 msg: An Any message to be unpacked. | 911 msg: An Any message to be unpacked. |
925 | 912 |
926 Returns: | 913 Returns: |
927 The unpacked message. | 914 The unpacked message. |
928 """ | 915 """ |
| 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 |
929 type_url = msg.type_url | 923 type_url = msg.type_url |
930 db = symbol_database.Default() | |
931 | 924 |
932 if not type_url: | 925 if not type_url: |
933 return None | 926 return None |
934 | 927 |
935 # TODO(haberman): For now we just strip the hostname. Better logic will be | 928 # TODO(haberman): For now we just strip the hostname. Better logic will be |
936 # required. | 929 # required. |
937 type_name = type_url.split("/")[-1] | 930 type_name = type_url.split('/')[-1] |
938 descriptor = db.pool.FindMessageTypeByName(type_name) | 931 descriptor = factory.pool.FindMessageTypeByName(type_name) |
939 | 932 |
940 if descriptor is None: | 933 if descriptor is None: |
941 return None | 934 return None |
942 | 935 |
943 message_class = db.GetPrototype(descriptor) | 936 message_class = factory.GetPrototype(descriptor) |
944 message = message_class() | 937 message = message_class() |
945 | 938 |
946 message.ParseFromString(msg.value) | 939 message.ParseFromString(msg.value) |
947 return message | 940 return message |
948 | 941 |
| 942 |
949 def _AddEqualsMethod(message_descriptor, cls): | 943 def _AddEqualsMethod(message_descriptor, cls): |
950 """Helper for _AddMessageMethods().""" | 944 """Helper for _AddMessageMethods().""" |
951 def __eq__(self, other): | 945 def __eq__(self, other): |
952 if (not isinstance(other, message_mod.Message) or | 946 if (not isinstance(other, message_mod.Message) or |
953 other.DESCRIPTOR != self.DESCRIPTOR): | 947 other.DESCRIPTOR != self.DESCRIPTOR): |
954 return False | 948 return False |
955 | 949 |
956 if self is other: | 950 if self is other: |
957 return True | 951 return True |
958 | 952 |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1216 | 1210 |
1217 | 1211 |
1218 def _AddMergeFromMethod(cls): | 1212 def _AddMergeFromMethod(cls): |
1219 LABEL_REPEATED = _FieldDescriptor.LABEL_REPEATED | 1213 LABEL_REPEATED = _FieldDescriptor.LABEL_REPEATED |
1220 CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE | 1214 CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE |
1221 | 1215 |
1222 def MergeFrom(self, msg): | 1216 def MergeFrom(self, msg): |
1223 if not isinstance(msg, cls): | 1217 if not isinstance(msg, cls): |
1224 raise TypeError( | 1218 raise TypeError( |
1225 "Parameter to MergeFrom() must be instance of same class: " | 1219 "Parameter to MergeFrom() must be instance of same class: " |
1226 "expected %s got %s." % (cls.__name__, type(msg).__name__)) | 1220 'expected %s got %s.' % (cls.__name__, msg.__class__.__name__)) |
1227 | 1221 |
1228 assert msg is not self | 1222 assert msg is not self |
1229 self._Modified() | 1223 self._Modified() |
1230 | 1224 |
1231 fields = self._fields | 1225 fields = self._fields |
1232 | 1226 |
1233 for field, value in msg._fields.items(): | 1227 for field, value in msg._fields.items(): |
1234 if field.label == LABEL_REPEATED: | 1228 if field.label == LABEL_REPEATED: |
1235 field_value = fields.get(field) | 1229 field_value = fields.get(field) |
1236 if field_value is None: | 1230 if field_value is None: |
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1539 def _FindExtensionByNumber(self, number): | 1533 def _FindExtensionByNumber(self, number): |
1540 """Tries to find a known extension with the field number. | 1534 """Tries to find a known extension with the field number. |
1541 | 1535 |
1542 Args: | 1536 Args: |
1543 number: Extension field number. | 1537 number: Extension field number. |
1544 | 1538 |
1545 Returns: | 1539 Returns: |
1546 Extension field descriptor. | 1540 Extension field descriptor. |
1547 """ | 1541 """ |
1548 return self._extended_message._extensions_by_number.get(number, None) | 1542 return self._extended_message._extensions_by_number.get(number, None) |
OLD | NEW |