Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(269)

Side by Side Diff: third_party/google-endpoints/apitools/base/protorpclite/messages.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 #
3 # Copyright 2010 Google Inc.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 # pylint: disable=too-many-lines
19
20 """Stand-alone implementation of in memory protocol messages.
21
22 Public Classes:
23 Enum: Represents an enumerated type.
24 Variant: Hint for wire format to determine how to serialize.
25 Message: Base class for user defined messages.
26 IntegerField: Field for integer values.
27 FloatField: Field for float values.
28 BooleanField: Field for boolean values.
29 BytesField: Field for binary string values.
30 StringField: Field for UTF-8 string values.
31 MessageField: Field for other message type values.
32 EnumField: Field for enumerated type values.
33
34 Public Exceptions (indentation indications class hierarchy):
35 EnumDefinitionError: Raised when enumeration is incorrectly defined.
36 FieldDefinitionError: Raised when field is incorrectly defined.
37 InvalidVariantError: Raised when variant is not compatible with field type.
38 InvalidDefaultError: Raised when default is not compatiable with field.
39 InvalidNumberError: Raised when field number is out of range or reserved.
40 MessageDefinitionError: Raised when message is incorrectly defined.
41 DuplicateNumberError: Raised when field has duplicate number with another.
42 ValidationError: Raised when a message or field is not valid.
43 DefinitionNotFoundError: Raised when definition not found.
44 """
45 import types
46 import weakref
47
48 import six
49
50 from apitools.base.protorpclite import util
51
52 __all__ = [
53 'MAX_ENUM_VALUE',
54 'MAX_FIELD_NUMBER',
55 'FIRST_RESERVED_FIELD_NUMBER',
56 'LAST_RESERVED_FIELD_NUMBER',
57
58 'Enum',
59 'Field',
60 'FieldList',
61 'Variant',
62 'Message',
63 'IntegerField',
64 'FloatField',
65 'BooleanField',
66 'BytesField',
67 'StringField',
68 'MessageField',
69 'EnumField',
70 'find_definition',
71
72 'Error',
73 'DecodeError',
74 'EncodeError',
75 'EnumDefinitionError',
76 'FieldDefinitionError',
77 'InvalidVariantError',
78 'InvalidDefaultError',
79 'InvalidNumberError',
80 'MessageDefinitionError',
81 'DuplicateNumberError',
82 'ValidationError',
83 'DefinitionNotFoundError',
84 ]
85
86 # pylint:disable=attribute-defined-outside-init
87 # pylint:disable=protected-access
88
89
90 # TODO(rafek): Add extended module test to ensure all exceptions
91 # in services extends Error.
92 Error = util.Error
93
94
95 class EnumDefinitionError(Error):
96 """Enumeration definition error."""
97
98
99 class FieldDefinitionError(Error):
100 """Field definition error."""
101
102
103 class InvalidVariantError(FieldDefinitionError):
104 """Invalid variant provided to field."""
105
106
107 class InvalidDefaultError(FieldDefinitionError):
108 """Invalid default provided to field."""
109
110
111 class InvalidNumberError(FieldDefinitionError):
112 """Invalid number provided to field."""
113
114
115 class MessageDefinitionError(Error):
116 """Message definition error."""
117
118
119 class DuplicateNumberError(Error):
120 """Duplicate number assigned to field."""
121
122
123 class DefinitionNotFoundError(Error):
124 """Raised when definition is not found."""
125
126
127 class DecodeError(Error):
128 """Error found decoding message from encoded form."""
129
130
131 class EncodeError(Error):
132 """Error found when encoding message."""
133
134
135 class ValidationError(Error):
136 """Invalid value for message error."""
137
138 def __str__(self):
139 """Prints string with field name if present on exception."""
140 return Error.__str__(self)
141
142
143 # Attributes that are reserved by a class definition that
144 # may not be used by either Enum or Message class definitions.
145 _RESERVED_ATTRIBUTE_NAMES = frozenset(
146 ['__module__', '__doc__', '__qualname__'])
147
148 _POST_INIT_FIELD_ATTRIBUTE_NAMES = frozenset(
149 ['name',
150 '_message_definition',
151 '_MessageField__type',
152 '_EnumField__type',
153 '_EnumField__resolved_default'])
154
155 _POST_INIT_ATTRIBUTE_NAMES = frozenset(
156 ['_message_definition'])
157
158 # Maximum enumeration value as defined by the protocol buffers standard.
159 # All enum values must be less than or equal to this value.
160 MAX_ENUM_VALUE = (2 ** 29) - 1
161
162 # Maximum field number as defined by the protocol buffers standard.
163 # All field numbers must be less than or equal to this value.
164 MAX_FIELD_NUMBER = (2 ** 29) - 1
165
166 # Field numbers between 19000 and 19999 inclusive are reserved by the
167 # protobuf protocol and may not be used by fields.
168 FIRST_RESERVED_FIELD_NUMBER = 19000
169 LAST_RESERVED_FIELD_NUMBER = 19999
170
171
172 class _DefinitionClass(type):
173 """Base meta-class used for definition meta-classes.
174
175 The Enum and Message definition classes share some basic functionality.
176 Both of these classes may be contained by a Message definition. After
177 initialization, neither class may have attributes changed
178 except for the protected _message_definition attribute, and that attribute
179 may change only once.
180 """
181
182 __initialized = False # pylint:disable=invalid-name
183
184 def __init__(cls, name, bases, dct):
185 """Constructor."""
186 type.__init__(cls, name, bases, dct)
187 # Base classes may never be initialized.
188 if cls.__bases__ != (object,):
189 cls.__initialized = True
190
191 def message_definition(cls):
192 """Get outer Message definition that contains this definition.
193
194 Returns:
195 Containing Message definition if definition is contained within one,
196 else None.
197 """
198 try:
199 return cls._message_definition()
200 except AttributeError:
201 return None
202
203 def __setattr__(cls, name, value):
204 """Overridden to avoid setting variables after init.
205
206 Setting attributes on a class must work during the period of
207 initialization to set the enumation value class variables and
208 build the name/number maps. Once __init__ has set the
209 __initialized flag to True prohibits setting any more values
210 on the class. The class is in effect frozen.
211
212 Args:
213 name: Name of value to set.
214 value: Value to set.
215
216 """
217 if cls.__initialized and name not in _POST_INIT_ATTRIBUTE_NAMES:
218 raise AttributeError('May not change values: %s' % name)
219 else:
220 type.__setattr__(cls, name, value)
221
222 def __delattr__(cls, name):
223 """Overridden so that cannot delete varaibles on definition classes."""
224 raise TypeError('May not delete attributes on definition class')
225
226 def definition_name(cls):
227 """Helper method for creating definition name.
228
229 Names will be generated to include the classes package name,
230 scope (if the class is nested in another definition) and class
231 name.
232
233 By default, the package name for a definition is derived from
234 its module name. However, this value can be overriden by
235 placing a 'package' attribute in the module that contains the
236 definition class. For example:
237
238 package = 'some.alternate.package'
239
240 class MyMessage(Message):
241 ...
242
243 >>> MyMessage.definition_name()
244 some.alternate.package.MyMessage
245
246 Returns:
247 Dot-separated fully qualified name of definition.
248
249 """
250 outer_definition_name = cls.outer_definition_name()
251 if outer_definition_name is None:
252 return six.text_type(cls.__name__)
253 else:
254 return u'%s.%s' % (outer_definition_name, cls.__name__)
255
256 def outer_definition_name(cls):
257 """Helper method for creating outer definition name.
258
259 Returns:
260 If definition is nested, will return the outer definitions
261 name, else the package name.
262
263 """
264 outer_definition = cls.message_definition()
265 if not outer_definition:
266 return util.get_package_for_module(cls.__module__)
267 else:
268 return outer_definition.definition_name()
269
270 def definition_package(cls):
271 """Helper method for creating creating the package of a definition.
272
273 Returns:
274 Name of package that definition belongs to.
275 """
276 outer_definition = cls.message_definition()
277 if not outer_definition:
278 return util.get_package_for_module(cls.__module__)
279 else:
280 return outer_definition.definition_package()
281
282
283 class _EnumClass(_DefinitionClass):
284 """Meta-class used for defining the Enum base class.
285
286 Meta-class enables very specific behavior for any defined Enum
287 class. All attributes defined on an Enum sub-class must be integers.
288 Each attribute defined on an Enum sub-class is translated
289 into an instance of that sub-class, with the name of the attribute
290 as its name, and the number provided as its value. It also ensures
291 that only one level of Enum class hierarchy is possible. In other
292 words it is not possible to delcare sub-classes of sub-classes of
293 Enum.
294
295 This class also defines some functions in order to restrict the
296 behavior of the Enum class and its sub-classes. It is not possible
297 to change the behavior of the Enum class in later classes since
298 any new classes may be defined with only integer values, and no methods.
299 """
300
301 def __init__(cls, name, bases, dct):
302 # Can only define one level of sub-classes below Enum.
303 if not (bases == (object,) or bases == (Enum,)):
304 raise EnumDefinitionError(
305 'Enum type %s may only inherit from Enum' % name)
306
307 cls.__by_number = {}
308 cls.__by_name = {}
309
310 # Enum base class does not need to be initialized or locked.
311 if bases != (object,):
312 # Replace integer with number.
313 for attribute, value in dct.items():
314
315 # Module will be in every enum class.
316 if attribute in _RESERVED_ATTRIBUTE_NAMES:
317 continue
318
319 # Reject anything that is not an int.
320 if not isinstance(value, six.integer_types):
321 raise EnumDefinitionError(
322 'May only use integers in Enum definitions. '
323 'Found: %s = %s' %
324 (attribute, value))
325
326 # Protocol buffer standard recommends non-negative values.
327 # Reject negative values.
328 if value < 0:
329 raise EnumDefinitionError(
330 'Must use non-negative enum values. Found: %s = %d' %
331 (attribute, value))
332
333 if value > MAX_ENUM_VALUE:
334 raise EnumDefinitionError(
335 'Must use enum values less than or equal %d. '
336 'Found: %s = %d' %
337 (MAX_ENUM_VALUE, attribute, value))
338
339 if value in cls.__by_number:
340 raise EnumDefinitionError(
341 'Value for %s = %d is already defined: %s' %
342 (attribute, value, cls.__by_number[value].name))
343
344 # Create enum instance and list in new Enum type.
345 instance = object.__new__(cls)
346 # pylint:disable=non-parent-init-called
347 cls.__init__(instance, attribute, value)
348 cls.__by_name[instance.name] = instance
349 cls.__by_number[instance.number] = instance
350 setattr(cls, attribute, instance)
351
352 _DefinitionClass.__init__(cls, name, bases, dct)
353
354 def __iter__(cls):
355 """Iterate over all values of enum.
356
357 Yields:
358 Enumeration instances of the Enum class in arbitrary order.
359 """
360 return iter(cls.__by_number.values())
361
362 def names(cls):
363 """Get all names for Enum.
364
365 Returns:
366 An iterator for names of the enumeration in arbitrary order.
367 """
368 return cls.__by_name.keys()
369
370 def numbers(cls):
371 """Get all numbers for Enum.
372
373 Returns:
374 An iterator for all numbers of the enumeration in arbitrary order.
375 """
376 return cls.__by_number.keys()
377
378 def lookup_by_name(cls, name):
379 """Look up Enum by name.
380
381 Args:
382 name: Name of enum to find.
383
384 Returns:
385 Enum sub-class instance of that value.
386 """
387 return cls.__by_name[name]
388
389 def lookup_by_number(cls, number):
390 """Look up Enum by number.
391
392 Args:
393 number: Number of enum to find.
394
395 Returns:
396 Enum sub-class instance of that value.
397 """
398 return cls.__by_number[number]
399
400 def __len__(cls):
401 return len(cls.__by_name)
402
403
404 class Enum(six.with_metaclass(_EnumClass, object)):
405 """Base class for all enumerated types."""
406
407 __slots__ = set(('name', 'number'))
408
409 def __new__(cls, index):
410 """Acts as look-up routine after class is initialized.
411
412 The purpose of overriding __new__ is to provide a way to treat
413 Enum subclasses as casting types, similar to how the int type
414 functions. A program can pass a string or an integer and this
415 method with "convert" that value in to an appropriate Enum instance.
416
417 Args:
418 index: Name or number to look up. During initialization
419 this is always the name of the new enum value.
420
421 Raises:
422 TypeError: When an inappropriate index value is passed provided.
423 """
424 # If is enum type of this class, return it.
425 if isinstance(index, cls):
426 return index
427
428 # If number, look up by number.
429 if isinstance(index, six.integer_types):
430 try:
431 return cls.lookup_by_number(index)
432 except KeyError:
433 pass
434
435 # If name, look up by name.
436 if isinstance(index, six.string_types):
437 try:
438 return cls.lookup_by_name(index)
439 except KeyError:
440 pass
441
442 raise TypeError('No such value for %s in Enum %s' %
443 (index, cls.__name__))
444
445 def __init__(self, name, number=None):
446 """Initialize new Enum instance.
447
448 Since this should only be called during class initialization any
449 calls that happen after the class is frozen raises an exception.
450 """
451 # Immediately return if __init__ was called after _Enum.__init__().
452 # It means that casting operator version of the class constructor
453 # is being used.
454 if getattr(type(self), '_DefinitionClass__initialized'):
455 return
456 object.__setattr__(self, 'name', name)
457 object.__setattr__(self, 'number', number)
458
459 def __setattr__(self, name, value):
460 raise TypeError('May not change enum values')
461
462 def __str__(self):
463 return self.name
464
465 def __int__(self):
466 return self.number
467
468 def __repr__(self):
469 return '%s(%s, %d)' % (type(self).__name__, self.name, self.number)
470
471 def __reduce__(self):
472 """Enable pickling.
473
474 Returns:
475 A 2-tuple containing the class and __new__ args to be used
476 for restoring a pickled instance.
477
478 """
479 return self.__class__, (self.number,)
480
481 def __cmp__(self, other):
482 """Order is by number."""
483 if isinstance(other, type(self)):
484 return cmp(self.number, other.number)
485 return NotImplemented
486
487 def __lt__(self, other):
488 """Order is by number."""
489 if isinstance(other, type(self)):
490 return self.number < other.number
491 return NotImplemented
492
493 def __le__(self, other):
494 """Order is by number."""
495 if isinstance(other, type(self)):
496 return self.number <= other.number
497 return NotImplemented
498
499 def __eq__(self, other):
500 """Order is by number."""
501 if isinstance(other, type(self)):
502 return self.number == other.number
503 return NotImplemented
504
505 def __ne__(self, other):
506 """Order is by number."""
507 if isinstance(other, type(self)):
508 return self.number != other.number
509 return NotImplemented
510
511 def __ge__(self, other):
512 """Order is by number."""
513 if isinstance(other, type(self)):
514 return self.number >= other.number
515 return NotImplemented
516
517 def __gt__(self, other):
518 """Order is by number."""
519 if isinstance(other, type(self)):
520 return self.number > other.number
521 return NotImplemented
522
523 def __hash__(self):
524 """Hash by number."""
525 return hash(self.number)
526
527 @classmethod
528 def to_dict(cls):
529 """Make dictionary version of enumerated class.
530
531 Dictionary created this way can be used with def_num.
532
533 Returns:
534 A dict (name) -> number
535 """
536 return dict((item.name, item.number) for item in iter(cls))
537
538 @staticmethod
539 def def_enum(dct, name):
540 """Define enum class from dictionary.
541
542 Args:
543 dct: Dictionary of enumerated values for type.
544 name: Name of enum.
545 """
546 return type(name, (Enum,), dct)
547
548
549 # TODO(rafek): Determine to what degree this enumeration should be compatible
550 # with FieldDescriptor.Type in https://github.com/google/protobuf.
551 class Variant(Enum):
552 """Wire format variant.
553
554 Used by the 'protobuf' wire format to determine how to transmit
555 a single piece of data. May be used by other formats.
556
557 See: http://code.google.com/apis/protocolbuffers/docs/encoding.html
558
559 Values:
560 DOUBLE: 64-bit floating point number.
561 FLOAT: 32-bit floating point number.
562 INT64: 64-bit signed integer.
563 UINT64: 64-bit unsigned integer.
564 INT32: 32-bit signed integer.
565 BOOL: Boolean value (True or False).
566 STRING: String of UTF-8 encoded text.
567 MESSAGE: Embedded message as byte string.
568 BYTES: String of 8-bit bytes.
569 UINT32: 32-bit unsigned integer.
570 ENUM: Enum value as integer.
571 SINT32: 32-bit signed integer. Uses "zig-zag" encoding.
572 SINT64: 64-bit signed integer. Uses "zig-zag" encoding.
573 """
574 DOUBLE = 1
575 FLOAT = 2
576 INT64 = 3
577 UINT64 = 4
578 INT32 = 5
579 BOOL = 8
580 STRING = 9
581 MESSAGE = 11
582 BYTES = 12
583 UINT32 = 13
584 ENUM = 14
585 SINT32 = 17
586 SINT64 = 18
587
588
589 class _MessageClass(_DefinitionClass):
590 """Meta-class used for defining the Message base class.
591
592 For more details about Message classes, see the Message class docstring.
593 Information contained there may help understanding this class.
594
595 Meta-class enables very specific behavior for any defined Message
596 class. All attributes defined on an Message sub-class must be
597 field instances, Enum class definitions or other Message class
598 definitions. Each field attribute defined on an Message sub-class
599 is added to the set of field definitions and the attribute is
600 translated in to a slot. It also ensures that only one level of
601 Message class hierarchy is possible. In other words it is not
602 possible to declare sub-classes of sub-classes of Message.
603
604 This class also defines some functions in order to restrict the
605 behavior of the Message class and its sub-classes. It is not
606 possible to change the behavior of the Message class in later
607 classes since any new classes may be defined with only field,
608 Enums and Messages, and no methods.
609
610 """
611
612 # pylint:disable=bad-mcs-classmethod-argument
613 def __new__(cls, name, bases, dct):
614 """Create new Message class instance.
615
616 The __new__ method of the _MessageClass type is overridden so as to
617 allow the translation of Field instances to slots.
618 """
619 by_number = {}
620 by_name = {}
621
622 variant_map = {} # pylint:disable=unused-variable
623
624 if bases != (object,):
625 # Can only define one level of sub-classes below Message.
626 if bases != (Message,):
627 raise MessageDefinitionError(
628 'Message types may only inherit from Message')
629
630 enums = []
631 messages = []
632 # Must not use iteritems because this loop will change the state of
633 # dct.
634 for key, field in dct.items():
635
636 if key in _RESERVED_ATTRIBUTE_NAMES:
637 continue
638
639 if isinstance(field, type) and issubclass(field, Enum):
640 enums.append(key)
641 continue
642
643 if (isinstance(field, type) and
644 issubclass(field, Message) and
645 field is not Message):
646 messages.append(key)
647 continue
648
649 # Reject anything that is not a field.
650 # pylint:disable=unidiomatic-typecheck
651 if type(field) is Field or not isinstance(field, Field):
652 raise MessageDefinitionError(
653 'May only use fields in message definitions. '
654 'Found: %s = %s' %
655 (key, field))
656
657 if field.number in by_number:
658 raise DuplicateNumberError(
659 'Field with number %d declared more than once in %s' %
660 (field.number, name))
661
662 field.name = key
663
664 # Place in name and number maps.
665 by_name[key] = field
666 by_number[field.number] = field
667
668 # Add enums if any exist.
669 if enums:
670 dct['__enums__'] = sorted(enums)
671
672 # Add messages if any exist.
673 if messages:
674 dct['__messages__'] = sorted(messages)
675
676 dct['_Message__by_number'] = by_number
677 dct['_Message__by_name'] = by_name
678
679 return _DefinitionClass.__new__(cls, name, bases, dct)
680
681 def __init__(cls, name, bases, dct):
682 """Initializer required to assign references to new class."""
683 if bases != (object,):
684 for v in dct.values():
685 if isinstance(v, _DefinitionClass) and v is not Message:
686 v._message_definition = weakref.ref(cls)
687
688 for field in cls.all_fields():
689 field._message_definition = weakref.ref(cls)
690
691 _DefinitionClass.__init__(cls, name, bases, dct)
692
693
694 class Message(six.with_metaclass(_MessageClass, object)):
695 """Base class for user defined message objects.
696
697 Used to define messages for efficient transmission across network or
698 process space. Messages are defined using the field classes (IntegerField,
699 FloatField, EnumField, etc.).
700
701 Messages are more restricted than normal classes in that they may
702 only contain field attributes and other Message and Enum
703 definitions. These restrictions are in place because the structure
704 of the Message class is intentended to itself be transmitted
705 across network or process space and used directly by clients or
706 even other servers. As such methods and non-field attributes could
707 not be transmitted with the structural information causing
708 discrepancies between different languages and implementations.
709
710 Initialization and validation:
711
712 A Message object is considered to be initialized if it has all required
713 fields and any nested messages are also initialized.
714
715 Calling 'check_initialized' will raise a ValidationException if it is not
716 initialized; 'is_initialized' returns a boolean value indicating if it is
717 valid.
718
719 Validation automatically occurs when Message objects are created
720 and populated. Validation that a given value will be compatible with
721 a field that it is assigned to can be done through the Field instances
722 validate() method. The validate method used on a message will check that
723 all values of a message and its sub-messages are valid. Assingning an
724 invalid value to a field will raise a ValidationException.
725
726 Example:
727
728 # Trade type.
729 class TradeType(Enum):
730 BUY = 1
731 SELL = 2
732 SHORT = 3
733 CALL = 4
734
735 class Lot(Message):
736 price = IntegerField(1, required=True)
737 quantity = IntegerField(2, required=True)
738
739 class Order(Message):
740 symbol = StringField(1, required=True)
741 total_quantity = IntegerField(2, required=True)
742 trade_type = EnumField(TradeType, 3, required=True)
743 lots = MessageField(Lot, 4, repeated=True)
744 limit = IntegerField(5)
745
746 order = Order(symbol='GOOG',
747 total_quantity=10,
748 trade_type=TradeType.BUY)
749
750 lot1 = Lot(price=304,
751 quantity=7)
752
753 lot2 = Lot(price = 305,
754 quantity=3)
755
756 order.lots = [lot1, lot2]
757
758 # Now object is initialized!
759 order.check_initialized()
760
761 """
762
763 def __init__(self, **kwargs):
764 """Initialize internal messages state.
765
766 Args:
767 A message can be initialized via the constructor by passing
768 in keyword arguments corresponding to fields. For example:
769
770 class Date(Message):
771 day = IntegerField(1)
772 month = IntegerField(2)
773 year = IntegerField(3)
774
775 Invoking:
776
777 date = Date(day=6, month=6, year=1911)
778
779 is the same as doing:
780
781 date = Date()
782 date.day = 6
783 date.month = 6
784 date.year = 1911
785
786 """
787 # Tag being an essential implementation detail must be private.
788 self.__tags = {}
789 self.__unrecognized_fields = {}
790
791 assigned = set()
792 for name, value in kwargs.items():
793 setattr(self, name, value)
794 assigned.add(name)
795
796 # initialize repeated fields.
797 for field in self.all_fields():
798 if field.repeated and field.name not in assigned:
799 setattr(self, field.name, [])
800
801 def check_initialized(self):
802 """Check class for initialization status.
803
804 Check that all required fields are initialized
805
806 Raises:
807 ValidationError: If message is not initialized.
808 """
809 for name, field in self.__by_name.items():
810 value = getattr(self, name)
811 if value is None:
812 if field.required:
813 raise ValidationError(
814 "Message %s is missing required field %s" %
815 (type(self).__name__, name))
816 else:
817 try:
818 if (isinstance(field, MessageField) and
819 issubclass(field.message_type, Message)):
820 if field.repeated:
821 for item in value:
822 item_message_value = field.value_to_message(
823 item)
824 item_message_value.check_initialized()
825 else:
826 message_value = field.value_to_message(value)
827 message_value.check_initialized()
828 except ValidationError as err:
829 if not hasattr(err, 'message_name'):
830 err.message_name = type(self).__name__
831 raise
832
833 def is_initialized(self):
834 """Get initialization status.
835
836 Returns:
837 True if message is valid, else False.
838 """
839 try:
840 self.check_initialized()
841 except ValidationError:
842 return False
843 else:
844 return True
845
846 @classmethod
847 def all_fields(cls):
848 """Get all field definition objects.
849
850 Ordering is arbitrary.
851
852 Returns:
853 Iterator over all values in arbitrary order.
854 """
855 return cls.__by_name.values()
856
857 @classmethod
858 def field_by_name(cls, name):
859 """Get field by name.
860
861 Returns:
862 Field object associated with name.
863
864 Raises:
865 KeyError if no field found by that name.
866 """
867 return cls.__by_name[name]
868
869 @classmethod
870 def field_by_number(cls, number):
871 """Get field by number.
872
873 Returns:
874 Field object associated with number.
875
876 Raises:
877 KeyError if no field found by that number.
878 """
879 return cls.__by_number[number]
880
881 def get_assigned_value(self, name):
882 """Get the assigned value of an attribute.
883
884 Get the underlying value of an attribute. If value has not
885 been set, will not return the default for the field.
886
887 Args:
888 name: Name of attribute to get.
889
890 Returns:
891 Value of attribute, None if it has not been set.
892
893 """
894 message_type = type(self)
895 try:
896 field = message_type.field_by_name(name)
897 except KeyError:
898 raise AttributeError('Message %s has no field %s' % (
899 message_type.__name__, name))
900 return self.__tags.get(field.number)
901
902 def reset(self, name):
903 """Reset assigned value for field.
904
905 Resetting a field will return it to its default value or None.
906
907 Args:
908 name: Name of field to reset.
909 """
910 message_type = type(self)
911 try:
912 field = message_type.field_by_name(name)
913 except KeyError:
914 if name not in message_type.__by_name:
915 raise AttributeError('Message %s has no field %s' % (
916 message_type.__name__, name))
917 if field.repeated:
918 self.__tags[field.number] = FieldList(field, [])
919 else:
920 self.__tags.pop(field.number, None)
921
922 def all_unrecognized_fields(self):
923 """Get the names of all unrecognized fields in this message."""
924 return list(self.__unrecognized_fields.keys())
925
926 def get_unrecognized_field_info(self, key, value_default=None,
927 variant_default=None):
928 """Get the value and variant of an unknown field in this message.
929
930 Args:
931 key: The name or number of the field to retrieve.
932 value_default: Value to be returned if the key isn't found.
933 variant_default: Value to be returned as variant if the key isn't
934 found.
935
936 Returns:
937 (value, variant), where value and variant are whatever was passed
938 to set_unrecognized_field.
939 """
940 value, variant = self.__unrecognized_fields.get(key, (value_default,
941 variant_default))
942 return value, variant
943
944 def set_unrecognized_field(self, key, value, variant):
945 """Set an unrecognized field, used when decoding a message.
946
947 Args:
948 key: The name or number used to refer to this unknown value.
949 value: The value of the field.
950 variant: Type information needed to interpret the value or re-encode
951 it.
952
953 Raises:
954 TypeError: If the variant is not an instance of messages.Variant.
955 """
956 if not isinstance(variant, Variant):
957 raise TypeError('Variant type %s is not valid.' % variant)
958 self.__unrecognized_fields[key] = value, variant
959
960 def __setattr__(self, name, value):
961 """Change set behavior for messages.
962
963 Messages may only be assigned values that are fields.
964
965 Does not try to validate field when set.
966
967 Args:
968 name: Name of field to assign to.
969 value: Value to assign to field.
970
971 Raises:
972 AttributeError when trying to assign value that is not a field.
973 """
974 if name in self.__by_name or name.startswith('_Message__'):
975 object.__setattr__(self, name, value)
976 else:
977 raise AttributeError("May not assign arbitrary value %s "
978 "to message %s" % (name, type(self).__name__))
979
980 def __repr__(self):
981 """Make string representation of message.
982
983 Example:
984
985 class MyMessage(messages.Message):
986 integer_value = messages.IntegerField(1)
987 string_value = messages.StringField(2)
988
989 my_message = MyMessage()
990 my_message.integer_value = 42
991 my_message.string_value = u'A string'
992
993 print my_message
994 >>> <MyMessage
995 ... integer_value: 42
996 ... string_value: u'A string'>
997
998 Returns:
999 String representation of message, including the values
1000 of all fields and repr of all sub-messages.
1001 """
1002 body = ['<', type(self).__name__]
1003 for field in sorted(self.all_fields(),
1004 key=lambda f: f.number):
1005 attribute = field.name
1006 value = self.get_assigned_value(field.name)
1007 if value is not None:
1008 body.append('\n %s: %s' % (attribute, repr(value)))
1009 body.append('>')
1010 return ''.join(body)
1011
1012 def __eq__(self, other):
1013 """Equality operator.
1014
1015 Does field by field comparison with other message. For
1016 equality, must be same type and values of all fields must be
1017 equal.
1018
1019 Messages not required to be initialized for comparison.
1020
1021 Does not attempt to determine equality for values that have
1022 default values that are not set. In other words:
1023
1024 class HasDefault(Message):
1025
1026 attr1 = StringField(1, default='default value')
1027
1028 message1 = HasDefault()
1029 message2 = HasDefault()
1030 message2.attr1 = 'default value'
1031
1032 message1 != message2
1033
1034 Does not compare unknown values.
1035
1036 Args:
1037 other: Other message to compare with.
1038 """
1039 # TODO(rafek): Implement "equivalent" which does comparisons
1040 # taking default values in to consideration.
1041 if self is other:
1042 return True
1043
1044 if type(self) is not type(other):
1045 return False
1046
1047 return self.__tags == other.__tags
1048
1049 def __ne__(self, other):
1050 """Not equals operator.
1051
1052 Does field by field comparison with other message. For
1053 non-equality, must be different type or any value of a field must be
1054 non-equal to the same field in the other instance.
1055
1056 Messages not required to be initialized for comparison.
1057
1058 Args:
1059 other: Other message to compare with.
1060 """
1061 return not self.__eq__(other)
1062
1063
1064 class FieldList(list):
1065 """List implementation that validates field values.
1066
1067 This list implementation overrides all methods that add values in
1068 to a list in order to validate those new elements. Attempting to
1069 add or set list values that are not of the correct type will raise
1070 ValidationError.
1071
1072 """
1073
1074 def __init__(self, field_instance, sequence):
1075 """Constructor.
1076
1077 Args:
1078 field_instance: Instance of field that validates the list.
1079 sequence: List or tuple to construct list from.
1080 """
1081 if not field_instance.repeated:
1082 raise FieldDefinitionError(
1083 'FieldList may only accept repeated fields')
1084 self.__field = field_instance
1085 self.__field.validate(sequence)
1086 list.__init__(self, sequence)
1087
1088 def __getstate__(self):
1089 """Enable pickling.
1090
1091 The assigned field instance can't be pickled if it belongs to
1092 a Message definition (message_definition uses a weakref), so
1093 the Message class and field number are returned in that case.
1094
1095 Returns:
1096 A 3-tuple containing:
1097 - The field instance, or None if it belongs to a Message class.
1098 - The Message class that the field instance belongs to, or None.
1099 - The field instance number of the Message class it belongs to, or
1100 None.
1101
1102 """
1103 message_class = self.__field.message_definition()
1104 if message_class is None:
1105 return self.__field, None, None
1106 else:
1107 return None, message_class, self.__field.number
1108
1109 def __setstate__(self, state):
1110 """Enable unpickling.
1111
1112 Args:
1113 state: A 3-tuple containing:
1114 - The field instance, or None if it belongs to a Message class.
1115 - The Message class that the field instance belongs to, or None.
1116 - The field instance number of the Message class it belongs to, or
1117 None.
1118 """
1119 field_instance, message_class, number = state
1120 if field_instance is None:
1121 self.__field = message_class.field_by_number(number)
1122 else:
1123 self.__field = field_instance
1124
1125 @property
1126 def field(self):
1127 """Field that validates list."""
1128 return self.__field
1129
1130 def __setslice__(self, i, j, sequence):
1131 """Validate slice assignment to list."""
1132 self.__field.validate(sequence)
1133 list.__setslice__(self, i, j, sequence)
1134
1135 def __setitem__(self, index, value):
1136 """Validate item assignment to list."""
1137 if isinstance(index, slice):
1138 self.__field.validate(value)
1139 else:
1140 self.__field.validate_element(value)
1141 list.__setitem__(self, index, value)
1142
1143 def append(self, value):
1144 """Validate item appending to list."""
1145 self.__field.validate_element(value)
1146 return list.append(self, value)
1147
1148 def extend(self, sequence):
1149 """Validate extension of list."""
1150 self.__field.validate(sequence)
1151 return list.extend(self, sequence)
1152
1153 def insert(self, index, value):
1154 """Validate item insertion to list."""
1155 self.__field.validate_element(value)
1156 return list.insert(self, index, value)
1157
1158
1159 class _FieldMeta(type):
1160
1161 def __init__(cls, name, bases, dct):
1162 getattr(cls, '_Field__variant_to_type').update(
1163 (variant, cls) for variant in dct.get('VARIANTS', []))
1164 type.__init__(cls, name, bases, dct)
1165
1166
1167 # TODO(rafek): Prevent additional field subclasses.
1168 class Field(six.with_metaclass(_FieldMeta, object)):
1169
1170 __initialized = False # pylint:disable=invalid-name
1171 __variant_to_type = {} # pylint:disable=invalid-name
1172
1173 # TODO(craigcitro): Remove this alias.
1174 #
1175 # We add an alias here for backwards compatibility; note that in
1176 # python3, this attribute will silently be ignored.
1177 __metaclass__ = _FieldMeta
1178
1179 @util.positional(2)
1180 def __init__(self,
1181 number,
1182 required=False,
1183 repeated=False,
1184 variant=None,
1185 default=None):
1186 """Constructor.
1187
1188 The required and repeated parameters are mutually exclusive.
1189 Setting both to True will raise a FieldDefinitionError.
1190
1191 Sub-class Attributes:
1192 Each sub-class of Field must define the following:
1193 VARIANTS: Set of variant types accepted by that field.
1194 DEFAULT_VARIANT: Default variant type if not specified in
1195 constructor.
1196
1197 Args:
1198 number: Number of field. Must be unique per message class.
1199 required: Whether or not field is required. Mutually exclusive with
1200 'repeated'.
1201 repeated: Whether or not field is repeated. Mutually exclusive with
1202 'required'.
1203 variant: Wire-format variant hint.
1204 default: Default value for field if not found in stream.
1205
1206 Raises:
1207 InvalidVariantError when invalid variant for field is provided.
1208 InvalidDefaultError when invalid default for field is provided.
1209 FieldDefinitionError when invalid number provided or mutually
1210 exclusive fields are used.
1211 InvalidNumberError when the field number is out of range or reserved.
1212
1213 """
1214 if not isinstance(number, int) or not 1 <= number <= MAX_FIELD_NUMBER:
1215 raise InvalidNumberError(
1216 'Invalid number for field: %s\n'
1217 'Number must be 1 or greater and %d or less' %
1218 (number, MAX_FIELD_NUMBER))
1219
1220 if FIRST_RESERVED_FIELD_NUMBER <= number <= LAST_RESERVED_FIELD_NUMBER:
1221 raise InvalidNumberError('Tag number %d is a reserved number.\n'
1222 'Numbers %d to %d are reserved' %
1223 (number, FIRST_RESERVED_FIELD_NUMBER,
1224 LAST_RESERVED_FIELD_NUMBER))
1225
1226 if repeated and required:
1227 raise FieldDefinitionError('Cannot set both repeated and required')
1228
1229 if variant is None:
1230 variant = self.DEFAULT_VARIANT
1231
1232 if repeated and default is not None:
1233 raise FieldDefinitionError('Repeated fields may not have defaults')
1234
1235 if variant not in self.VARIANTS:
1236 raise InvalidVariantError(
1237 'Invalid variant: %s\nValid variants for %s are %r' %
1238 (variant, type(self).__name__, sorted(self.VARIANTS)))
1239
1240 self.number = number
1241 self.required = required
1242 self.repeated = repeated
1243 self.variant = variant
1244
1245 if default is not None:
1246 try:
1247 self.validate_default(default)
1248 except ValidationError as err:
1249 try:
1250 name = self.name
1251 except AttributeError:
1252 # For when raising error before name initialization.
1253 raise InvalidDefaultError(
1254 'Invalid default value for %s: %r: %s' %
1255 (self.__class__.__name__, default, err))
1256 else:
1257 raise InvalidDefaultError(
1258 'Invalid default value for field %s: '
1259 '%r: %s' % (name, default, err))
1260
1261 self.__default = default
1262 self.__initialized = True
1263
1264 def __setattr__(self, name, value):
1265 """Setter overidden to prevent assignment to fields after creation.
1266
1267 Args:
1268 name: Name of attribute to set.
1269 value: Value to assign.
1270 """
1271 # Special case post-init names. They need to be set after constructor.
1272 if name in _POST_INIT_FIELD_ATTRIBUTE_NAMES:
1273 object.__setattr__(self, name, value)
1274 return
1275
1276 # All other attributes must be set before __initialized.
1277 if not self.__initialized:
1278 # Not initialized yet, allow assignment.
1279 object.__setattr__(self, name, value)
1280 else:
1281 raise AttributeError('Field objects are read-only')
1282
1283 def __set__(self, message_instance, value):
1284 """Set value on message.
1285
1286 Args:
1287 message_instance: Message instance to set value on.
1288 value: Value to set on message.
1289 """
1290 # Reaches in to message instance directly to assign to private tags.
1291 if value is None:
1292 if self.repeated:
1293 raise ValidationError(
1294 'May not assign None to repeated field %s' % self.name)
1295 else:
1296 message_instance._Message__tags.pop(self.number, None)
1297 else:
1298 if self.repeated:
1299 value = FieldList(self, value)
1300 else:
1301 value = ( # pylint: disable=redefined-variable-type
1302 self.validate(value))
1303 message_instance._Message__tags[self.number] = value
1304
1305 def __get__(self, message_instance, message_class):
1306 if message_instance is None:
1307 return self
1308
1309 result = message_instance._Message__tags.get(self.number)
1310 if result is None:
1311 return self.default
1312 else:
1313 return result
1314
1315 def validate_element(self, value):
1316 """Validate single element of field.
1317
1318 This is different from validate in that it is used on individual
1319 values of repeated fields.
1320
1321 Args:
1322 value: Value to validate.
1323
1324 Returns:
1325 The value casted in the expected type.
1326
1327 Raises:
1328 ValidationError if value is not expected type.
1329 """
1330 if not isinstance(value, self.type):
1331
1332 # Authorize int values as float.
1333 if isinstance(value, six.integer_types) and self.type == float:
1334 return float(value)
1335
1336 if value is None:
1337 if self.required:
1338 raise ValidationError('Required field is missing')
1339 else:
1340 try:
1341 name = self.name
1342 except AttributeError:
1343 raise ValidationError('Expected type %s for %s, '
1344 'found %s (type %s)' %
1345 (self.type, self.__class__.__name__,
1346 value, type(value)))
1347 else:
1348 raise ValidationError(
1349 'Expected type %s for field %s, found %s (type %s)' %
1350 (self.type, name, value, type(value)))
1351 return value
1352
1353 def __validate(self, value, validate_element):
1354 """Internal validation function.
1355
1356 Validate an internal value using a function to validate
1357 individual elements.
1358
1359 Args:
1360 value: Value to validate.
1361 validate_element: Function to use to validate individual elements.
1362
1363 Raises:
1364 ValidationError if value is not expected type.
1365
1366 """
1367 if not self.repeated:
1368 return validate_element(value)
1369 else:
1370 # Must be a list or tuple, may not be a string.
1371 if isinstance(value, (list, tuple)):
1372 result = []
1373 for element in value:
1374 if element is None:
1375 try:
1376 name = self.name
1377 except AttributeError:
1378 raise ValidationError(
1379 'Repeated values for %s '
1380 'may not be None' % self.__class__.__name__)
1381 else:
1382 raise ValidationError(
1383 'Repeated values for field %s '
1384 'may not be None' % name)
1385 result.append(validate_element(element))
1386 return result
1387 elif value is not None:
1388 try:
1389 name = self.name
1390 except AttributeError:
1391 raise ValidationError('%s is repeated. Found: %s' % (
1392 self.__class__.__name__, value))
1393 else:
1394 raise ValidationError(
1395 'Field %s is repeated. Found: %s' % (name, value))
1396 return value
1397
1398 def validate(self, value):
1399 """Validate value assigned to field.
1400
1401 Args:
1402 value: Value to validate.
1403
1404 Returns:
1405 the value in casted in the correct type.
1406
1407 Raises:
1408 ValidationError if value is not expected type.
1409 """
1410 return self.__validate(value, self.validate_element)
1411
1412 def validate_default_element(self, value):
1413 """Validate value as assigned to field default field.
1414
1415 Some fields may allow for delayed resolution of default types
1416 necessary in the case of circular definition references. In
1417 this case, the default value might be a place holder that is
1418 resolved when needed after all the message classes are
1419 defined.
1420
1421 Args:
1422 value: Default value to validate.
1423
1424 Returns:
1425 the value in casted in the correct type.
1426
1427 Raises:
1428 ValidationError if value is not expected type.
1429
1430 """
1431 return self.validate_element(value)
1432
1433 def validate_default(self, value):
1434 """Validate default value assigned to field.
1435
1436 Args:
1437 value: Value to validate.
1438
1439 Returns:
1440 the value in casted in the correct type.
1441
1442 Raises:
1443 ValidationError if value is not expected type.
1444 """
1445 return self.__validate(value, self.validate_default_element)
1446
1447 def message_definition(self):
1448 """Get Message definition that contains this Field definition.
1449
1450 Returns:
1451 Containing Message definition for Field. Will return None if
1452 for some reason Field is defined outside of a Message class.
1453
1454 """
1455 try:
1456 return self._message_definition()
1457 except AttributeError:
1458 return None
1459
1460 @property
1461 def default(self):
1462 """Get default value for field."""
1463 return self.__default
1464
1465 @classmethod
1466 def lookup_field_type_by_variant(cls, variant):
1467 return cls.__variant_to_type[variant]
1468
1469
1470 class IntegerField(Field):
1471 """Field definition for integer values."""
1472
1473 VARIANTS = frozenset([
1474 Variant.INT32,
1475 Variant.INT64,
1476 Variant.UINT32,
1477 Variant.UINT64,
1478 Variant.SINT32,
1479 Variant.SINT64,
1480 ])
1481
1482 DEFAULT_VARIANT = Variant.INT64
1483
1484 type = six.integer_types
1485
1486
1487 class FloatField(Field):
1488 """Field definition for float values."""
1489
1490 VARIANTS = frozenset([
1491 Variant.FLOAT,
1492 Variant.DOUBLE,
1493 ])
1494
1495 DEFAULT_VARIANT = Variant.DOUBLE
1496
1497 type = float
1498
1499
1500 class BooleanField(Field):
1501 """Field definition for boolean values."""
1502
1503 VARIANTS = frozenset([Variant.BOOL])
1504
1505 DEFAULT_VARIANT = Variant.BOOL
1506
1507 type = bool
1508
1509
1510 class BytesField(Field):
1511 """Field definition for byte string values."""
1512
1513 VARIANTS = frozenset([Variant.BYTES])
1514
1515 DEFAULT_VARIANT = Variant.BYTES
1516
1517 type = bytes
1518
1519
1520 class StringField(Field):
1521 """Field definition for unicode string values."""
1522
1523 VARIANTS = frozenset([Variant.STRING])
1524
1525 DEFAULT_VARIANT = Variant.STRING
1526
1527 type = six.text_type
1528
1529 def validate_element(self, value):
1530 """Validate StringField allowing for str and unicode.
1531
1532 Raises:
1533 ValidationError if a str value is not 7-bit ascii.
1534 """
1535 # If value is str is it considered valid. Satisfies "required=True".
1536 if isinstance(value, bytes):
1537 try:
1538 six.text_type(value, 'ascii')
1539 except UnicodeDecodeError as err:
1540 try:
1541 _ = self.name
1542 except AttributeError:
1543 validation_error = ValidationError(
1544 'Field encountered non-ASCII string %r: %s' % (value,
1545 err))
1546 else:
1547 validation_error = ValidationError(
1548 'Field %s encountered non-ASCII string %r: %s' % (
1549 self.name, value, err))
1550 validation_error.field_name = self.name
1551 raise validation_error
1552 else:
1553 return super(StringField, self).validate_element(value)
1554 return value
1555
1556
1557 class MessageField(Field):
1558 """Field definition for sub-message values.
1559
1560 Message fields contain instance of other messages. Instances stored
1561 on messages stored on message fields are considered to be owned by
1562 the containing message instance and should not be shared between
1563 owning instances.
1564
1565 Message fields must be defined to reference a single type of message.
1566 Normally message field are defined by passing the referenced message
1567 class in to the constructor.
1568
1569 It is possible to define a message field for a type that does not
1570 yet exist by passing the name of the message in to the constructor
1571 instead of a message class. Resolution of the actual type of the
1572 message is deferred until it is needed, for example, during
1573 message verification. Names provided to the constructor must refer
1574 to a class within the same python module as the class that is
1575 using it. Names refer to messages relative to the containing
1576 messages scope. For example, the two fields of OuterMessage refer
1577 to the same message type:
1578
1579 class Outer(Message):
1580
1581 inner_relative = MessageField('Inner', 1)
1582 inner_absolute = MessageField('Outer.Inner', 2)
1583
1584 class Inner(Message):
1585 ...
1586
1587 When resolving an actual type, MessageField will traverse the
1588 entire scope of nested messages to match a message name. This
1589 makes it easy for siblings to reference siblings:
1590
1591 class Outer(Message):
1592
1593 class Inner(Message):
1594
1595 sibling = MessageField('Sibling', 1)
1596
1597 class Sibling(Message):
1598 ...
1599
1600 """
1601
1602 VARIANTS = frozenset([Variant.MESSAGE])
1603
1604 DEFAULT_VARIANT = Variant.MESSAGE
1605
1606 @util.positional(3)
1607 def __init__(self,
1608 message_type,
1609 number,
1610 required=False,
1611 repeated=False,
1612 variant=None):
1613 """Constructor.
1614
1615 Args:
1616 message_type: Message type for field. Must be subclass of Message.
1617 number: Number of field. Must be unique per message class.
1618 required: Whether or not field is required. Mutually exclusive to
1619 'repeated'.
1620 repeated: Whether or not field is repeated. Mutually exclusive to
1621 'required'.
1622 variant: Wire-format variant hint.
1623
1624 Raises:
1625 FieldDefinitionError when invalid message_type is provided.
1626 """
1627 valid_type = (isinstance(message_type, six.string_types) or
1628 (message_type is not Message and
1629 isinstance(message_type, type) and
1630 issubclass(message_type, Message)))
1631
1632 if not valid_type:
1633 raise FieldDefinitionError(
1634 'Invalid message class: %s' % message_type)
1635
1636 if isinstance(message_type, six.string_types):
1637 self.__type_name = message_type
1638 self.__type = None
1639 else:
1640 self.__type = message_type
1641
1642 super(MessageField, self).__init__(number,
1643 required=required,
1644 repeated=repeated,
1645 variant=variant)
1646
1647 def __set__(self, message_instance, value):
1648 """Set value on message.
1649
1650 Args:
1651 message_instance: Message instance to set value on.
1652 value: Value to set on message.
1653 """
1654 t = self.type
1655 if isinstance(t, type) and issubclass(t, Message):
1656 if self.repeated:
1657 if value and isinstance(value, (list, tuple)):
1658 value = [(t(**v) if isinstance(v, dict) else v)
1659 for v in value]
1660 elif isinstance(value, dict):
1661 value = t(**value)
1662 super(MessageField, self).__set__(message_instance, value)
1663
1664 @property
1665 def type(self):
1666 """Message type used for field."""
1667 if self.__type is None:
1668 message_type = find_definition(
1669 self.__type_name, self.message_definition())
1670 if not (message_type is not Message and
1671 isinstance(message_type, type) and
1672 issubclass(message_type, Message)):
1673 raise FieldDefinitionError(
1674 'Invalid message class: %s' % message_type)
1675 self.__type = message_type
1676 return self.__type
1677
1678 @property
1679 def message_type(self):
1680 """Underlying message type used for serialization.
1681
1682 Will always be a sub-class of Message. This is different from type
1683 which represents the python value that message_type is mapped to for
1684 use by the user.
1685 """
1686 return self.type
1687
1688 def value_from_message(self, message):
1689 """Convert a message to a value instance.
1690
1691 Used by deserializers to convert from underlying messages to
1692 value of expected user type.
1693
1694 Args:
1695 message: A message instance of type self.message_type.
1696
1697 Returns:
1698 Value of self.message_type.
1699 """
1700 if not isinstance(message, self.message_type):
1701 raise DecodeError('Expected type %s, got %s: %r' %
1702 (self.message_type.__name__,
1703 type(message).__name__,
1704 message))
1705 return message
1706
1707 def value_to_message(self, value):
1708 """Convert a value instance to a message.
1709
1710 Used by serializers to convert Python user types to underlying
1711 messages for transmission.
1712
1713 Args:
1714 value: A value of type self.type.
1715
1716 Returns:
1717 An instance of type self.message_type.
1718 """
1719 if not isinstance(value, self.type):
1720 raise EncodeError('Expected type %s, got %s: %r' %
1721 (self.type.__name__,
1722 type(value).__name__,
1723 value))
1724 return value
1725
1726
1727 class EnumField(Field):
1728 """Field definition for enum values.
1729
1730 Enum fields may have default values that are delayed until the
1731 associated enum type is resolved. This is necessary to support
1732 certain circular references.
1733
1734 For example:
1735
1736 class Message1(Message):
1737
1738 class Color(Enum):
1739
1740 RED = 1
1741 GREEN = 2
1742 BLUE = 3
1743
1744 # This field default value will be validated when default is accessed.
1745 animal = EnumField('Message2.Animal', 1, default='HORSE')
1746
1747 class Message2(Message):
1748
1749 class Animal(Enum):
1750
1751 DOG = 1
1752 CAT = 2
1753 HORSE = 3
1754
1755 # This fields default value will be validated right away since Color
1756 # is already fully resolved.
1757 color = EnumField(Message1.Color, 1, default='RED')
1758 """
1759
1760 VARIANTS = frozenset([Variant.ENUM])
1761
1762 DEFAULT_VARIANT = Variant.ENUM
1763
1764 def __init__(self, enum_type, number, **kwargs):
1765 """Constructor.
1766
1767 Args:
1768 enum_type: Enum type for field. Must be subclass of Enum.
1769 number: Number of field. Must be unique per message class.
1770 required: Whether or not field is required. Mutually exclusive to
1771 'repeated'.
1772 repeated: Whether or not field is repeated. Mutually exclusive to
1773 'required'.
1774 variant: Wire-format variant hint.
1775 default: Default value for field if not found in stream.
1776
1777 Raises:
1778 FieldDefinitionError when invalid enum_type is provided.
1779 """
1780 valid_type = (isinstance(enum_type, six.string_types) or
1781 (enum_type is not Enum and
1782 isinstance(enum_type, type) and
1783 issubclass(enum_type, Enum)))
1784
1785 if not valid_type:
1786 raise FieldDefinitionError('Invalid enum type: %s' % enum_type)
1787
1788 if isinstance(enum_type, six.string_types):
1789 self.__type_name = enum_type
1790 self.__type = None
1791 else:
1792 self.__type = enum_type
1793
1794 super(EnumField, self).__init__(number, **kwargs)
1795
1796 def validate_default_element(self, value):
1797 """Validate default element of Enum field.
1798
1799 Enum fields allow for delayed resolution of default values
1800 when the type of the field has not been resolved. The default
1801 value of a field may be a string or an integer. If the Enum
1802 type of the field has been resolved, the default value is
1803 validated against that type.
1804
1805 Args:
1806 value: Value to validate.
1807
1808 Raises:
1809 ValidationError if value is not expected message type.
1810
1811 """
1812 if isinstance(value, (six.string_types, six.integer_types)):
1813 # Validation of the value does not happen for delayed resolution
1814 # enumerated types. Ignore if type is not yet resolved.
1815 if self.__type:
1816 self.__type(value)
1817 return value
1818
1819 return super(EnumField, self).validate_default_element(value)
1820
1821 @property
1822 def type(self):
1823 """Enum type used for field."""
1824 if self.__type is None:
1825 found_type = find_definition(
1826 self.__type_name, self.message_definition())
1827 if not (found_type is not Enum and
1828 isinstance(found_type, type) and
1829 issubclass(found_type, Enum)):
1830 raise FieldDefinitionError(
1831 'Invalid enum type: %s' % found_type)
1832
1833 self.__type = found_type
1834 return self.__type
1835
1836 @property
1837 def default(self):
1838 """Default for enum field.
1839
1840 Will cause resolution of Enum type and unresolved default value.
1841 """
1842 try:
1843 return self.__resolved_default
1844 except AttributeError:
1845 resolved_default = super(EnumField, self).default
1846 if isinstance(resolved_default, (six.string_types,
1847 six.integer_types)):
1848 # pylint:disable=not-callable
1849 resolved_default = self.type(resolved_default)
1850 self.__resolved_default = resolved_default
1851 return self.__resolved_default
1852
1853
1854 @util.positional(2)
1855 def find_definition(name, relative_to=None, importer=__import__):
1856 """Find definition by name in module-space.
1857
1858 The find algorthm will look for definitions by name relative to a
1859 message definition or by fully qualfied name. If no definition is
1860 found relative to the relative_to parameter it will do the same
1861 search against the container of relative_to. If relative_to is a
1862 nested Message, it will search its message_definition(). If that
1863 message has no message_definition() it will search its module. If
1864 relative_to is a module, it will attempt to look for the
1865 containing module and search relative to it. If the module is a
1866 top-level module, it will look for the a message using a fully
1867 qualified name. If no message is found then, the search fails and
1868 DefinitionNotFoundError is raised.
1869
1870 For example, when looking for any definition 'foo.bar.ADefinition'
1871 relative to an actual message definition abc.xyz.SomeMessage:
1872
1873 find_definition('foo.bar.ADefinition', SomeMessage)
1874
1875 It is like looking for the following fully qualified names:
1876
1877 abc.xyz.SomeMessage. foo.bar.ADefinition
1878 abc.xyz. foo.bar.ADefinition
1879 abc. foo.bar.ADefinition
1880 foo.bar.ADefinition
1881
1882 When resolving the name relative to Message definitions and modules, the
1883 algorithm searches any Messages or sub-modules found in its path.
1884 Non-Message values are not searched.
1885
1886 A name that begins with '.' is considered to be a fully qualified
1887 name. The name is always searched for from the topmost package.
1888 For example, assume two message types:
1889
1890 abc.xyz.SomeMessage
1891 xyz.SomeMessage
1892
1893 Searching for '.xyz.SomeMessage' relative to 'abc' will resolve to
1894 'xyz.SomeMessage' and not 'abc.xyz.SomeMessage'. For this kind of name,
1895 the relative_to parameter is effectively ignored and always set to None.
1896
1897 For more information about package name resolution, please see:
1898
1899 http://code.google.com/apis/protocolbuffers/docs/proto.html#packages
1900
1901 Args:
1902 name: Name of definition to find. May be fully qualified or relative
1903 name.
1904 relative_to: Search for definition relative to message definition or
1905 module. None will cause a fully qualified name search.
1906 importer: Import function to use for resolving modules.
1907
1908 Returns:
1909 Enum or Message class definition associated with name.
1910
1911 Raises:
1912 DefinitionNotFoundError if no definition is found in any search path.
1913
1914 """
1915 # Check parameters.
1916 if not (relative_to is None or
1917 isinstance(relative_to, types.ModuleType) or
1918 isinstance(relative_to, type) and
1919 issubclass(relative_to, Message)):
1920 raise TypeError(
1921 'relative_to must be None, Message definition or module.'
1922 ' Found: %s' % relative_to)
1923
1924 name_path = name.split('.')
1925
1926 # Handle absolute path reference.
1927 if not name_path[0]:
1928 relative_to = None
1929 name_path = name_path[1:]
1930
1931 def search_path():
1932 """Performs a single iteration searching the path from relative_to.
1933
1934 This is the function that searches up the path from a relative object.
1935
1936 fully.qualified.object . relative.or.nested.Definition
1937 ---------------------------->
1938 ^
1939 |
1940 this part of search --+
1941
1942 Returns:
1943 Message or Enum at the end of name_path, else None.
1944 """
1945 next_part = relative_to
1946 for node in name_path:
1947 # Look for attribute first.
1948 attribute = getattr(next_part, node, None)
1949
1950 if attribute is not None:
1951 next_part = attribute
1952 else:
1953 # If module, look for sub-module.
1954 if (next_part is None or
1955 isinstance(next_part, types.ModuleType)):
1956 if next_part is None:
1957 module_name = node
1958 else:
1959 module_name = '%s.%s' % (next_part.__name__, node)
1960
1961 try:
1962 fromitem = module_name.split('.')[-1]
1963 next_part = importer(module_name, '', '',
1964 [str(fromitem)])
1965 except ImportError:
1966 return None
1967 else:
1968 return None
1969
1970 if not isinstance(next_part, types.ModuleType):
1971 if not (isinstance(next_part, type) and
1972 issubclass(next_part, (Message, Enum))):
1973 return None
1974
1975 return next_part
1976
1977 while True:
1978 found = search_path()
1979 if isinstance(found, type) and issubclass(found, (Enum, Message)):
1980 return found
1981 else:
1982 # Find next relative_to to search against.
1983 #
1984 # fully.qualified.object . relative.or.nested.Definition
1985 # <---------------------
1986 # ^
1987 # |
1988 # does this part of search
1989 if relative_to is None:
1990 # Fully qualified search was done. Nothing found. Fail.
1991 raise DefinitionNotFoundError(
1992 'Could not find definition for %s' % name)
1993 else:
1994 if isinstance(relative_to, types.ModuleType):
1995 # Find parent module.
1996 module_path = relative_to.__name__.split('.')[:-1]
1997 if not module_path:
1998 relative_to = None
1999 else:
2000 # Should not raise ImportError. If it does...
2001 # weird and unexpected. Propagate.
2002 relative_to = importer(
2003 '.'.join(module_path), '', '', [module_path[-1]])
2004 elif (isinstance(relative_to, type) and
2005 issubclass(relative_to, Message)):
2006 parent = relative_to.message_definition()
2007 if parent is None:
2008 last_module_name = relative_to.__module__.split(
2009 '.')[-1]
2010 relative_to = importer(
2011 relative_to.__module__, '', '', [last_module_name])
2012 else:
2013 relative_to = parent
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698