ortools.math_opt.python.normalize
Utility functions for normalizing proto3 message objects in Python.
1# Copyright 2010-2024 Google LLC 2# Licensed under the Apache License, Version 2.0 (the "License"); 3# you may not use this file except in compliance with the License. 4# You may obtain a copy of the License at 5# 6# http://www.apache.org/licenses/LICENSE-2.0 7# 8# Unless required by applicable law or agreed to in writing, software 9# distributed under the License is distributed on an "AS IS" BASIS, 10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11# See the License for the specific language governing permissions and 12# limitations under the License. 13 14# A fork of net/proto2/contrib/pyutil/normalize.py. A lot of the code can be 15# deleted because we do not support proto2 (no groups, no extension). Further, 16# the code has been changed to not clear: 17# * optional scalar fields at their default value. 18# * durations 19# * messages in a oneof 20 21 22"""Utility functions for normalizing proto3 message objects in Python.""" 23from google.protobuf import duration_pb2 24from google.protobuf import descriptor 25from google.protobuf import message 26 27 28def math_opt_normalize_proto(protobuf_message: message.Message) -> None: 29 """Clears all non-duration submessages that are not in one_ofs. 30 31 A message is considered `empty` if: 32 * every non-optional scalar fields has its default value, 33 * every optional scalar field is unset, 34 * every repeated/map fields is empty 35 * every oneof is unset, 36 * every duration field is unset 37 * all other message fields (singular, not oneof, not duration) are `empty`. 38 This function clears all `empty` fields from `message`. 39 40 This is useful for testing. 41 42 Args: 43 protobuf_message: The Message object to clear. 44 """ 45 for field, value in protobuf_message.ListFields(): 46 if field.type != field.TYPE_MESSAGE: 47 continue 48 if field.label == field.LABEL_REPEATED: 49 # Now the repeated case, recursively normalize each member. Note that 50 # there is no field presence for repeated fields, so we don't need to call 51 # ClearField(). 52 # 53 # Maps need to be handled specially. 54 if ( 55 field.message_type.has_options 56 and field.message_type.GetOptions().map_entry 57 ): 58 if ( 59 field.message_type.fields_by_number[2].type 60 == descriptor.FieldDescriptor.TYPE_MESSAGE 61 ): 62 for item in value.values(): 63 math_opt_normalize_proto(item) 64 # The remaining case is a regular repeated field (a list). 65 else: 66 for item in value: 67 math_opt_normalize_proto(item) 68 continue 69 # Last case, the non-repeated sub-message 70 math_opt_normalize_proto(value) 71 # If field value is empty, not a Duration, and not in a oneof, clear it. 72 if ( 73 not value.ListFields() 74 and field.message_type != duration_pb2.Duration.DESCRIPTOR 75 and field.containing_oneof is None 76 ): 77 protobuf_message.ClearField(field.name)
def
math_opt_normalize_proto(protobuf_message: google.protobuf.message.Message) -> None:
29def math_opt_normalize_proto(protobuf_message: message.Message) -> None: 30 """Clears all non-duration submessages that are not in one_ofs. 31 32 A message is considered `empty` if: 33 * every non-optional scalar fields has its default value, 34 * every optional scalar field is unset, 35 * every repeated/map fields is empty 36 * every oneof is unset, 37 * every duration field is unset 38 * all other message fields (singular, not oneof, not duration) are `empty`. 39 This function clears all `empty` fields from `message`. 40 41 This is useful for testing. 42 43 Args: 44 protobuf_message: The Message object to clear. 45 """ 46 for field, value in protobuf_message.ListFields(): 47 if field.type != field.TYPE_MESSAGE: 48 continue 49 if field.label == field.LABEL_REPEATED: 50 # Now the repeated case, recursively normalize each member. Note that 51 # there is no field presence for repeated fields, so we don't need to call 52 # ClearField(). 53 # 54 # Maps need to be handled specially. 55 if ( 56 field.message_type.has_options 57 and field.message_type.GetOptions().map_entry 58 ): 59 if ( 60 field.message_type.fields_by_number[2].type 61 == descriptor.FieldDescriptor.TYPE_MESSAGE 62 ): 63 for item in value.values(): 64 math_opt_normalize_proto(item) 65 # The remaining case is a regular repeated field (a list). 66 else: 67 for item in value: 68 math_opt_normalize_proto(item) 69 continue 70 # Last case, the non-repeated sub-message 71 math_opt_normalize_proto(value) 72 # If field value is empty, not a Duration, and not in a oneof, clear it. 73 if ( 74 not value.ListFields() 75 and field.message_type != duration_pb2.Duration.DESCRIPTOR 76 and field.containing_oneof is None 77 ): 78 protobuf_message.ClearField(field.name)
Clears all non-duration submessages that are not in one_ofs.
A message is considered empty
if:
- every non-optional scalar fields has its default value,
- every optional scalar field is unset,
- every repeated/map fields is empty
- every oneof is unset,
- every duration field is unset
- all other message fields (singular, not oneof, not duration) are
empty
. This function clears allempty
fields frommessage
.
This is useful for testing.
Arguments:
- protobuf_message: The Message object to clear.