Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/google/protobuf/internal/python_message.py: 11%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

828 statements  

1# Protocol Buffers - Google's data interchange format 

2# Copyright 2008 Google Inc. All rights reserved. 

3# 

4# Use of this source code is governed by a BSD-style 

5# license that can be found in the LICENSE file or at 

6# https://developers.google.com/open-source/licenses/bsd 

7 

8# This code is meant to work on Python 2.4 and above only. 

9# 

10# TODO: Helpers for verbose, common checks like seeing if a 

11# descriptor's cpp_type is CPPTYPE_MESSAGE. 

12"""Contains a metaclass and helper functions used to create 

13 

14protocol message classes from Descriptor objects at runtime. 

15 

16Recall that a metaclass is the "type" of a class. 

17(A class is to a metaclass what an instance is to a class.) 

18 

19In this case, we use the GeneratedProtocolMessageType metaclass 

20to inject all the useful functionality into the classes 

21output by the protocol compiler at compile-time. 

22 

23The upshot of all this is that the real implementation 

24details for ALL pure-Python protocol buffers are *here in 

25this file*. 

26""" 

27 

28__author__ = 'robinson@google.com (Will Robinson)' 

29 

30import datetime 

31from io import BytesIO 

32import math 

33import struct 

34import sys 

35import warnings 

36import weakref 

37 

38from google.protobuf import descriptor as descriptor_mod 

39from google.protobuf import message as message_mod 

40from google.protobuf import text_format 

41 

42# We use "as" to avoid name collisions with variables. 

43from google.protobuf.internal import api_implementation 

44from google.protobuf.internal import containers 

45from google.protobuf.internal import decoder 

46from google.protobuf.internal import encoder 

47from google.protobuf.internal import enum_type_wrapper 

48from google.protobuf.internal import extension_dict 

49from google.protobuf.internal import message_listener as message_listener_mod 

50from google.protobuf.internal import type_checkers 

51from google.protobuf.internal import well_known_types 

52from google.protobuf.internal import wire_format 

53 

54_FieldDescriptor = descriptor_mod.FieldDescriptor 

55_AnyFullTypeName = 'google.protobuf.Any' 

56_StructFullTypeName = 'google.protobuf.Struct' 

57_ListValueFullTypeName = 'google.protobuf.ListValue' 

58_ExtensionDict = extension_dict._ExtensionDict 

59 

60 

61class GeneratedProtocolMessageType(type): 

62 """Metaclass for protocol message classes created at runtime from Descriptors. 

63 

64 We add implementations for all methods described in the Message class. We 

65 also create properties to allow getting/setting all fields in the protocol 

66 message. Finally, we create slots to prevent users from accidentally 

67 "setting" nonexistent fields in the protocol message, which then wouldn't get 

68 serialized / deserialized properly. 

69 

70 The protocol compiler currently uses this metaclass to create protocol 

71 message classes at runtime. Clients can also manually create their own 

72 classes at runtime, as in this example: 

73 

74 mydescriptor = Descriptor(.....) 

75 factory = symbol_database.Default() 

76 factory.pool.AddDescriptor(mydescriptor) 

77 MyProtoClass = message_factory.GetMessageClass(mydescriptor) 

78 myproto_instance = MyProtoClass() 

79 myproto.foo_field = 23 

80 ... 

81 """ 

82 

83 # Must be consistent with the protocol-compiler code in 

84 # proto2/compiler/internal/generator.*. 

85 _DESCRIPTOR_KEY = 'DESCRIPTOR' 

86 

87 def __new__(cls, name, bases, dictionary): 

88 """Custom allocation for runtime-generated class types. 

89 

90 We override __new__ because this is apparently the only place 

91 where we can meaningfully set __slots__ on the class we're creating(?). 

92 (The interplay between metaclasses and slots is not very well-documented). 

93 

94 Args: 

95 name: Name of the class (ignored, but required by the metaclass protocol). 

96 bases: Base classes of the class we're constructing. (Should be 

97 message.Message). We ignore this field, but it's required by the 

98 metaclass protocol 

99 dictionary: The class dictionary of the class we're constructing. 

100 dictionary[_DESCRIPTOR_KEY] must contain a Descriptor object describing 

101 this protocol message type. 

102 

103 Returns: 

104 Newly-allocated class. 

105 

106 Raises: 

107 RuntimeError: Generated code only work with python cpp extension. 

108 """ 

109 descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] 

110 

111 if isinstance(descriptor, str): 

112 raise RuntimeError( 

113 'The generated code only work with python cpp ' 

114 'extension, but it is using pure python runtime.' 

115 ) 

116 

117 # If a concrete class already exists for this descriptor, don't try to 

118 # create another. Doing so will break any messages that already exist with 

119 # the existing class. 

120 # 

121 # The C++ implementation appears to have its own internal `PyMessageFactory` 

122 # to achieve similar results. 

123 # 

124 # This most commonly happens in `text_format.py` when using descriptors from 

125 # a custom pool; it calls message_factory.GetMessageClass() on a 

126 # descriptor which already has an existing concrete class. 

127 new_class = getattr(descriptor, '_concrete_class', None) 

128 if new_class: 

129 return new_class 

130 

131 if descriptor.full_name in well_known_types.WKTBASES: 

132 bases += (well_known_types.WKTBASES[descriptor.full_name],) 

133 _AddClassAttributesForNestedExtensions(descriptor, dictionary) 

134 _AddSlots(descriptor, dictionary) 

135 

136 superclass = super(GeneratedProtocolMessageType, cls) 

137 new_class = superclass.__new__(cls, name, bases, dictionary) 

138 return new_class 

139 

140 def __init__(cls, name, bases, dictionary): 

141 """Here we perform the majority of our work on the class. 

142 

143 We add enum getters, an __init__ method, implementations of all Message 

144 methods, and properties for all fields in the protocol type. 

145 

146 Args: 

147 name: Name of the class (ignored, but required by the metaclass protocol). 

148 bases: Base classes of the class we're constructing. (Should be 

149 message.Message). We ignore this field, but it's required by the 

150 metaclass protocol 

151 dictionary: The class dictionary of the class we're constructing. 

152 dictionary[_DESCRIPTOR_KEY] must contain a Descriptor object describing 

153 this protocol message type. 

154 """ 

155 descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] 

156 

157 # If this is an _existing_ class looked up via `_concrete_class` in the 

158 # __new__ method above, then we don't need to re-initialize anything. 

159 existing_class = getattr(descriptor, '_concrete_class', None) 

160 if existing_class: 

161 assert existing_class is cls, ( 

162 'Duplicate `GeneratedProtocolMessageType` created for descriptor %r' 

163 % (descriptor.full_name) 

164 ) 

165 return 

166 

167 cls._message_set_decoders_by_tag = {} 

168 cls._fields_by_tag = {} 

169 if ( 

170 descriptor.has_options 

171 and descriptor.GetOptions().message_set_wire_format 

172 ): 

173 cls._message_set_decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = ( 

174 decoder.MessageSetItemDecoder(descriptor), 

175 None, 

176 ) 

177 

178 # Attach stuff to each FieldDescriptor for quick lookup later on. 

179 for field in descriptor.fields: 

180 _AttachFieldHelpers(cls, field) 

181 

182 if descriptor.is_extendable and hasattr(descriptor.file, 'pool'): 

183 extensions = descriptor.file.pool.FindAllExtensions(descriptor) 

184 for ext in extensions: 

185 _AttachFieldHelpers(cls, ext) 

186 

187 descriptor._concrete_class = cls # pylint: disable=protected-access 

188 _AddEnumValues(descriptor, cls) 

189 _AddInitMethod(descriptor, cls) 

190 _AddPropertiesForFields(descriptor, cls) 

191 _AddPropertiesForExtensions(descriptor, cls) 

192 _AddStaticMethods(cls) 

193 _AddMessageMethods(descriptor, cls) 

194 _AddPrivateHelperMethods(descriptor, cls) 

195 

196 superclass = super(GeneratedProtocolMessageType, cls) 

197 superclass.__init__(name, bases, dictionary) 

198 

199 

200# Stateless helpers for GeneratedProtocolMessageType below. 

201# Outside clients should not access these directly. 

202# 

203# I opted not to make any of these methods on the metaclass, to make it more 

204# clear that I'm not really using any state there and to keep clients from 

205# thinking that they have direct access to these construction helpers. 

206 

207 

208def _PropertyName(proto_field_name): 

209 """Returns the name of the public property attribute which 

210 

211 clients can use to get and (in some cases) set the value 

212 of a protocol message field. 

213 

214 Args: 

215 proto_field_name: The protocol message field name, exactly as it appears (or 

216 would appear) in a .proto file. 

217 """ 

218 # TODO: Escape Python keywords (e.g., yield), and test this support. 

219 # nnorwitz makes my day by writing: 

220 # """ 

221 # FYI. See the keyword module in the stdlib. This could be as simple as: 

222 # 

223 # if keyword.iskeyword(proto_field_name): 

224 # return proto_field_name + "_" 

225 # return proto_field_name 

226 # """ 

227 # Kenton says: The above is a BAD IDEA. People rely on being able to use 

228 # getattr() and setattr() to reflectively manipulate field values. If we 

229 # rename the properties, then every such user has to also make sure to apply 

230 # the same transformation. Note that currently if you name a field "yield", 

231 # you can still access it just fine using getattr/setattr -- it's not even 

232 # that cumbersome to do so. 

233 # TODO: Remove this method entirely if/when everyone agrees with my 

234 # position. 

235 return proto_field_name 

236 

237 

238def _AddSlots(message_descriptor, dictionary): 

239 """Adds a __slots__ entry to dictionary, containing the names of all valid 

240 

241 attributes for this message type. 

242 

243 Args: 

244 message_descriptor: A Descriptor instance describing this message type. 

245 dictionary: Class dictionary to which we'll add a '__slots__' entry. 

246 """ 

247 dictionary['__slots__'] = [ 

248 '_cached_byte_size', 

249 '_cached_byte_size_dirty', 

250 '_fields', 

251 '_unknown_fields', 

252 '_is_present_in_parent', 

253 '_listener', 

254 '_listener_for_children', 

255 '__weakref__', 

256 '_oneofs', 

257 '_frozen', 

258 ] 

259 

260 

261def _IsMessageSetExtension(field): 

262 return ( 

263 field.is_extension 

264 and field.containing_type.has_options 

265 and field.containing_type.GetOptions().message_set_wire_format 

266 and field.type == _FieldDescriptor.TYPE_MESSAGE 

267 and not field.is_required 

268 and not field.is_repeated 

269 ) 

270 

271 

272def _IsMapField(field): 

273 return ( 

274 field.type == _FieldDescriptor.TYPE_MESSAGE 

275 and field.message_type._is_map_entry 

276 ) 

277 

278 

279def _IsMessageMapField(field): 

280 value_type = field.message_type.fields_by_name['value'] 

281 return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE 

282 

283 

284def _AttachFieldHelpers(cls, field_descriptor): 

285 field_descriptor._default_constructor = _DefaultValueConstructorForField( 

286 field_descriptor 

287 ) 

288 

289 def AddFieldByTag(wiretype, is_packed): 

290 tag_bytes = encoder.TagBytes(field_descriptor.number, wiretype) 

291 cls._fields_by_tag[tag_bytes] = (field_descriptor, is_packed) 

292 

293 AddFieldByTag( 

294 type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type], False 

295 ) 

296 

297 if field_descriptor.is_repeated and wire_format.IsTypePackable( 

298 field_descriptor.type 

299 ): 

300 # To support wire compatibility of adding packed = true, add a decoder for 

301 # packed values regardless of the field's options. 

302 AddFieldByTag(wire_format.WIRETYPE_LENGTH_DELIMITED, True) 

303 

304 

305def _MaybeAddEncoder(cls, field_descriptor): 

306 if hasattr(field_descriptor, '_encoder'): 

307 return 

308 is_repeated = field_descriptor.is_repeated 

309 is_map_entry = _IsMapField(field_descriptor) 

310 is_packed = field_descriptor.is_packed 

311 

312 if is_map_entry: 

313 key_descriptor = field_descriptor.message_type.fields_by_name['key'] 

314 value_descriptor = field_descriptor.message_type.fields_by_name['value'] 

315 

316 key_sizer = type_checkers.TYPE_TO_SIZER[key_descriptor.type]( 

317 key_descriptor.number, False, False 

318 ) 

319 value_sizer = type_checkers.TYPE_TO_SIZER[value_descriptor.type]( 

320 value_descriptor.number, False, False 

321 ) 

322 

323 key_encoder = type_checkers.TYPE_TO_ENCODER[key_descriptor.type]( 

324 key_descriptor.number, False, False 

325 ) 

326 value_encoder = type_checkers.TYPE_TO_ENCODER[value_descriptor.type]( 

327 value_descriptor.number, False, False 

328 ) 

329 

330 field_encoder = encoder.MapEncoder( 

331 field_descriptor, key_encoder, value_encoder, key_sizer, value_sizer 

332 ) 

333 sizer = encoder.MapSizer(field_descriptor, key_sizer, value_sizer) 

334 elif _IsMessageSetExtension(field_descriptor): 

335 field_encoder = encoder.MessageSetItemEncoder(field_descriptor.number) 

336 sizer = encoder.MessageSetItemSizer(field_descriptor.number) 

337 else: 

338 field_encoder = type_checkers.TYPE_TO_ENCODER[field_descriptor.type]( 

339 field_descriptor.number, is_repeated, is_packed 

340 ) 

341 sizer = type_checkers.TYPE_TO_SIZER[field_descriptor.type]( 

342 field_descriptor.number, is_repeated, is_packed 

343 ) 

344 

345 field_descriptor._sizer = sizer 

346 field_descriptor._encoder = field_encoder 

347 

348 

349def _MaybeAddDecoder(cls, field_descriptor): 

350 if hasattr(field_descriptor, '_decoders'): 

351 return 

352 

353 is_repeated = field_descriptor.is_repeated 

354 is_map_entry = _IsMapField(field_descriptor) 

355 helper_decoders = {} 

356 

357 def AddDecoder(is_packed): 

358 decode_type = field_descriptor.type 

359 if ( 

360 decode_type == _FieldDescriptor.TYPE_ENUM 

361 and not field_descriptor.enum_type.is_closed 

362 ): 

363 decode_type = _FieldDescriptor.TYPE_INT32 

364 

365 oneof_descriptor = None 

366 if field_descriptor.containing_oneof is not None: 

367 oneof_descriptor = field_descriptor 

368 

369 if is_map_entry: 

370 is_message_map = _IsMessageMapField(field_descriptor) 

371 

372 field_decoder = decoder.MapDecoder( 

373 field_descriptor, 

374 _GetInitializeDefaultForMap(field_descriptor), 

375 is_message_map, 

376 ) 

377 elif decode_type == _FieldDescriptor.TYPE_STRING: 

378 field_decoder = decoder.StringDecoder( 

379 field_descriptor.number, 

380 is_repeated, 

381 is_packed, 

382 field_descriptor, 

383 field_descriptor._default_constructor, 

384 not field_descriptor.has_presence, 

385 ) 

386 elif field_descriptor.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

387 field_decoder = type_checkers.TYPE_TO_DECODER[decode_type]( 

388 field_descriptor.number, 

389 is_repeated, 

390 is_packed, 

391 field_descriptor, 

392 field_descriptor._default_constructor, 

393 ) 

394 else: 

395 field_decoder = type_checkers.TYPE_TO_DECODER[decode_type]( 

396 field_descriptor.number, 

397 is_repeated, 

398 is_packed, 

399 # pylint: disable=protected-access 

400 field_descriptor, 

401 field_descriptor._default_constructor, 

402 not field_descriptor.has_presence, 

403 ) 

404 

405 helper_decoders[is_packed] = field_decoder 

406 

407 AddDecoder(False) 

408 

409 if is_repeated and wire_format.IsTypePackable(field_descriptor.type): 

410 # To support wire compatibility of adding packed = true, add a decoder for 

411 # packed values regardless of the field's options. 

412 AddDecoder(True) 

413 

414 field_descriptor._decoders = helper_decoders 

415 

416 

417def _AddClassAttributesForNestedExtensions(descriptor, dictionary): 

418 extensions = descriptor.extensions_by_name 

419 for extension_name, extension_field in extensions.items(): 

420 assert extension_name not in dictionary 

421 dictionary[extension_name] = extension_field 

422 

423 

424def _AddEnumValues(descriptor, cls): 

425 """Sets class-level attributes for all enum fields defined in this message. 

426 

427 Also exporting a class-level object that can name enum values. 

428 

429 Args: 

430 descriptor: Descriptor object for this message type. 

431 cls: Class we're constructing for this message type. 

432 """ 

433 for enum_type in descriptor.enum_types: 

434 setattr(cls, enum_type.name, enum_type_wrapper.EnumTypeWrapper(enum_type)) 

435 for enum_value in enum_type.values: 

436 setattr(cls, enum_value.name, enum_value.number) 

437 

438 

439def _GetInitializeDefaultForMap(field): 

440 if not field.is_repeated: 

441 raise ValueError('map_entry set on non-repeated field %s' % (field.name)) 

442 fields_by_name = field.message_type.fields_by_name 

443 key_checker = type_checkers.GetTypeChecker(fields_by_name['key']) 

444 

445 value_field = fields_by_name['value'] 

446 if _IsMessageMapField(field): 

447 

448 def MakeMessageMapDefault(message): 

449 return containers.MessageMap( 

450 message._listener_for_children, 

451 value_field.message_type, 

452 key_checker, 

453 field.message_type, 

454 ) 

455 

456 return MakeMessageMapDefault 

457 else: 

458 value_checker = type_checkers.GetTypeChecker(value_field) 

459 

460 def MakePrimitiveMapDefault(message): 

461 return containers.ScalarMap( 

462 message._listener_for_children, 

463 key_checker, 

464 value_checker, 

465 field.message_type, 

466 ) 

467 

468 return MakePrimitiveMapDefault 

469 

470 

471def _DefaultValueConstructorForField(field): 

472 """Returns a function which returns a default value for a field. 

473 

474 Args: 

475 field: FieldDescriptor object for this field. 

476 

477 The returned function has one argument: 

478 message: Message instance containing this field, or a weakref proxy 

479 of same. 

480 

481 That function in turn returns a default value for this field. The default 

482 value may refer back to |message| via a weak reference. 

483 """ 

484 

485 if _IsMapField(field): 

486 return _GetInitializeDefaultForMap(field) 

487 

488 if field.is_repeated: 

489 if field.has_default_value and field.default_value != []: 

490 raise ValueError( 

491 'Repeated field default value not empty list: %s' 

492 % (field.default_value) 

493 ) 

494 if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

495 # We can't look at _concrete_class yet since it might not have 

496 # been set. (Depends on order in which we initialize the classes). 

497 message_type = field.message_type 

498 

499 def MakeRepeatedMessageDefault(message): 

500 return containers.RepeatedCompositeFieldContainer( 

501 message._listener_for_children, field.message_type 

502 ) 

503 

504 return MakeRepeatedMessageDefault 

505 else: 

506 type_checker = type_checkers.GetTypeChecker(field) 

507 

508 def MakeRepeatedScalarDefault(message): 

509 return containers.RepeatedScalarFieldContainer( 

510 message._listener_for_children, type_checker, field 

511 ) 

512 

513 return MakeRepeatedScalarDefault 

514 

515 if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

516 message_type = field.message_type 

517 

518 def MakeSubMessageDefault(message): 

519 # _concrete_class may not yet be initialized. 

520 if not hasattr(message_type, '_concrete_class'): 

521 from google.protobuf import message_factory 

522 

523 message_factory.GetMessageClass(message_type) 

524 result = message_type._concrete_class() 

525 result._SetListener( 

526 _OneofListener(message, field) 

527 if field.containing_oneof is not None 

528 else message._listener_for_children 

529 ) 

530 return result 

531 

532 return MakeSubMessageDefault 

533 

534 def MakeScalarDefault(message): 

535 # TODO: This may be broken since there may not be 

536 # default_value. Combine with has_default_value somehow. 

537 return field.default_value 

538 

539 return MakeScalarDefault 

540 

541 

542def _ReraiseTypeErrorWithFieldName(message_name, field_name): 

543 """Re-raise the currently-handled TypeError with the field name added.""" 

544 exc = sys.exc_info()[1] 

545 if len(exc.args) == 1 and type(exc) is TypeError: 

546 # simple TypeError; add field name to exception message 

547 exc = TypeError('%s for field %s.%s' % (str(exc), message_name, field_name)) 

548 

549 # re-raise possibly-amended exception with original traceback: 

550 raise exc.with_traceback(sys.exc_info()[2]) 

551 

552 

553def _AddInitMethod(message_descriptor, cls): 

554 """Adds an __init__ method to cls.""" 

555 

556 def _GetIntegerEnumValue(enum_type, value): 

557 """Convert a string or integer enum value to an integer. 

558 

559 If the value is a string, it is converted to the enum value in 

560 enum_type with the same name. If the value is not a string, it's 

561 returned as-is. (No conversion or bounds-checking is done.) 

562 """ 

563 if isinstance(value, str): 

564 try: 

565 return enum_type.values_by_name[value].number 

566 except KeyError: 

567 raise ValueError( 

568 'Enum type %s: unknown label "%s"' % (enum_type.full_name, value) 

569 ) 

570 return value 

571 

572 def init(self, **kwargs): 

573 

574 def init_wkt_or_merge(field, msg, value): 

575 if isinstance(value, message_mod.Message): 

576 msg.MergeFrom(value) 

577 elif ( 

578 isinstance(value, dict) 

579 and field.message_type.full_name == _StructFullTypeName 

580 ): 

581 msg.Clear() 

582 if len(value) == 1 and 'fields' in value: 

583 try: 

584 msg.update(value) 

585 except: 

586 msg.Clear() 

587 msg.__init__(**value) 

588 else: 

589 msg.update(value) 

590 elif hasattr(msg, '_internal_assign'): 

591 msg._internal_assign(value) 

592 else: 

593 raise TypeError( 

594 'Message field {0}.{1} must be initialized with a ' 

595 'dict or instance of same class, got {2}.'.format( 

596 message_descriptor.name, 

597 field.name, 

598 type(value).__name__, 

599 ) 

600 ) 

601 

602 self._cached_byte_size = 0 

603 self._cached_byte_size_dirty = len(kwargs) > 0 

604 self._fields = {} 

605 # Contains a mapping from oneof field descriptors to the descriptor 

606 # of the currently set field in that oneof field. 

607 self._oneofs = {} 

608 

609 # _unknown_fields is () when empty for efficiency, and will be turned into 

610 # a list if fields are added. 

611 self._unknown_fields = () 

612 self._is_present_in_parent = False 

613 self._listener = message_listener_mod.NullMessageListener() 

614 self._listener_for_children = _Listener(self) 

615 self._frozen = False 

616 for field_name, field_value in kwargs.items(): 

617 field = _GetFieldByName(message_descriptor, field_name) 

618 if field is None: 

619 raise TypeError( 

620 '%s() got an unexpected keyword argument "%s"' 

621 % (message_descriptor.name, field_name) 

622 ) 

623 if field_value is None: 

624 # field=None is the same as no field at all. 

625 continue 

626 if field.is_repeated: 

627 field_copy = field._default_constructor(self) 

628 if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: # Composite 

629 if _IsMapField(field): 

630 if _IsMessageMapField(field): 

631 for key in field_value: 

632 item_value = field_value[key] 

633 if isinstance(item_value, dict): 

634 field_copy[key].__init__(**item_value) 

635 else: 

636 field_copy[key].MergeFrom(item_value) 

637 else: 

638 field_copy.update(field_value) 

639 else: 

640 for val in field_value: 

641 if isinstance(val, dict) and ( 

642 field.message_type.full_name != _StructFullTypeName 

643 ): 

644 field_copy.add(**val) 

645 else: 

646 new_msg = field_copy.add() 

647 init_wkt_or_merge(field, new_msg, val) 

648 else: # Scalar 

649 if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM: 

650 field_value = [ 

651 _GetIntegerEnumValue(field.enum_type, val) 

652 for val in field_value 

653 ] 

654 field_copy.extend(field_value) 

655 self._fields[field] = field_copy 

656 elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

657 field_copy = field._default_constructor(self) 

658 if isinstance(field_value, dict) and ( 

659 field.message_type.full_name != _StructFullTypeName 

660 ): 

661 new_val = field.message_type._concrete_class(**field_value) 

662 field_copy.MergeFrom(new_val) 

663 else: 

664 try: 

665 init_wkt_or_merge(field, field_copy, field_value) 

666 except TypeError: 

667 _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name) 

668 self._fields[field] = field_copy 

669 else: 

670 if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM: 

671 field_value = _GetIntegerEnumValue(field.enum_type, field_value) 

672 try: 

673 setattr(self, field_name, field_value) 

674 except TypeError: 

675 _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name) 

676 

677 init.__module__ = None 

678 init.__doc__ = None 

679 cls.__init__ = init 

680 

681 

682def _GetFieldByName(message_descriptor, field_name): 

683 """Returns a field descriptor by field name. 

684 

685 Args: 

686 message_descriptor: A Descriptor describing all fields in message. 

687 field_name: The name of the field to retrieve. 

688 

689 Returns: 

690 The field descriptor associated with the field name. 

691 """ 

692 try: 

693 return message_descriptor.fields_by_name[field_name] 

694 except KeyError: 

695 raise ValueError( 

696 'Protocol message %s has no "%s" field.' 

697 % (message_descriptor.name, field_name) 

698 ) 

699 

700 

701def _AddPropertiesForFields(descriptor, cls): 

702 """Adds properties for all fields in this protocol message type.""" 

703 for field in descriptor.fields: 

704 _AddPropertiesForField(field, cls) 

705 

706 if descriptor.is_extendable: 

707 # _ExtensionDict is just an adaptor with no state so we allocate a new one 

708 # every time it is accessed. 

709 cls.Extensions = property(lambda self: _ExtensionDict(self)) 

710 

711 

712def _AddPropertiesForField(field, cls): 

713 """Adds a public property for a protocol message field. 

714 

715 Clients can use this property to get and (in the case of non-repeated scalar 

716 fields) directly set the value of a protocol message field. 

717 

718 Args: 

719 field: A FieldDescriptor for this field. 

720 cls: The class we're constructing. 

721 """ 

722 # Catch it if we add other types that we should 

723 # handle specially here. 

724 assert _FieldDescriptor.MAX_CPPTYPE == 10 

725 

726 constant_name = field.name.upper() + '_FIELD_NUMBER' 

727 setattr(cls, constant_name, field.number) 

728 

729 if field.is_repeated: 

730 _AddPropertiesForRepeatedField(field, cls) 

731 elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

732 _AddPropertiesForNonRepeatedCompositeField(field, cls) 

733 else: 

734 _AddPropertiesForNonRepeatedScalarField(field, cls) 

735 

736 

737class _FieldProperty(property): 

738 __slots__ = ('DESCRIPTOR',) 

739 

740 def __init__(self, descriptor, getter, setter, doc): 

741 property.__init__(self, getter, setter, doc=doc) 

742 self.DESCRIPTOR = descriptor 

743 

744 

745def _AddPropertiesForRepeatedField(field, cls): 

746 """Adds a public property for a "repeated" protocol message field. 

747 

748 Clients can use this property to get the value of the field, which will be 

749 either a RepeatedScalarFieldContainer or RepeatedCompositeFieldContainer (see 

750 below). 

751 

752 Note that when clients add values to these containers, we perform 

753 type-checking in the case of repeated scalar fields, and we also set any 

754 necessary "has" bits as a side-effect. 

755 

756 Args: 

757 field: A FieldDescriptor for this field. 

758 cls: The class we're constructing. 

759 """ 

760 proto_field_name = field.name 

761 property_name = _PropertyName(proto_field_name) 

762 

763 def getter(self): 

764 field_value = self._fields.get(field) 

765 if field_value is None: 

766 # Construct a new object to represent this field. 

767 field_value = field._default_constructor(self) 

768 if self._frozen: 

769 field_value._SetFrozen() 

770 

771 # Atomically check if another thread has preempted us and, if not, swap 

772 # in the new object we just created. If someone has preempted us, we 

773 # take that object and discard ours. 

774 # WARNING: We are relying on setdefault() being atomic. This is true 

775 # in CPython but we haven't investigated others. This warning appears 

776 # in several other locations in this file. 

777 field_value = self._fields.setdefault(field, field_value) 

778 return field_value 

779 

780 getter.__module__ = None 

781 getter.__doc__ = 'Getter for %s.' % proto_field_name 

782 

783 # We define a setter just so we can throw an exception with a more 

784 # helpful error message. 

785 def setter(self, new_value): 

786 raise AttributeError( 

787 'Assignment not allowed to repeated field ' 

788 '"%s" in protocol message object.' % proto_field_name 

789 ) 

790 

791 doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name 

792 setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc)) 

793 

794 

795def _AddPropertiesForNonRepeatedScalarField(field, cls): 

796 """Adds a public property for a nonrepeated, scalar protocol message field. 

797 

798 Clients can use this property to get and directly set the value of the field. 

799 Note that when the client sets the value of a field by using this property, 

800 all necessary "has" bits are set as a side-effect, and we also perform 

801 type-checking. 

802 

803 Args: 

804 field: A FieldDescriptor for this field. 

805 cls: The class we're constructing. 

806 """ 

807 proto_field_name = field.name 

808 property_name = _PropertyName(proto_field_name) 

809 type_checker = type_checkers.GetTypeChecker(field) 

810 default_value = field.default_value 

811 

812 def getter(self): 

813 # TODO: This may be broken since there may not be 

814 # default_value. Combine with has_default_value somehow. 

815 return self._fields.get(field, default_value) 

816 

817 getter.__module__ = None 

818 getter.__doc__ = 'Getter for %s.' % proto_field_name 

819 

820 def field_setter(self, new_value): 

821 self._AssureWritable() 

822 # pylint: disable=protected-access 

823 # Testing the value for truthiness captures all of the implicit presence 

824 # defaults (0, 0.0, enum 0, and False), except for -0.0. 

825 try: 

826 new_value = type_checker.CheckValue(new_value) 

827 except TypeError as e: 

828 raise TypeError( 

829 'Cannot set %s to %.1024r: %s' % (field.full_name, new_value, e) 

830 ) 

831 if not field.has_presence and decoder.IsDefaultScalarValue(new_value): 

832 self._fields.pop(field, None) 

833 else: 

834 self._fields[field] = new_value 

835 # Check _cached_byte_size_dirty inline to improve performance, since scalar 

836 # setters are called frequently. 

837 if not self._cached_byte_size_dirty: 

838 self._Modified() 

839 

840 if field.containing_oneof: 

841 

842 def setter(self, new_value): 

843 field_setter(self, new_value) 

844 self._UpdateOneofState(field) 

845 

846 else: 

847 setter = field_setter 

848 

849 setter.__module__ = None 

850 setter.__doc__ = 'Setter for %s.' % proto_field_name 

851 

852 # Add a property to encapsulate the getter/setter. 

853 doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name 

854 setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc)) 

855 

856 

857def _AddPropertiesForNonRepeatedCompositeField(field, cls): 

858 """Adds a public property for a nonrepeated, composite protocol message field. 

859 

860 A composite field is a "group" or "message" field. 

861 

862 Clients can use this property to get the value of the field, but cannot 

863 assign to the property directly. 

864 

865 Args: 

866 field: A FieldDescriptor for this field. 

867 cls: The class we're constructing. 

868 """ 

869 # TODO: Remove duplication with similar method 

870 # for non-repeated scalars. 

871 proto_field_name = field.name 

872 property_name = _PropertyName(proto_field_name) 

873 

874 def getter(self): 

875 field_value = self._fields.get(field) 

876 if field_value is None: 

877 # Construct a new object to represent this field. 

878 field_value = field._default_constructor(self) 

879 if self._frozen: 

880 field_value._SetFrozen() 

881 

882 # Atomically check if another thread has preempted us and, if not, swap 

883 # in the new object we just created. If someone has preempted us, we 

884 # take that object and discard ours. 

885 # WARNING: We are relying on setdefault() being atomic. This is true 

886 # in CPython but we haven't investigated others. This warning appears 

887 # in several other locations in this file. 

888 field_value = self._fields.setdefault(field, field_value) 

889 return field_value 

890 

891 getter.__module__ = None 

892 getter.__doc__ = 'Getter for %s.' % proto_field_name 

893 

894 # We define a setter just so we can throw an exception with a more 

895 # helpful error message. 

896 def setter(self, new_value): 

897 self._AssureWritable() 

898 if field.message_type.full_name == 'google.protobuf.Timestamp': 

899 getter(self) 

900 self._fields[field].FromDatetime(new_value) 

901 elif field.message_type.full_name == 'google.protobuf.Duration': 

902 getter(self) 

903 self._fields[field].FromTimedelta(new_value) 

904 elif field.message_type.full_name == _StructFullTypeName: 

905 getter(self) 

906 self._fields[field].Clear() 

907 self._fields[field].update(new_value) 

908 elif field.message_type.full_name == _ListValueFullTypeName: 

909 getter(self) 

910 self._fields[field].Clear() 

911 self._fields[field].extend(new_value) 

912 else: 

913 raise AttributeError( 

914 'Assignment not allowed to composite field ' 

915 '"%s" in protocol message object.' % proto_field_name 

916 ) 

917 

918 # Add a property to encapsulate the getter. 

919 doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name 

920 setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc)) 

921 

922 

923def _AddPropertiesForExtensions(descriptor, cls): 

924 """Adds properties for all fields in this protocol message type.""" 

925 extensions = descriptor.extensions_by_name 

926 for extension_name, extension_field in extensions.items(): 

927 constant_name = extension_name.upper() + '_FIELD_NUMBER' 

928 setattr(cls, constant_name, extension_field.number) 

929 

930 # TODO: Migrate all users of these attributes to functions like 

931 # pool.FindExtensionByNumber(descriptor). 

932 if descriptor.file is not None: 

933 # TODO: Use cls.MESSAGE_FACTORY.pool when available. 

934 pool = descriptor.file.pool 

935 

936 

937def _AddStaticMethods(cls): 

938 

939 def RegisterExtension(_): 

940 """no-op to keep generated code <=4.23 working with new runtimes.""" 

941 # This was originally removed in 5.26 (cl/595989309). 

942 pass 

943 

944 cls.RegisterExtension = staticmethod(RegisterExtension) 

945 

946 def FromString(s): 

947 message = cls() 

948 message.MergeFromString(s) 

949 return message 

950 

951 cls.FromString = staticmethod(FromString) 

952 

953 

954def _IsPresent(item): 

955 """Given a (FieldDescriptor, value) tuple from _fields, return true if the 

956 

957 value should be included in the list returned by ListFields(). 

958 """ 

959 

960 if item[0].is_repeated: 

961 return bool(item[1]) 

962 elif item[0].cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

963 return item[1]._is_present_in_parent 

964 else: 

965 return True 

966 

967 

968def _AddListFieldsMethod(message_descriptor, cls): 

969 """Helper for _AddMessageMethods().""" 

970 

971 def ListFields(self): 

972 all_fields = [item for item in self._fields.items() if _IsPresent(item)] 

973 all_fields.sort(key=lambda item: item[0].number) 

974 return all_fields 

975 

976 cls.ListFields = ListFields 

977 

978 

979def _AddHasFieldMethod(message_descriptor, cls): 

980 """Helper for _AddMessageMethods().""" 

981 

982 hassable_fields = {} 

983 for field in message_descriptor.fields: 

984 if field.is_repeated: 

985 continue 

986 # For proto3, only submessages and fields inside a oneof have presence. 

987 if not field.has_presence: 

988 continue 

989 hassable_fields[field.name] = field 

990 

991 # Has methods are supported for oneof descriptors. 

992 for oneof in message_descriptor.oneofs: 

993 hassable_fields[oneof.name] = oneof 

994 

995 def HasField(self, field_name): 

996 try: 

997 field = hassable_fields[field_name] 

998 except KeyError as exc: 

999 raise ValueError( 

1000 'Protocol message %s has no non-repeated field "%s" ' 

1001 'nor has presence is not available for this field.' 

1002 % (message_descriptor.full_name, field_name) 

1003 ) from exc 

1004 

1005 if isinstance(field, descriptor_mod.OneofDescriptor): 

1006 try: 

1007 return HasField(self, self._oneofs[field].name) 

1008 except KeyError: 

1009 return False 

1010 else: 

1011 if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

1012 value = self._fields.get(field) 

1013 return value is not None and value._is_present_in_parent 

1014 else: 

1015 return field in self._fields 

1016 

1017 cls.HasField = HasField 

1018 

1019 

1020def _AddClearFieldMethod(message_descriptor, cls): 

1021 """Helper for _AddMessageMethods().""" 

1022 

1023 def ClearField(self, field_name): 

1024 self._AssureWritable() 

1025 try: 

1026 field = message_descriptor.fields_by_name[field_name] 

1027 except KeyError: 

1028 try: 

1029 field = message_descriptor.oneofs_by_name[field_name] 

1030 if field in self._oneofs: 

1031 field = self._oneofs[field] 

1032 else: 

1033 return 

1034 except KeyError: 

1035 raise ValueError( 

1036 'Protocol message %s has no "%s" field.' 

1037 % (message_descriptor.name, field_name) 

1038 ) 

1039 

1040 if field in self._fields: 

1041 # To match the C++ implementation, we need to invalidate iterators 

1042 # for map fields when ClearField() happens. 

1043 if hasattr(self._fields[field], 'InvalidateIterators'): 

1044 self._fields[field].InvalidateIterators() 

1045 

1046 # Note: If the field is a sub-message, its listener will still point 

1047 # at us. That's fine, because the worst than can happen is that it 

1048 # will call _Modified() and invalidate our byte size. Big deal. 

1049 del self._fields[field] 

1050 

1051 if self._oneofs.get(field.containing_oneof, None) is field: 

1052 del self._oneofs[field.containing_oneof] 

1053 

1054 # Always call _Modified() -- even if nothing was changed, this is 

1055 # a mutating method, and thus calling it should cause the field to become 

1056 # present in the parent message. 

1057 self._Modified() 

1058 

1059 cls.ClearField = ClearField 

1060 

1061 

1062def _AddClearExtensionMethod(cls): 

1063 """Helper for _AddMessageMethods().""" 

1064 

1065 def ClearExtension(self, field_descriptor): 

1066 self._AssureWritable() 

1067 extension_dict._VerifyExtensionHandle(self, field_descriptor) 

1068 

1069 # Similar to ClearField(), above. 

1070 if field_descriptor in self._fields: 

1071 del self._fields[field_descriptor] 

1072 self._Modified() 

1073 

1074 cls.ClearExtension = ClearExtension 

1075 

1076 

1077def _AddHasExtensionMethod(cls): 

1078 """Helper for _AddMessageMethods().""" 

1079 

1080 def HasExtension(self, field_descriptor): 

1081 extension_dict._VerifyExtensionHandle(self, field_descriptor) 

1082 if field_descriptor.is_repeated: 

1083 raise KeyError('"%s" is repeated.' % field_descriptor.full_name) 

1084 

1085 if field_descriptor.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

1086 value = self._fields.get(field_descriptor) 

1087 return value is not None and value._is_present_in_parent 

1088 else: 

1089 return field_descriptor in self._fields 

1090 

1091 cls.HasExtension = HasExtension 

1092 

1093 

1094def _InternalUnpackAny(msg): 

1095 """Unpacks Any message and returns the unpacked message. 

1096 

1097 This internal method is different from public Any Unpack method which takes 

1098 the target message as argument. _InternalUnpackAny method does not have 

1099 target message type and need to find the message type in descriptor pool. 

1100 

1101 Args: 

1102 msg: An Any message to be unpacked. 

1103 

1104 Returns: 

1105 The unpacked message. 

1106 """ 

1107 # TODO: Don't use the factory of generated messages. 

1108 # To make Any work with custom factories, use the message factory of the 

1109 # parent message. 

1110 # pylint: disable=g-import-not-at-top 

1111 from google.protobuf import symbol_database 

1112 

1113 factory = symbol_database.Default() 

1114 

1115 type_url = msg.type_url 

1116 

1117 if not type_url: 

1118 return None 

1119 

1120 # TODO: For now we just strip the hostname. Better logic will be 

1121 # required. 

1122 type_name = type_url.split('/')[-1] 

1123 descriptor = factory.pool.FindMessageTypeByName(type_name) 

1124 

1125 if descriptor is None: 

1126 return None 

1127 

1128 # Unable to import message_factory at top because of circular import. 

1129 # pylint: disable=g-import-not-at-top 

1130 from google.protobuf import message_factory 

1131 

1132 message_class = message_factory.GetMessageClass(descriptor) 

1133 message = message_class() 

1134 

1135 message.ParseFromString(msg.value) 

1136 return message 

1137 

1138 

1139def _AddEqualsMethod(message_descriptor, cls): 

1140 """Helper for _AddMessageMethods().""" 

1141 

1142 def __eq__(self, other): 

1143 if self.DESCRIPTOR.full_name == _ListValueFullTypeName and isinstance( 

1144 other, list 

1145 ): 

1146 return self._internal_compare(other) 

1147 if self.DESCRIPTOR.full_name == _StructFullTypeName and isinstance( 

1148 other, dict 

1149 ): 

1150 return self._internal_compare(other) 

1151 

1152 if ( 

1153 not isinstance(other, message_mod.Message) 

1154 or other.DESCRIPTOR != self.DESCRIPTOR 

1155 ): 

1156 return NotImplemented 

1157 

1158 if self is other: 

1159 return True 

1160 

1161 if self.DESCRIPTOR.full_name == _AnyFullTypeName: 

1162 any_a = _InternalUnpackAny(self) 

1163 any_b = _InternalUnpackAny(other) 

1164 if any_a and any_b: 

1165 return any_a == any_b 

1166 

1167 if not self.ListFields() == other.ListFields(): 

1168 return False 

1169 

1170 # TODO: Fix UnknownFieldSet to consider MessageSet extensions, 

1171 # then use it for the comparison. 

1172 unknown_fields = list(self._unknown_fields) 

1173 unknown_fields.sort() 

1174 other_unknown_fields = list(other._unknown_fields) 

1175 other_unknown_fields.sort() 

1176 return unknown_fields == other_unknown_fields 

1177 

1178 cls.__eq__ = __eq__ 

1179 

1180 

1181def _AddStrMethod(message_descriptor, cls): 

1182 """Helper for _AddMessageMethods().""" 

1183 

1184 def __str__(self): 

1185 return text_format.MessageToString(self) 

1186 

1187 cls.__str__ = __str__ 

1188 

1189 

1190def _AddReprMethod(message_descriptor, cls): 

1191 """Helper for _AddMessageMethods().""" 

1192 

1193 def __repr__(self): 

1194 return text_format.MessageToString(self) 

1195 

1196 cls.__repr__ = __repr__ 

1197 

1198 

1199def _AddUnicodeMethod(unused_message_descriptor, cls): 

1200 """Helper for _AddMessageMethods().""" 

1201 

1202 def __unicode__(self): 

1203 return text_format.MessageToString(self, as_utf8=True).decode('utf-8') 

1204 

1205 cls.__unicode__ = __unicode__ 

1206 

1207 

1208def _AddContainsMethod(message_descriptor, cls): 

1209 

1210 if message_descriptor.full_name == 'google.protobuf.Struct': 

1211 

1212 def __contains__(self, key): 

1213 return key in self.fields 

1214 

1215 elif message_descriptor.full_name == 'google.protobuf.ListValue': 

1216 

1217 def __contains__(self, value): 

1218 return value in self.items() 

1219 

1220 else: 

1221 

1222 def __contains__(self, field): 

1223 return self.HasField(field) 

1224 

1225 cls.__contains__ = __contains__ 

1226 

1227 

1228def _BytesForNonRepeatedElement(value, field_number, field_type): 

1229 """Returns the number of bytes needed to serialize a non-repeated element. 

1230 

1231 The returned byte count includes space for tag information and any other 

1232 additional space associated with serializing value. 

1233 

1234 Args: 

1235 value: Value we're serializing. 

1236 field_number: Field number of this value. (Since the field number is stored 

1237 as part of a varint-encoded tag, this has an impact on the total bytes 

1238 required to serialize the value). 

1239 field_type: The type of the field. One of the TYPE_* constants within 

1240 FieldDescriptor. 

1241 """ 

1242 try: 

1243 fn = type_checkers.TYPE_TO_BYTE_SIZE_FN[field_type] 

1244 return fn(field_number, value) 

1245 except KeyError: 

1246 raise message_mod.EncodeError('Unrecognized field type: %d' % field_type) 

1247 

1248 

1249def _AddByteSizeMethod(message_descriptor, cls): 

1250 """Helper for _AddMessageMethods().""" 

1251 

1252 def ByteSize(self): 

1253 if not self._cached_byte_size_dirty: 

1254 return self._cached_byte_size 

1255 

1256 size = 0 

1257 descriptor = self.DESCRIPTOR 

1258 if descriptor._is_map_entry: 

1259 # Fields of map entry should always be serialized. 

1260 key_field = descriptor.fields_by_name['key'] 

1261 _MaybeAddEncoder(cls, key_field) 

1262 size = key_field._sizer(self.key) 

1263 value_field = descriptor.fields_by_name['value'] 

1264 _MaybeAddEncoder(cls, value_field) 

1265 size += value_field._sizer(self.value) 

1266 else: 

1267 for field_descriptor, field_value in self.ListFields(): 

1268 _MaybeAddEncoder(cls, field_descriptor) 

1269 size += field_descriptor._sizer(field_value) 

1270 for tag_bytes, value_bytes in self._unknown_fields: 

1271 size += len(tag_bytes) + len(value_bytes) 

1272 

1273 self._cached_byte_size = size 

1274 self._cached_byte_size_dirty = False 

1275 self._listener_for_children.dirty = False 

1276 return size 

1277 

1278 cls.ByteSize = ByteSize 

1279 

1280 

1281def _AddSerializeToStringMethod(message_descriptor, cls): 

1282 """Helper for _AddMessageMethods().""" 

1283 

1284 def SerializeToString(self, **kwargs): 

1285 # Check if the message has all of its required fields set. 

1286 if not self.IsInitialized(): 

1287 raise message_mod.EncodeError( 

1288 'Message %s is missing required fields: %s' 

1289 % ( 

1290 self.DESCRIPTOR.full_name, 

1291 ','.join(self.FindInitializationErrors()), 

1292 ) 

1293 ) 

1294 return self.SerializePartialToString(**kwargs) 

1295 

1296 cls.SerializeToString = SerializeToString 

1297 

1298 

1299def _AddSerializePartialToStringMethod(message_descriptor, cls): 

1300 """Helper for _AddMessageMethods().""" 

1301 

1302 def SerializePartialToString(self, **kwargs): 

1303 out = BytesIO() 

1304 self._InternalSerialize(out.write, **kwargs) 

1305 return out.getvalue() 

1306 

1307 cls.SerializePartialToString = SerializePartialToString 

1308 

1309 def InternalSerialize(self, write_bytes, deterministic=None): 

1310 if deterministic is None: 

1311 deterministic = ( 

1312 api_implementation.IsPythonDefaultSerializationDeterministic() 

1313 ) 

1314 else: 

1315 deterministic = bool(deterministic) 

1316 

1317 descriptor = self.DESCRIPTOR 

1318 if descriptor._is_map_entry: 

1319 # Fields of map entry should always be serialized. 

1320 key_field = descriptor.fields_by_name['key'] 

1321 _MaybeAddEncoder(cls, key_field) 

1322 key_field._encoder(write_bytes, self.key, deterministic) 

1323 value_field = descriptor.fields_by_name['value'] 

1324 _MaybeAddEncoder(cls, value_field) 

1325 value_field._encoder(write_bytes, self.value, deterministic) 

1326 else: 

1327 for field_descriptor, field_value in self.ListFields(): 

1328 _MaybeAddEncoder(cls, field_descriptor) 

1329 field_descriptor._encoder(write_bytes, field_value, deterministic) 

1330 for tag_bytes, value_bytes in self._unknown_fields: 

1331 write_bytes(tag_bytes) 

1332 write_bytes(value_bytes) 

1333 

1334 cls._InternalSerialize = InternalSerialize 

1335 

1336 

1337def _AddMergeFromStringMethod(message_descriptor, cls): 

1338 """Helper for _AddMessageMethods().""" 

1339 

1340 def MergeFromString(self, serialized): 

1341 self._AssureWritable() 

1342 serialized = memoryview(serialized) 

1343 length = len(serialized) 

1344 try: 

1345 if self._InternalParse(serialized, 0, length) != length: 

1346 # The only reason _InternalParse would return early is if it 

1347 # encountered an end-group tag. 

1348 raise message_mod.DecodeError('Unexpected end-group tag.') 

1349 except (IndexError, TypeError): 

1350 # Now ord(buf[p:p+1]) == ord('') gets TypeError. 

1351 raise message_mod.DecodeError('Truncated message.') 

1352 except struct.error as e: 

1353 raise message_mod.DecodeError(e) 

1354 return length # Return this for legacy reasons. 

1355 

1356 cls.MergeFromString = MergeFromString 

1357 

1358 fields_by_tag = cls._fields_by_tag 

1359 message_set_decoders_by_tag = cls._message_set_decoders_by_tag 

1360 

1361 def InternalParse(self, buffer, pos, end, current_depth=0): 

1362 """Create a message from serialized bytes. 

1363 

1364 Args: 

1365 self: Message, instance of the proto message object. 

1366 buffer: memoryview of the serialized data. 

1367 pos: int, position to start in the serialized data. 

1368 end: int, end position of the serialized data. 

1369 

1370 Returns: 

1371 Message object. 

1372 """ 

1373 # Guard against internal misuse, since this function is called internally 

1374 # quite extensively, and its easy to accidentally pass bytes. 

1375 assert isinstance(buffer, memoryview) 

1376 self._Modified() 

1377 field_dict = self._fields 

1378 while pos != end: 

1379 tag_bytes, new_pos = decoder.ReadTag(buffer, pos) 

1380 field_decoder, field_des = message_set_decoders_by_tag.get( 

1381 tag_bytes, (None, None) 

1382 ) 

1383 if field_decoder: 

1384 pos = field_decoder( 

1385 buffer, new_pos, end, self, field_dict, current_depth 

1386 ) 

1387 continue 

1388 field_des, is_packed = fields_by_tag.get(tag_bytes, (None, None)) 

1389 if field_des is None: 

1390 if not self._unknown_fields: # pylint: disable=protected-access 

1391 self._unknown_fields = [] # pylint: disable=protected-access 

1392 field_number, wire_type = decoder.DecodeTag(tag_bytes) 

1393 if field_number == 0: 

1394 raise message_mod.DecodeError('Field number 0 is illegal.') 

1395 data, new_pos = decoder._DecodeUnknownField( 

1396 buffer, new_pos, end, field_number, wire_type 

1397 ) # pylint: disable=protected-access 

1398 if new_pos == -1: 

1399 return pos 

1400 self._unknown_fields.append( 

1401 (tag_bytes, buffer[pos + len(tag_bytes) : new_pos].tobytes()) 

1402 ) 

1403 pos = new_pos 

1404 else: 

1405 _MaybeAddDecoder(cls, field_des) 

1406 field_decoder = field_des._decoders[is_packed] 

1407 pos = field_decoder( 

1408 buffer, new_pos, end, self, field_dict, current_depth 

1409 ) 

1410 if field_des.containing_oneof: 

1411 self._UpdateOneofState(field_des) 

1412 return pos 

1413 

1414 cls._InternalParse = InternalParse 

1415 

1416 

1417def _AddIsInitializedMethod(message_descriptor, cls): 

1418 """Adds the IsInitialized and FindInitializationError methods to the 

1419 

1420 protocol message class. 

1421 """ 

1422 

1423 required_fields = [ 

1424 field for field in message_descriptor.fields if field.is_required 

1425 ] 

1426 

1427 def IsInitialized(self, errors=None): 

1428 """Checks if all required fields of a message are set. 

1429 

1430 Args: 

1431 errors: A list which, if provided, will be populated with the field paths 

1432 of all missing required fields. 

1433 

1434 Returns: 

1435 True iff the specified message has all required fields set. 

1436 """ 

1437 

1438 # Performance is critical so we avoid HasField() and ListFields(). 

1439 

1440 for field in required_fields: 

1441 if field not in self._fields or ( 

1442 field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE 

1443 and not self._fields[field]._is_present_in_parent 

1444 ): 

1445 if errors is not None: 

1446 errors.extend(self.FindInitializationErrors()) 

1447 return False 

1448 

1449 for field, value in list(self._fields.items()): # dict can change size! 

1450 if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

1451 if field.is_repeated: 

1452 if field.message_type._is_map_entry: 

1453 continue 

1454 for element in value: 

1455 if not element.IsInitialized(): 

1456 if errors is not None: 

1457 errors.extend(self.FindInitializationErrors()) 

1458 return False 

1459 elif value._is_present_in_parent and not value.IsInitialized(): 

1460 if errors is not None: 

1461 errors.extend(self.FindInitializationErrors()) 

1462 return False 

1463 

1464 return True 

1465 

1466 cls.IsInitialized = IsInitialized 

1467 

1468 def FindInitializationErrors(self): 

1469 """Finds required fields which are not initialized. 

1470 

1471 Returns: 

1472 A list of strings. Each string is a path to an uninitialized field from 

1473 the top-level message, e.g. "foo.bar[5].baz". 

1474 """ 

1475 

1476 errors = [] # simplify things 

1477 

1478 for field in required_fields: 

1479 if not self.HasField(field.name): 

1480 errors.append(field.name) 

1481 

1482 for field, value in self.ListFields(): 

1483 if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

1484 if field.is_extension: 

1485 name = '(%s)' % field.full_name 

1486 else: 

1487 name = field.name 

1488 

1489 if _IsMapField(field): 

1490 if _IsMessageMapField(field): 

1491 for key in value: 

1492 element = value[key] 

1493 prefix = '%s[%s].' % (name, key) 

1494 sub_errors = element.FindInitializationErrors() 

1495 errors += [prefix + error for error in sub_errors] 

1496 else: 

1497 # ScalarMaps can't have any initialization errors. 

1498 pass 

1499 elif field.is_repeated: 

1500 for i in range(len(value)): 

1501 element = value[i] 

1502 prefix = '%s[%d].' % (name, i) 

1503 sub_errors = element.FindInitializationErrors() 

1504 errors += [prefix + error for error in sub_errors] 

1505 else: 

1506 prefix = name + '.' 

1507 sub_errors = value.FindInitializationErrors() 

1508 errors += [prefix + error for error in sub_errors] 

1509 

1510 return errors 

1511 

1512 cls.FindInitializationErrors = FindInitializationErrors 

1513 

1514 

1515def _FullyQualifiedClassName(klass): 

1516 module = klass.__module__ 

1517 name = getattr(klass, '__qualname__', klass.__name__) 

1518 if module in (None, 'builtins', '__builtin__'): 

1519 return name 

1520 return module + '.' + name 

1521 

1522 

1523def _AddMergeFromMethod(cls): 

1524 CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE 

1525 

1526 def MergeFrom(self, msg): 

1527 self._AssureWritable() 

1528 if not isinstance(msg, cls): 

1529 raise TypeError( 

1530 'Parameter to MergeFrom() must be instance of same class: ' 

1531 'expected %s got %s.' 

1532 % ( 

1533 _FullyQualifiedClassName(cls), 

1534 _FullyQualifiedClassName(msg.__class__), 

1535 ) 

1536 ) 

1537 

1538 assert msg is not self 

1539 self._Modified() 

1540 

1541 fields = self._fields 

1542 

1543 for field, value in msg._fields.items(): 

1544 if field.is_repeated: 

1545 field_value = fields.get(field) 

1546 if field_value is None: 

1547 # Construct a new object to represent this field. 

1548 field_value = field._default_constructor(self) 

1549 fields[field] = field_value 

1550 field_value.MergeFrom(value) 

1551 elif field.cpp_type == CPPTYPE_MESSAGE: 

1552 if value._is_present_in_parent: 

1553 field_value = fields.get(field) 

1554 if field_value is None: 

1555 # Construct a new object to represent this field. 

1556 field_value = field._default_constructor(self) 

1557 fields[field] = field_value 

1558 field_value.MergeFrom(value) 

1559 else: 

1560 self._fields[field] = value 

1561 if field.containing_oneof: 

1562 self._UpdateOneofState(field) 

1563 

1564 if msg._unknown_fields: 

1565 if not self._unknown_fields: 

1566 self._unknown_fields = [] 

1567 self._unknown_fields.extend(msg._unknown_fields) 

1568 

1569 cls.MergeFrom = MergeFrom 

1570 

1571 

1572def _AddWhichOneofMethod(message_descriptor, cls): 

1573 

1574 def WhichOneof(self, oneof_name): 

1575 """Returns the name of the currently set field inside a oneof, or None.""" 

1576 try: 

1577 field = message_descriptor.oneofs_by_name[oneof_name] 

1578 except KeyError: 

1579 raise ValueError('Protocol message has no oneof "%s" field.' % oneof_name) 

1580 

1581 nested_field = self._oneofs.get(field, None) 

1582 if nested_field is not None and self.HasField(nested_field.name): 

1583 return nested_field.name 

1584 else: 

1585 return None 

1586 

1587 cls.WhichOneof = WhichOneof 

1588 

1589 

1590def _Clear(self): 

1591 self._AssureWritable() 

1592 # Clear fields. 

1593 self._fields = {} 

1594 self._unknown_fields = () 

1595 

1596 self._oneofs = {} 

1597 self._Modified() 

1598 

1599 

1600def _SetFrozen(self): 

1601 self._frozen = True 

1602 for value in self._fields.values(): 

1603 if hasattr(value, '_SetFrozen'): 

1604 value._SetFrozen() 

1605 

1606 

1607def _AssureWritable(self): 

1608 if self._frozen: 

1609 warnings.warn( 

1610 'Mutating messages or containers returned by GetOptions() is' 

1611 ' deprecated and will raise an exception in a future release.', 

1612 category=FutureWarning, 

1613 stacklevel=3, 

1614 ) 

1615 return self 

1616 

1617 

1618def _UnknownFields(self): 

1619 raise NotImplementedError( 

1620 'Please use the add-on feaure ' 

1621 'unknown_fields.UnknownFieldSet(message) in ' 

1622 'unknown_fields.py instead.' 

1623 ) 

1624 

1625 

1626def _DiscardUnknownFields(self): 

1627 self._AssureWritable() 

1628 self._unknown_fields = [] 

1629 for field, value in self.ListFields(): 

1630 if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: 

1631 if _IsMapField(field): 

1632 if _IsMessageMapField(field): 

1633 for key in value: 

1634 value[key].DiscardUnknownFields() 

1635 elif field.is_repeated: 

1636 for sub_message in value: 

1637 sub_message.DiscardUnknownFields() 

1638 else: 

1639 value.DiscardUnknownFields() 

1640 

1641 

1642def _SetListener(self, listener): 

1643 if listener is None: 

1644 self._listener = message_listener_mod.NullMessageListener() 

1645 else: 

1646 self._listener = listener 

1647 

1648 

1649def _AddMessageMethods(message_descriptor, cls): 

1650 """Adds implementations of all Message methods to cls.""" 

1651 _AddListFieldsMethod(message_descriptor, cls) 

1652 _AddHasFieldMethod(message_descriptor, cls) 

1653 _AddClearFieldMethod(message_descriptor, cls) 

1654 if message_descriptor.is_extendable: 

1655 _AddClearExtensionMethod(cls) 

1656 _AddHasExtensionMethod(cls) 

1657 _AddEqualsMethod(message_descriptor, cls) 

1658 _AddStrMethod(message_descriptor, cls) 

1659 _AddReprMethod(message_descriptor, cls) 

1660 _AddUnicodeMethod(message_descriptor, cls) 

1661 _AddContainsMethod(message_descriptor, cls) 

1662 _AddByteSizeMethod(message_descriptor, cls) 

1663 _AddSerializeToStringMethod(message_descriptor, cls) 

1664 _AddSerializePartialToStringMethod(message_descriptor, cls) 

1665 _AddMergeFromStringMethod(message_descriptor, cls) 

1666 _AddIsInitializedMethod(message_descriptor, cls) 

1667 _AddMergeFromMethod(cls) 

1668 _AddWhichOneofMethod(message_descriptor, cls) 

1669 # Adds methods which do not depend on cls. 

1670 cls.Clear = _Clear 

1671 cls.DiscardUnknownFields = _DiscardUnknownFields 

1672 cls._SetListener = _SetListener 

1673 cls._SetFrozen = _SetFrozen 

1674 cls._AssureWritable = _AssureWritable 

1675 

1676 

1677def _AddPrivateHelperMethods(message_descriptor, cls): 

1678 """Adds implementation of private helper methods to cls.""" 

1679 

1680 def Modified(self): 

1681 """Sets the _cached_byte_size_dirty bit to true, 

1682 

1683 and propagates this to our listener iff this was a state change. 

1684 """ 

1685 

1686 # Note: Some callers check _cached_byte_size_dirty before calling 

1687 # _Modified() as an extra optimization. So, if this method is ever 

1688 # changed such that it does stuff even when _cached_byte_size_dirty is 

1689 # already true, the callers need to be updated. 

1690 if not self._cached_byte_size_dirty: 

1691 self._cached_byte_size_dirty = True 

1692 self._listener_for_children.dirty = True 

1693 self._is_present_in_parent = True 

1694 self._listener.Modified() 

1695 

1696 def _UpdateOneofState(self, field): 

1697 """Sets field as the active field in its containing oneof. 

1698 

1699 Will also delete currently active field in the oneof, if it is different 

1700 from the argument. Does not mark the message as modified. 

1701 """ 

1702 other_field = self._oneofs.setdefault(field.containing_oneof, field) 

1703 if other_field is not field: 

1704 del self._fields[other_field] 

1705 self._oneofs[field.containing_oneof] = field 

1706 

1707 cls._Modified = Modified 

1708 cls.SetInParent = Modified 

1709 cls._UpdateOneofState = _UpdateOneofState 

1710 

1711 

1712class _Listener(object): 

1713 """MessageListener implementation that a parent message registers with its 

1714 

1715 child message. 

1716 

1717 In order to support semantics like: 

1718 

1719 foo.bar.baz.moo = 23 

1720 assert foo.HasField('bar') 

1721 

1722 ...child objects must have back references to their parents. 

1723 This helper class is at the heart of this support. 

1724 """ 

1725 

1726 def __init__(self, parent_message): 

1727 """Args: 

1728 

1729 parent_message: The message whose _Modified() method we should call when 

1730 we receive Modified() messages. 

1731 """ 

1732 # This listener establishes a back reference from a child (contained) object 

1733 # to its parent (containing) object. We make this a weak reference to avoid 

1734 # creating cyclic garbage when the client finishes with the 'parent' object 

1735 # in the tree. 

1736 if isinstance(parent_message, weakref.ProxyType): 

1737 self._parent_message_weakref = parent_message 

1738 else: 

1739 self._parent_message_weakref = weakref.proxy(parent_message) 

1740 

1741 # As an optimization, we also indicate directly on the listener whether 

1742 # or not the parent message is dirty. This way we can avoid traversing 

1743 # up the tree in the common case. 

1744 self.dirty = False 

1745 

1746 def Modified(self): 

1747 if self.dirty: 

1748 return 

1749 try: 

1750 # Propagate the signal to our parents iff this is the first field set. 

1751 self._parent_message_weakref._Modified() 

1752 except ReferenceError: 

1753 # We can get here if a client has kept a reference to a child object, 

1754 # and is now setting a field on it, but the child's parent has been 

1755 # garbage-collected. This is not an error. 

1756 pass 

1757 

1758 

1759class _OneofListener(_Listener): 

1760 """Special listener implementation for setting composite oneof fields.""" 

1761 

1762 def __init__(self, parent_message, field): 

1763 """Args: 

1764 

1765 parent_message: The message whose _Modified() method we should call when 

1766 we receive Modified() messages. 

1767 field: The descriptor of the field being set in the parent message. 

1768 """ 

1769 super(_OneofListener, self).__init__(parent_message) 

1770 self._field = field 

1771 

1772 def Modified(self): 

1773 """Also updates the state of the containing oneof in the parent message.""" 

1774 try: 

1775 self._parent_message_weakref._UpdateOneofState(self._field) 

1776 super(_OneofListener, self).Modified() 

1777 except ReferenceError: 

1778 pass