1313# limitations under the License.
1414from __future__ import annotations
1515
16- from typing import Any , Callable , Dict , Type
16+ from typing import Any , Callable , Dict , Type , Union , Optional
17+ from typing_extensions import TypeAlias
1718
1819from google .protobuf .message import Message
1920from google .protobuf .internal .enum_type_wrapper import EnumTypeWrapper
@@ -43,7 +44,7 @@ def _parse_array_type(
4344 value : PBValue ,
4445 metadata_type : SqlType .Array ,
4546 column_name : str | None ,
46- column_info : dict [str , Any ] | None = None ,
47+ column_info : dict [str , Union [ Message , EnumTypeWrapper ] ] | None = None ,
4748) -> Any :
4849 """
4950 used for parsing an array represented as a protobuf to a python list.
@@ -62,7 +63,7 @@ def _parse_map_type(
6263 value : PBValue ,
6364 metadata_type : SqlType .Map ,
6465 column_name : str | None ,
65- column_info : dict [str , Any ] | None = None ,
66+ column_info : dict [str , Union [ Message , EnumTypeWrapper ] ] | None = None ,
6667) -> Any :
6768 """
6869 used for parsing a map represented as a protobuf to a python dict.
@@ -103,7 +104,7 @@ def _parse_struct_type(
103104 value : PBValue ,
104105 metadata_type : SqlType .Struct ,
105106 column_name : str | None ,
106- column_info : dict [str , Any ] | None = None ,
107+ column_info : dict [str , Union [ Message , EnumTypeWrapper ] ] | None = None ,
107108) -> Struct :
108109 """
109110 used for parsing a struct represented as a protobuf to a
@@ -137,7 +138,7 @@ def _parse_timestamp_type(
137138 value : PBValue ,
138139 metadata_type : SqlType .Timestamp ,
139140 column_name : str | None ,
140- column_info : dict [str , Any ] | None = None ,
141+ column_info : dict [str , Union [ Message , EnumTypeWrapper ] ] | None = None ,
141142) -> DatetimeWithNanoseconds :
142143 """
143144 used for parsing a timestamp represented as a protobuf to DatetimeWithNanoseconds
@@ -149,10 +150,26 @@ def _parse_proto_type(
149150 value : PBValue ,
150151 metadata_type : SqlType .Proto ,
151152 column_name : str | None ,
152- column_info : dict [str , Any ] | None = None ,
153+ column_info : dict [str , Union [ Message , EnumTypeWrapper ] ] | None = None ,
153154) -> Message | bytes :
154155 """
155- Parses a serialized protobuf message into a Message object.
156+ Parses a serialized protobuf message into a Message object using type information
157+ provided in column_info.
158+
159+ Args:
160+ value: The value to parse, expected to have a bytes_value attribute.
161+ metadata_type: The expected SQL type (Proto).
162+ column_name: The name of the column.
163+ column_info: (Optional) A dictionary mapping column names to their
164+ corresponding Protobuf Message classes. This information is used
165+ to deserialize the raw bytes.
166+
167+ Returns:
168+ A deserialized Protobuf Message object if parsing is successful.
169+ If parsing fails for any reason, or if the required type information
170+ is not found in column_info, the function returns the original
171+ serialized data as bytes (value.bytes_value). This fallback
172+ ensures that the raw data is still accessible.
156173 """
157174 if (
158175 column_name is not None
@@ -171,10 +188,27 @@ def _parse_enum_type(
171188 value : PBValue ,
172189 metadata_type : SqlType .Enum ,
173190 column_name : str | None ,
174- column_info : dict [str , Any ] | None = None ,
175- ) -> int | Any :
191+ column_info : dict [str , Union [ Message , EnumTypeWrapper ] ] | None = None ,
192+ ) -> int | str :
176193 """
177- Parses an integer value into a Protobuf enum.
194+ Parses an integer value into a Protobuf enum name string using type information
195+ provided in column_info.
196+
197+ Args:
198+ value: The value to parse, expected to have an int_value attribute.
199+ metadata_type: The expected SQL type (Enum).
200+ column_name: The name of the column.
201+ column_info: (Optional) A dictionary mapping column names to their
202+ corresponding Protobuf EnumTypeWrapper objects. This information
203+ is used to convert the integer to an enum name.
204+
205+ Returns:
206+ A string representing the name of the enum value if conversion is successful.
207+ If conversion fails for any reason, such as the required EnumTypeWrapper
208+ not being found in column_info, or if an error occurs during the name lookup
209+ (e.g., the integer is not a valid enum value), the function returns the
210+ original integer value (value.int_value). This fallback ensures the
211+ raw integer representation is still accessible.
178212 """
179213 if (
180214 column_name is not None
@@ -187,9 +221,12 @@ def _parse_enum_type(
187221 return value .int_value
188222
189223
190- _TYPE_PARSERS : Dict [
191- Type [SqlType .Type ], Callable [[PBValue , Any , str | None , dict [str , Any ] | None ], Any ]
192- ] = {
224+ ParserCallable : TypeAlias = Callable [
225+ [PBValue , Any , Optional [str ], Optional [Dict [str , Union [Message , EnumTypeWrapper ]]]],
226+ Any ,
227+ ]
228+
229+ _TYPE_PARSERS : Dict [Type [SqlType .Type ], ParserCallable ] = {
193230 SqlType .Timestamp : _parse_timestamp_type ,
194231 SqlType .Struct : _parse_struct_type ,
195232 SqlType .Array : _parse_array_type ,
@@ -203,7 +240,7 @@ def _parse_pb_value_to_python_value(
203240 value : PBValue ,
204241 metadata_type : SqlType .Type ,
205242 column_name : str | None ,
206- column_info : dict [str , Any ] | None = None ,
243+ column_info : dict [str , Union [ Message , EnumTypeWrapper ] ] | None = None ,
207244) -> Any :
208245 """
209246 used for converting the value represented as a protobufs to a python object.
0 commit comments