protobuf 6.33.0__cp39-abi3-manylinux2014_s390x.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of protobuf might be problematic. Click here for more details.
- google/_upb/_message.abi3.so +0 -0
- google/protobuf/__init__.py +10 -0
- google/protobuf/any.py +53 -0
- google/protobuf/any_pb2.py +37 -0
- google/protobuf/api_pb2.py +47 -0
- google/protobuf/compiler/__init__.py +0 -0
- google/protobuf/compiler/plugin_pb2.py +46 -0
- google/protobuf/descriptor.py +1676 -0
- google/protobuf/descriptor_database.py +172 -0
- google/protobuf/descriptor_pb2.py +3363 -0
- google/protobuf/descriptor_pool.py +1370 -0
- google/protobuf/duration.py +100 -0
- google/protobuf/duration_pb2.py +37 -0
- google/protobuf/empty_pb2.py +37 -0
- google/protobuf/field_mask_pb2.py +37 -0
- google/protobuf/internal/__init__.py +7 -0
- google/protobuf/internal/api_implementation.py +136 -0
- google/protobuf/internal/builder.py +118 -0
- google/protobuf/internal/containers.py +690 -0
- google/protobuf/internal/decoder.py +1066 -0
- google/protobuf/internal/encoder.py +806 -0
- google/protobuf/internal/enum_type_wrapper.py +112 -0
- google/protobuf/internal/extension_dict.py +194 -0
- google/protobuf/internal/field_mask.py +312 -0
- google/protobuf/internal/message_listener.py +55 -0
- google/protobuf/internal/python_edition_defaults.py +5 -0
- google/protobuf/internal/python_message.py +1599 -0
- google/protobuf/internal/testing_refleaks.py +128 -0
- google/protobuf/internal/type_checkers.py +455 -0
- google/protobuf/internal/well_known_types.py +695 -0
- google/protobuf/internal/wire_format.py +245 -0
- google/protobuf/json_format.py +1111 -0
- google/protobuf/message.py +448 -0
- google/protobuf/message_factory.py +190 -0
- google/protobuf/proto.py +153 -0
- google/protobuf/proto_builder.py +111 -0
- google/protobuf/proto_json.py +83 -0
- google/protobuf/proto_text.py +129 -0
- google/protobuf/pyext/__init__.py +0 -0
- google/protobuf/pyext/cpp_message.py +49 -0
- google/protobuf/reflection.py +36 -0
- google/protobuf/runtime_version.py +104 -0
- google/protobuf/service_reflection.py +272 -0
- google/protobuf/source_context_pb2.py +37 -0
- google/protobuf/struct_pb2.py +47 -0
- google/protobuf/symbol_database.py +179 -0
- google/protobuf/testdata/__init__.py +0 -0
- google/protobuf/text_encoding.py +106 -0
- google/protobuf/text_format.py +1884 -0
- google/protobuf/timestamp.py +112 -0
- google/protobuf/timestamp_pb2.py +37 -0
- google/protobuf/type_pb2.py +53 -0
- google/protobuf/unknown_fields.py +96 -0
- google/protobuf/util/__init__.py +0 -0
- google/protobuf/wrappers_pb2.py +53 -0
- protobuf-6.33.0.dist-info/LICENSE +32 -0
- protobuf-6.33.0.dist-info/METADATA +17 -0
- protobuf-6.33.0.dist-info/RECORD +59 -0
- protobuf-6.33.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,112 @@
|
|
|
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
|
+
"""A simple wrapper around enum types to expose utility functions.
|
|
9
|
+
|
|
10
|
+
Instances are created as properties with the same name as the enum they wrap
|
|
11
|
+
on proto classes. For usage, see:
|
|
12
|
+
reflection_test.py
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
__author__ = 'rabsatt@google.com (Kevin Rabsatt)'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EnumTypeWrapper(object):
|
|
21
|
+
"""A utility for finding the names of enum values."""
|
|
22
|
+
|
|
23
|
+
DESCRIPTOR = None
|
|
24
|
+
|
|
25
|
+
# This is a type alias, which mypy typing stubs can type as
|
|
26
|
+
# a genericized parameter constrained to an int, allowing subclasses
|
|
27
|
+
# to be typed with more constraint in .pyi stubs
|
|
28
|
+
# Eg.
|
|
29
|
+
# def MyGeneratedEnum(Message):
|
|
30
|
+
# ValueType = NewType('ValueType', int)
|
|
31
|
+
# def Name(self, number: MyGeneratedEnum.ValueType) -> str
|
|
32
|
+
ValueType = int
|
|
33
|
+
|
|
34
|
+
def __init__(self, enum_type):
|
|
35
|
+
"""Inits EnumTypeWrapper with an EnumDescriptor."""
|
|
36
|
+
self._enum_type = enum_type
|
|
37
|
+
self.DESCRIPTOR = enum_type # pylint: disable=invalid-name
|
|
38
|
+
|
|
39
|
+
def Name(self, number): # pylint: disable=invalid-name
|
|
40
|
+
"""Returns a string containing the name of an enum value."""
|
|
41
|
+
try:
|
|
42
|
+
return self._enum_type.values_by_number[number].name
|
|
43
|
+
except KeyError:
|
|
44
|
+
pass # fall out to break exception chaining
|
|
45
|
+
|
|
46
|
+
if not isinstance(number, int):
|
|
47
|
+
raise TypeError(
|
|
48
|
+
'Enum value for {} must be an int, but got {} {!r}.'.format(
|
|
49
|
+
self._enum_type.name, type(number), number))
|
|
50
|
+
else:
|
|
51
|
+
# repr here to handle the odd case when you pass in a boolean.
|
|
52
|
+
raise ValueError('Enum {} has no name defined for value {!r}'.format(
|
|
53
|
+
self._enum_type.name, number))
|
|
54
|
+
|
|
55
|
+
def Value(self, name): # pylint: disable=invalid-name
|
|
56
|
+
"""Returns the value corresponding to the given enum name."""
|
|
57
|
+
try:
|
|
58
|
+
return self._enum_type.values_by_name[name].number
|
|
59
|
+
except KeyError:
|
|
60
|
+
pass # fall out to break exception chaining
|
|
61
|
+
raise ValueError('Enum {} has no value defined for name {!r}'.format(
|
|
62
|
+
self._enum_type.name, name))
|
|
63
|
+
|
|
64
|
+
def keys(self):
|
|
65
|
+
"""Return a list of the string names in the enum.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
A list of strs, in the order they were defined in the .proto file.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
return [value_descriptor.name
|
|
72
|
+
for value_descriptor in self._enum_type.values]
|
|
73
|
+
|
|
74
|
+
def values(self):
|
|
75
|
+
"""Return a list of the integer values in the enum.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
A list of ints, in the order they were defined in the .proto file.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
return [value_descriptor.number
|
|
82
|
+
for value_descriptor in self._enum_type.values]
|
|
83
|
+
|
|
84
|
+
def items(self):
|
|
85
|
+
"""Return a list of the (name, value) pairs of the enum.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
A list of (str, int) pairs, in the order they were defined
|
|
89
|
+
in the .proto file.
|
|
90
|
+
"""
|
|
91
|
+
return [(value_descriptor.name, value_descriptor.number)
|
|
92
|
+
for value_descriptor in self._enum_type.values]
|
|
93
|
+
|
|
94
|
+
def __getattr__(self, name):
|
|
95
|
+
"""Returns the value corresponding to the given enum name."""
|
|
96
|
+
try:
|
|
97
|
+
return super(
|
|
98
|
+
EnumTypeWrapper,
|
|
99
|
+
self).__getattribute__('_enum_type').values_by_name[name].number
|
|
100
|
+
except KeyError:
|
|
101
|
+
pass # fall out to break exception chaining
|
|
102
|
+
raise AttributeError('Enum {} has no value defined for name {!r}'.format(
|
|
103
|
+
self._enum_type.name, name))
|
|
104
|
+
|
|
105
|
+
def __or__(self, other):
|
|
106
|
+
"""Returns the union type of self and other."""
|
|
107
|
+
if sys.version_info >= (3, 10):
|
|
108
|
+
return type(self) | other
|
|
109
|
+
else:
|
|
110
|
+
raise NotImplementedError(
|
|
111
|
+
'You may not use | on EnumTypes (or classes) below python 3.10'
|
|
112
|
+
)
|
|
@@ -0,0 +1,194 @@
|
|
|
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
|
+
"""Contains _ExtensionDict class to represent extensions.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from google.protobuf.internal import type_checkers
|
|
12
|
+
from google.protobuf.descriptor import FieldDescriptor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _VerifyExtensionHandle(message, extension_handle):
|
|
16
|
+
"""Verify that the given extension handle is valid."""
|
|
17
|
+
|
|
18
|
+
if not isinstance(extension_handle, FieldDescriptor):
|
|
19
|
+
raise KeyError('HasExtension() expects an extension handle, got: %s' %
|
|
20
|
+
extension_handle)
|
|
21
|
+
|
|
22
|
+
if not extension_handle.is_extension:
|
|
23
|
+
raise KeyError('"%s" is not an extension.' % extension_handle.full_name)
|
|
24
|
+
|
|
25
|
+
if not extension_handle.containing_type:
|
|
26
|
+
raise KeyError('"%s" is missing a containing_type.'
|
|
27
|
+
% extension_handle.full_name)
|
|
28
|
+
|
|
29
|
+
if extension_handle.containing_type is not message.DESCRIPTOR:
|
|
30
|
+
raise KeyError('Extension "%s" extends message type "%s", but this '
|
|
31
|
+
'message is of type "%s".' %
|
|
32
|
+
(extension_handle.full_name,
|
|
33
|
+
extension_handle.containing_type.full_name,
|
|
34
|
+
message.DESCRIPTOR.full_name))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# TODO: Unify error handling of "unknown extension" crap.
|
|
38
|
+
# TODO: Support iteritems()-style iteration over all
|
|
39
|
+
# extensions with the "has" bits turned on?
|
|
40
|
+
class _ExtensionDict(object):
|
|
41
|
+
|
|
42
|
+
"""Dict-like container for Extension fields on proto instances.
|
|
43
|
+
|
|
44
|
+
Note that in all cases we expect extension handles to be
|
|
45
|
+
FieldDescriptors.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(self, extended_message):
|
|
49
|
+
"""
|
|
50
|
+
Args:
|
|
51
|
+
extended_message: Message instance for which we are the Extensions dict.
|
|
52
|
+
"""
|
|
53
|
+
self._extended_message = extended_message
|
|
54
|
+
|
|
55
|
+
def __getitem__(self, extension_handle):
|
|
56
|
+
"""Returns the current value of the given extension handle."""
|
|
57
|
+
|
|
58
|
+
_VerifyExtensionHandle(self._extended_message, extension_handle)
|
|
59
|
+
|
|
60
|
+
result = self._extended_message._fields.get(extension_handle)
|
|
61
|
+
if result is not None:
|
|
62
|
+
return result
|
|
63
|
+
|
|
64
|
+
if extension_handle.is_repeated:
|
|
65
|
+
result = extension_handle._default_constructor(self._extended_message)
|
|
66
|
+
elif extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
|
|
67
|
+
message_type = extension_handle.message_type
|
|
68
|
+
if not hasattr(message_type, '_concrete_class'):
|
|
69
|
+
# pylint: disable=g-import-not-at-top
|
|
70
|
+
from google.protobuf import message_factory
|
|
71
|
+
message_factory.GetMessageClass(message_type)
|
|
72
|
+
if not hasattr(extension_handle.message_type, '_concrete_class'):
|
|
73
|
+
from google.protobuf import message_factory
|
|
74
|
+
message_factory.GetMessageClass(extension_handle.message_type)
|
|
75
|
+
result = extension_handle.message_type._concrete_class()
|
|
76
|
+
try:
|
|
77
|
+
result._SetListener(self._extended_message._listener_for_children)
|
|
78
|
+
except ReferenceError:
|
|
79
|
+
pass
|
|
80
|
+
else:
|
|
81
|
+
# Singular scalar -- just return the default without inserting into the
|
|
82
|
+
# dict.
|
|
83
|
+
return extension_handle.default_value
|
|
84
|
+
|
|
85
|
+
# Atomically check if another thread has preempted us and, if not, swap
|
|
86
|
+
# in the new object we just created. If someone has preempted us, we
|
|
87
|
+
# take that object and discard ours.
|
|
88
|
+
# WARNING: We are relying on setdefault() being atomic. This is true
|
|
89
|
+
# in CPython but we haven't investigated others. This warning appears
|
|
90
|
+
# in several other locations in this file.
|
|
91
|
+
result = self._extended_message._fields.setdefault(
|
|
92
|
+
extension_handle, result)
|
|
93
|
+
|
|
94
|
+
return result
|
|
95
|
+
|
|
96
|
+
def __eq__(self, other):
|
|
97
|
+
if not isinstance(other, self.__class__):
|
|
98
|
+
return False
|
|
99
|
+
|
|
100
|
+
my_fields = self._extended_message.ListFields()
|
|
101
|
+
other_fields = other._extended_message.ListFields()
|
|
102
|
+
|
|
103
|
+
# Get rid of non-extension fields.
|
|
104
|
+
my_fields = [field for field in my_fields if field.is_extension]
|
|
105
|
+
other_fields = [field for field in other_fields if field.is_extension]
|
|
106
|
+
|
|
107
|
+
return my_fields == other_fields
|
|
108
|
+
|
|
109
|
+
def __ne__(self, other):
|
|
110
|
+
return not self == other
|
|
111
|
+
|
|
112
|
+
def __len__(self):
|
|
113
|
+
fields = self._extended_message.ListFields()
|
|
114
|
+
# Get rid of non-extension fields.
|
|
115
|
+
extension_fields = [field for field in fields if field[0].is_extension]
|
|
116
|
+
return len(extension_fields)
|
|
117
|
+
|
|
118
|
+
def __hash__(self):
|
|
119
|
+
raise TypeError('unhashable object')
|
|
120
|
+
|
|
121
|
+
# Note that this is only meaningful for non-repeated, scalar extension
|
|
122
|
+
# fields. Note also that we may have to call _Modified() when we do
|
|
123
|
+
# successfully set a field this way, to set any necessary "has" bits in the
|
|
124
|
+
# ancestors of the extended message.
|
|
125
|
+
def __setitem__(self, extension_handle, value):
|
|
126
|
+
"""If extension_handle specifies a non-repeated, scalar extension
|
|
127
|
+
field, sets the value of that field.
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
_VerifyExtensionHandle(self._extended_message, extension_handle)
|
|
131
|
+
|
|
132
|
+
if (extension_handle.is_repeated or
|
|
133
|
+
extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE):
|
|
134
|
+
raise TypeError(
|
|
135
|
+
'Cannot assign to extension "%s" because it is a repeated or '
|
|
136
|
+
'composite type.' % extension_handle.full_name)
|
|
137
|
+
|
|
138
|
+
# It's slightly wasteful to lookup the type checker each time,
|
|
139
|
+
# but we expect this to be a vanishingly uncommon case anyway.
|
|
140
|
+
type_checker = type_checkers.GetTypeChecker(extension_handle)
|
|
141
|
+
# pylint: disable=protected-access
|
|
142
|
+
self._extended_message._fields[extension_handle] = (
|
|
143
|
+
type_checker.CheckValue(value))
|
|
144
|
+
self._extended_message._Modified()
|
|
145
|
+
|
|
146
|
+
def __delitem__(self, extension_handle):
|
|
147
|
+
self._extended_message.ClearExtension(extension_handle)
|
|
148
|
+
|
|
149
|
+
def _FindExtensionByName(self, name):
|
|
150
|
+
"""Tries to find a known extension with the specified name.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
name: Extension full name.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Extension field descriptor.
|
|
157
|
+
"""
|
|
158
|
+
descriptor = self._extended_message.DESCRIPTOR
|
|
159
|
+
extensions = descriptor.file.pool._extensions_by_name[descriptor]
|
|
160
|
+
return extensions.get(name, None)
|
|
161
|
+
|
|
162
|
+
def _FindExtensionByNumber(self, number):
|
|
163
|
+
"""Tries to find a known extension with the field number.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
number: Extension field number.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
Extension field descriptor.
|
|
170
|
+
"""
|
|
171
|
+
descriptor = self._extended_message.DESCRIPTOR
|
|
172
|
+
extensions = descriptor.file.pool._extensions_by_number[descriptor]
|
|
173
|
+
return extensions.get(number, None)
|
|
174
|
+
|
|
175
|
+
def __iter__(self):
|
|
176
|
+
# Return a generator over the populated extension fields
|
|
177
|
+
return (f[0] for f in self._extended_message.ListFields()
|
|
178
|
+
if f[0].is_extension)
|
|
179
|
+
|
|
180
|
+
def __contains__(self, extension_handle):
|
|
181
|
+
_VerifyExtensionHandle(self._extended_message, extension_handle)
|
|
182
|
+
|
|
183
|
+
if extension_handle not in self._extended_message._fields:
|
|
184
|
+
return False
|
|
185
|
+
|
|
186
|
+
if extension_handle.is_repeated:
|
|
187
|
+
return bool(self._extended_message._fields.get(extension_handle))
|
|
188
|
+
|
|
189
|
+
if extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
|
|
190
|
+
value = self._extended_message._fields.get(extension_handle)
|
|
191
|
+
# pylint: disable=protected-access
|
|
192
|
+
return value is not None and value._is_present_in_parent
|
|
193
|
+
|
|
194
|
+
return True
|
|
@@ -0,0 +1,312 @@
|
|
|
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
|
+
"""Contains FieldMask class."""
|
|
9
|
+
|
|
10
|
+
from google.protobuf.descriptor import FieldDescriptor
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FieldMask(object):
|
|
14
|
+
"""Class for FieldMask message type."""
|
|
15
|
+
|
|
16
|
+
__slots__ = ()
|
|
17
|
+
|
|
18
|
+
def ToJsonString(self):
|
|
19
|
+
"""Converts FieldMask to string according to proto3 JSON spec."""
|
|
20
|
+
camelcase_paths = []
|
|
21
|
+
for path in self.paths:
|
|
22
|
+
camelcase_paths.append(_SnakeCaseToCamelCase(path))
|
|
23
|
+
return ','.join(camelcase_paths)
|
|
24
|
+
|
|
25
|
+
def FromJsonString(self, value):
|
|
26
|
+
"""Converts string to FieldMask according to proto3 JSON spec."""
|
|
27
|
+
if not isinstance(value, str):
|
|
28
|
+
raise ValueError('FieldMask JSON value not a string: {!r}'.format(value))
|
|
29
|
+
self.Clear()
|
|
30
|
+
if value:
|
|
31
|
+
for path in value.split(','):
|
|
32
|
+
self.paths.append(_CamelCaseToSnakeCase(path))
|
|
33
|
+
|
|
34
|
+
def IsValidForDescriptor(self, message_descriptor):
|
|
35
|
+
"""Checks whether the FieldMask is valid for Message Descriptor."""
|
|
36
|
+
for path in self.paths:
|
|
37
|
+
if not _IsValidPath(message_descriptor, path):
|
|
38
|
+
return False
|
|
39
|
+
return True
|
|
40
|
+
|
|
41
|
+
def AllFieldsFromDescriptor(self, message_descriptor):
|
|
42
|
+
"""Gets all direct fields of Message Descriptor to FieldMask."""
|
|
43
|
+
self.Clear()
|
|
44
|
+
for field in message_descriptor.fields:
|
|
45
|
+
self.paths.append(field.name)
|
|
46
|
+
|
|
47
|
+
def CanonicalFormFromMask(self, mask):
|
|
48
|
+
"""Converts a FieldMask to the canonical form.
|
|
49
|
+
|
|
50
|
+
Removes paths that are covered by another path. For example,
|
|
51
|
+
"foo.bar" is covered by "foo" and will be removed if "foo"
|
|
52
|
+
is also in the FieldMask. Then sorts all paths in alphabetical order.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
mask: The original FieldMask to be converted.
|
|
56
|
+
"""
|
|
57
|
+
tree = _FieldMaskTree(mask)
|
|
58
|
+
tree.ToFieldMask(self)
|
|
59
|
+
|
|
60
|
+
def Union(self, mask1, mask2):
|
|
61
|
+
"""Merges mask1 and mask2 into this FieldMask."""
|
|
62
|
+
_CheckFieldMaskMessage(mask1)
|
|
63
|
+
_CheckFieldMaskMessage(mask2)
|
|
64
|
+
tree = _FieldMaskTree(mask1)
|
|
65
|
+
tree.MergeFromFieldMask(mask2)
|
|
66
|
+
tree.ToFieldMask(self)
|
|
67
|
+
|
|
68
|
+
def Intersect(self, mask1, mask2):
|
|
69
|
+
"""Intersects mask1 and mask2 into this FieldMask."""
|
|
70
|
+
_CheckFieldMaskMessage(mask1)
|
|
71
|
+
_CheckFieldMaskMessage(mask2)
|
|
72
|
+
tree = _FieldMaskTree(mask1)
|
|
73
|
+
intersection = _FieldMaskTree()
|
|
74
|
+
for path in mask2.paths:
|
|
75
|
+
tree.IntersectPath(path, intersection)
|
|
76
|
+
intersection.ToFieldMask(self)
|
|
77
|
+
|
|
78
|
+
def MergeMessage(
|
|
79
|
+
self, source, destination,
|
|
80
|
+
replace_message_field=False, replace_repeated_field=False):
|
|
81
|
+
"""Merges fields specified in FieldMask from source to destination.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
source: Source message.
|
|
85
|
+
destination: The destination message to be merged into.
|
|
86
|
+
replace_message_field: Replace message field if True. Merge message
|
|
87
|
+
field if False.
|
|
88
|
+
replace_repeated_field: Replace repeated field if True. Append
|
|
89
|
+
elements of repeated field if False.
|
|
90
|
+
"""
|
|
91
|
+
tree = _FieldMaskTree(self)
|
|
92
|
+
tree.MergeMessage(
|
|
93
|
+
source, destination, replace_message_field, replace_repeated_field)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _IsValidPath(message_descriptor, path):
|
|
97
|
+
"""Checks whether the path is valid for Message Descriptor."""
|
|
98
|
+
parts = path.split('.')
|
|
99
|
+
last = parts.pop()
|
|
100
|
+
for name in parts:
|
|
101
|
+
field = message_descriptor.fields_by_name.get(name)
|
|
102
|
+
if (field is None or
|
|
103
|
+
field.is_repeated or
|
|
104
|
+
field.type != FieldDescriptor.TYPE_MESSAGE):
|
|
105
|
+
return False
|
|
106
|
+
message_descriptor = field.message_type
|
|
107
|
+
return last in message_descriptor.fields_by_name
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _CheckFieldMaskMessage(message):
|
|
111
|
+
"""Raises ValueError if message is not a FieldMask."""
|
|
112
|
+
message_descriptor = message.DESCRIPTOR
|
|
113
|
+
if (message_descriptor.name != 'FieldMask' or
|
|
114
|
+
message_descriptor.file.name != 'google/protobuf/field_mask.proto'):
|
|
115
|
+
raise ValueError('Message {0} is not a FieldMask.'.format(
|
|
116
|
+
message_descriptor.full_name))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _SnakeCaseToCamelCase(path_name):
|
|
120
|
+
"""Converts a path name from snake_case to camelCase."""
|
|
121
|
+
result = []
|
|
122
|
+
after_underscore = False
|
|
123
|
+
for c in path_name:
|
|
124
|
+
if c.isupper():
|
|
125
|
+
raise ValueError(
|
|
126
|
+
'Fail to print FieldMask to Json string: Path name '
|
|
127
|
+
'{0} must not contain uppercase letters.'.format(path_name))
|
|
128
|
+
if after_underscore:
|
|
129
|
+
if c.islower():
|
|
130
|
+
result.append(c.upper())
|
|
131
|
+
after_underscore = False
|
|
132
|
+
else:
|
|
133
|
+
raise ValueError(
|
|
134
|
+
'Fail to print FieldMask to Json string: The '
|
|
135
|
+
'character after a "_" must be a lowercase letter '
|
|
136
|
+
'in path name {0}.'.format(path_name))
|
|
137
|
+
elif c == '_':
|
|
138
|
+
after_underscore = True
|
|
139
|
+
else:
|
|
140
|
+
result += c
|
|
141
|
+
|
|
142
|
+
if after_underscore:
|
|
143
|
+
raise ValueError('Fail to print FieldMask to Json string: Trailing "_" '
|
|
144
|
+
'in path name {0}.'.format(path_name))
|
|
145
|
+
return ''.join(result)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _CamelCaseToSnakeCase(path_name):
|
|
149
|
+
"""Converts a field name from camelCase to snake_case."""
|
|
150
|
+
result = []
|
|
151
|
+
for c in path_name:
|
|
152
|
+
if c == '_':
|
|
153
|
+
raise ValueError('Fail to parse FieldMask: Path name '
|
|
154
|
+
'{0} must not contain "_"s.'.format(path_name))
|
|
155
|
+
if c.isupper():
|
|
156
|
+
result += '_'
|
|
157
|
+
result += c.lower()
|
|
158
|
+
else:
|
|
159
|
+
result += c
|
|
160
|
+
return ''.join(result)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class _FieldMaskTree(object):
|
|
164
|
+
"""Represents a FieldMask in a tree structure.
|
|
165
|
+
|
|
166
|
+
For example, given a FieldMask "foo.bar,foo.baz,bar.baz",
|
|
167
|
+
the FieldMaskTree will be:
|
|
168
|
+
[_root] -+- foo -+- bar
|
|
169
|
+
| |
|
|
170
|
+
| +- baz
|
|
171
|
+
|
|
|
172
|
+
+- bar --- baz
|
|
173
|
+
In the tree, each leaf node represents a field path.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
__slots__ = ('_root',)
|
|
177
|
+
|
|
178
|
+
def __init__(self, field_mask=None):
|
|
179
|
+
"""Initializes the tree by FieldMask."""
|
|
180
|
+
self._root = {}
|
|
181
|
+
if field_mask:
|
|
182
|
+
self.MergeFromFieldMask(field_mask)
|
|
183
|
+
|
|
184
|
+
def MergeFromFieldMask(self, field_mask):
|
|
185
|
+
"""Merges a FieldMask to the tree."""
|
|
186
|
+
for path in field_mask.paths:
|
|
187
|
+
self.AddPath(path)
|
|
188
|
+
|
|
189
|
+
def AddPath(self, path):
|
|
190
|
+
"""Adds a field path into the tree.
|
|
191
|
+
|
|
192
|
+
If the field path to add is a sub-path of an existing field path
|
|
193
|
+
in the tree (i.e., a leaf node), it means the tree already matches
|
|
194
|
+
the given path so nothing will be added to the tree. If the path
|
|
195
|
+
matches an existing non-leaf node in the tree, that non-leaf node
|
|
196
|
+
will be turned into a leaf node with all its children removed because
|
|
197
|
+
the path matches all the node's children. Otherwise, a new path will
|
|
198
|
+
be added.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
path: The field path to add.
|
|
202
|
+
"""
|
|
203
|
+
node = self._root
|
|
204
|
+
for name in path.split('.'):
|
|
205
|
+
if name not in node:
|
|
206
|
+
node[name] = {}
|
|
207
|
+
elif not node[name]:
|
|
208
|
+
# Pre-existing empty node implies we already have this entire tree.
|
|
209
|
+
return
|
|
210
|
+
node = node[name]
|
|
211
|
+
# Remove any sub-trees we might have had.
|
|
212
|
+
node.clear()
|
|
213
|
+
|
|
214
|
+
def ToFieldMask(self, field_mask):
|
|
215
|
+
"""Converts the tree to a FieldMask."""
|
|
216
|
+
field_mask.Clear()
|
|
217
|
+
_AddFieldPaths(self._root, '', field_mask)
|
|
218
|
+
|
|
219
|
+
def IntersectPath(self, path, intersection):
|
|
220
|
+
"""Calculates the intersection part of a field path with this tree.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
path: The field path to calculates.
|
|
224
|
+
intersection: The out tree to record the intersection part.
|
|
225
|
+
"""
|
|
226
|
+
node = self._root
|
|
227
|
+
for name in path.split('.'):
|
|
228
|
+
if name not in node:
|
|
229
|
+
return
|
|
230
|
+
elif not node[name]:
|
|
231
|
+
intersection.AddPath(path)
|
|
232
|
+
return
|
|
233
|
+
node = node[name]
|
|
234
|
+
intersection.AddLeafNodes(path, node)
|
|
235
|
+
|
|
236
|
+
def AddLeafNodes(self, prefix, node):
|
|
237
|
+
"""Adds leaf nodes begin with prefix to this tree."""
|
|
238
|
+
if not node:
|
|
239
|
+
self.AddPath(prefix)
|
|
240
|
+
for name in node:
|
|
241
|
+
child_path = prefix + '.' + name
|
|
242
|
+
self.AddLeafNodes(child_path, node[name])
|
|
243
|
+
|
|
244
|
+
def MergeMessage(
|
|
245
|
+
self, source, destination,
|
|
246
|
+
replace_message, replace_repeated):
|
|
247
|
+
"""Merge all fields specified by this tree from source to destination."""
|
|
248
|
+
_MergeMessage(
|
|
249
|
+
self._root, source, destination, replace_message, replace_repeated)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _StrConvert(value):
|
|
253
|
+
"""Converts value to str if it is not."""
|
|
254
|
+
# This file is imported by c extension and some methods like ClearField
|
|
255
|
+
# requires string for the field name. py2/py3 has different text
|
|
256
|
+
# type and may use unicode.
|
|
257
|
+
if not isinstance(value, str):
|
|
258
|
+
return value.encode('utf-8')
|
|
259
|
+
return value
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _MergeMessage(
|
|
263
|
+
node, source, destination, replace_message, replace_repeated):
|
|
264
|
+
"""Merge all fields specified by a sub-tree from source to destination."""
|
|
265
|
+
source_descriptor = source.DESCRIPTOR
|
|
266
|
+
for name in node:
|
|
267
|
+
child = node[name]
|
|
268
|
+
field = source_descriptor.fields_by_name[name]
|
|
269
|
+
if field is None:
|
|
270
|
+
raise ValueError('Error: Can\'t find field {0} in message {1}.'.format(
|
|
271
|
+
name, source_descriptor.full_name))
|
|
272
|
+
if child:
|
|
273
|
+
# Sub-paths are only allowed for singular message fields.
|
|
274
|
+
if (field.is_repeated or
|
|
275
|
+
field.cpp_type != FieldDescriptor.CPPTYPE_MESSAGE):
|
|
276
|
+
raise ValueError('Error: Field {0} in message {1} is not a singular '
|
|
277
|
+
'message field and cannot have sub-fields.'.format(
|
|
278
|
+
name, source_descriptor.full_name))
|
|
279
|
+
if source.HasField(name):
|
|
280
|
+
_MergeMessage(
|
|
281
|
+
child, getattr(source, name), getattr(destination, name),
|
|
282
|
+
replace_message, replace_repeated)
|
|
283
|
+
continue
|
|
284
|
+
if field.is_repeated:
|
|
285
|
+
if replace_repeated:
|
|
286
|
+
destination.ClearField(_StrConvert(name))
|
|
287
|
+
repeated_source = getattr(source, name)
|
|
288
|
+
repeated_destination = getattr(destination, name)
|
|
289
|
+
repeated_destination.MergeFrom(repeated_source)
|
|
290
|
+
else:
|
|
291
|
+
if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
|
|
292
|
+
if replace_message:
|
|
293
|
+
destination.ClearField(_StrConvert(name))
|
|
294
|
+
if source.HasField(name):
|
|
295
|
+
getattr(destination, name).MergeFrom(getattr(source, name))
|
|
296
|
+
elif not field.has_presence or source.HasField(name):
|
|
297
|
+
setattr(destination, name, getattr(source, name))
|
|
298
|
+
else:
|
|
299
|
+
destination.ClearField(_StrConvert(name))
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _AddFieldPaths(node, prefix, field_mask):
|
|
303
|
+
"""Adds the field paths descended from node to field_mask."""
|
|
304
|
+
if not node and prefix:
|
|
305
|
+
field_mask.paths.append(prefix)
|
|
306
|
+
return
|
|
307
|
+
for name in sorted(node):
|
|
308
|
+
if prefix:
|
|
309
|
+
child_path = prefix + '.' + name
|
|
310
|
+
else:
|
|
311
|
+
child_path = name
|
|
312
|
+
_AddFieldPaths(node[name], child_path, field_mask)
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
"""Defines a listener interface for observing certain
|
|
9
|
+
state transitions on Message objects.
|
|
10
|
+
|
|
11
|
+
Also defines a null implementation of this interface.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__author__ = 'robinson@google.com (Will Robinson)'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MessageListener(object):
|
|
18
|
+
|
|
19
|
+
"""Listens for modifications made to a message. Meant to be registered via
|
|
20
|
+
Message._SetListener().
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
dirty: If True, then calling Modified() would be a no-op. This can be
|
|
24
|
+
used to avoid these calls entirely in the common case.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def Modified(self):
|
|
28
|
+
"""Called every time the message is modified in such a way that the parent
|
|
29
|
+
message may need to be updated. This currently means either:
|
|
30
|
+
(a) The message was modified for the first time, so the parent message
|
|
31
|
+
should henceforth mark the message as present.
|
|
32
|
+
(b) The message's cached byte size became dirty -- i.e. the message was
|
|
33
|
+
modified for the first time after a previous call to ByteSize().
|
|
34
|
+
Therefore the parent should also mark its byte size as dirty.
|
|
35
|
+
Note that (a) implies (b), since new objects start out with a client cached
|
|
36
|
+
size (zero). However, we document (a) explicitly because it is important.
|
|
37
|
+
|
|
38
|
+
Modified() will *only* be called in response to one of these two events --
|
|
39
|
+
not every time the sub-message is modified.
|
|
40
|
+
|
|
41
|
+
Note that if the listener's |dirty| attribute is true, then calling
|
|
42
|
+
Modified at the moment would be a no-op, so it can be skipped. Performance-
|
|
43
|
+
sensitive callers should check this attribute directly before calling since
|
|
44
|
+
it will be true most of the time.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
raise NotImplementedError
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class NullMessageListener(object):
|
|
51
|
+
|
|
52
|
+
"""No-op MessageListener implementation."""
|
|
53
|
+
|
|
54
|
+
def Modified(self):
|
|
55
|
+
pass
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This file contains the serialized FeatureSetDefaults object corresponding to
|
|
3
|
+
the Pure Python runtime. This is used for feature resolution under Editions.
|
|
4
|
+
"""
|
|
5
|
+
_PROTOBUF_INTERNAL_PYTHON_EDITION_DEFAULTS = b"\n\027\030\204\007\"\000*\020\010\001\020\002\030\002 \003(\0010\0028\002@\001\n\027\030\347\007\"\000*\020\010\002\020\001\030\001 \002(\0010\0018\002@\001\n\027\030\350\007\"\014\010\001\020\001\030\001 \002(\0010\001*\0048\002@\001\n\027\030\351\007\"\020\010\001\020\001\030\001 \002(\0010\0018\001@\002*\000 \346\007(\351\007"
|