Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/proto/fields.py: 89%
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
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
1# Copyright 2018 Google LLC
2#
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# https://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.
15from enum import EnumMeta
17from google.protobuf import descriptor_pb2
18from google.protobuf.internal.enum_type_wrapper import EnumTypeWrapper
20from proto.primitives import ProtoType
23class Field:
24 """A representation of a type of field in protocol buffers."""
26 # Fields are NOT repeated nor maps.
27 # The RepeatedField overrides this values.
28 repeated = False
30 def __init__(
31 self,
32 proto_type,
33 *,
34 number: int,
35 message=None,
36 enum=None,
37 oneof: str = None,
38 json_name: str = None,
39 optional: bool = False
40 ):
41 # This class is not intended to stand entirely alone;
42 # data is augmented by the metaclass for Message.
43 self.mcls_data = None
44 self.parent = None
46 # If the proto type sent is an object or a string, it is really
47 # a message or enum.
48 if not isinstance(proto_type, int):
49 # Note: We only support the "shortcut syntax" for enums
50 # when receiving the actual class.
51 if isinstance(proto_type, (EnumMeta, EnumTypeWrapper)):
52 enum = proto_type
53 proto_type = ProtoType.ENUM
54 else:
55 message = proto_type
56 proto_type = ProtoType.MESSAGE
58 # Save the direct arguments.
59 self.number = number
60 self.proto_type = proto_type
61 self.message = message
62 self.enum = enum
63 self.json_name = json_name
64 self.optional = optional
65 self.oneof = oneof
67 # Once the descriptor is accessed the first time, cache it.
68 # This is important because in rare cases the message or enum
69 # types are written later.
70 self._descriptor = None
72 @property
73 def descriptor(self):
74 """Return the descriptor for the field."""
75 if not self._descriptor:
76 # Resolve the message type, if any, to a string.
77 type_name = None
78 if isinstance(self.message, str):
79 if not self.message.startswith(self.package):
80 self.message = "{package}.{name}".format(
81 package=self.package,
82 name=self.message,
83 )
84 type_name = self.message
85 elif self.message:
86 type_name = (
87 self.message.DESCRIPTOR.full_name
88 if hasattr(self.message, "DESCRIPTOR")
89 else self.message._meta.full_name
90 )
91 elif isinstance(self.enum, str):
92 if not self.enum.startswith(self.package):
93 self.enum = "{package}.{name}".format(
94 package=self.package,
95 name=self.enum,
96 )
97 type_name = self.enum
98 elif self.enum:
99 type_name = (
100 self.enum.DESCRIPTOR.full_name
101 if hasattr(self.enum, "DESCRIPTOR")
102 else self.enum._meta.full_name
103 )
105 # Set the descriptor.
106 self._descriptor = descriptor_pb2.FieldDescriptorProto(
107 name=self.name,
108 number=self.number,
109 label=3 if self.repeated else 1,
110 type=self.proto_type,
111 type_name=type_name,
112 json_name=self.json_name,
113 proto3_optional=self.optional,
114 )
116 # Return the descriptor.
117 return self._descriptor
119 @property
120 def name(self) -> str:
121 """Return the name of the field."""
122 return self.mcls_data["name"]
124 @property
125 def package(self) -> str:
126 """Return the package of the field."""
127 return self.mcls_data["package"]
129 @property
130 def pb_type(self):
131 """Return the composite type of the field, or the primitive type if a primitive."""
132 # For enums, return the Python enum.
133 if self.enum:
134 return self.enum
136 # For primitive fields, we still want to know
137 # what the type is.
138 if not self.message:
139 return self.proto_type
141 # Return the internal protobuf message.
142 if hasattr(self.message, "_meta"):
143 return self.message.pb()
144 return self.message
147class RepeatedField(Field):
148 """A representation of a repeated field in protocol buffers."""
150 repeated = True
153class MapField(Field):
154 """A representation of a map field in protocol buffers."""
156 def __init__(self, key_type, value_type, *, number: int, message=None, enum=None):
157 super().__init__(value_type, number=number, message=message, enum=enum)
158 self.map_key_type = key_type
161__all__ = (
162 "Field",
163 "MapField",
164 "RepeatedField",
165)