| 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 |