Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
normalize.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# Copyright 2010-2025 Google LLC
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15# A fork of net/proto2/contrib/pyutil/normalize.py. A lot of the code can be
16# deleted because we do not support proto2 (no groups, no extension). Further,
17# the code has been changed to not clear:
18# * optional scalar fields at their default value.
19# * durations
20# * messages in a oneof
21
22
23"""Utility functions for normalizing proto3 message objects in Python."""
24from google.protobuf import duration_pb2
25from google.protobuf import descriptor
26from google.protobuf import message
27
28
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():
65 # The remaining case is a regular repeated field (a list).
66 else:
67 for item in value:
69 continue
70 # Last case, the non-repeated sub-message
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)
None math_opt_normalize_proto(message.Message protobuf_message)
Definition normalize.py:29