2020
2121from dataclasses import dataclass
2222from importlib import import_module
23- from typing import AnyStr , Optional , Sequence , Tuple
23+ from types import ModuleType
24+ from typing import (
25+ Any ,
26+ AnyStr ,
27+ Dict ,
28+ List ,
29+ Optional ,
30+ Sequence ,
31+ Tuple
32+ )
2433import json
2534
26- from google .protobuf .message import DecodeError
27- from grpc import ClientCallDetails , StatusCode , CallCredentials
35+ from google .protobuf .message import DecodeError , Message
36+ from grpc import Call , ClientCallDetails , StatusCode , CallCredentials , RpcError
2837
2938from google .ads .googleads .errors import GoogleAdsException
3039
31- _REQUEST_ID_KEY = "request-id"
40+ _REQUEST_ID_KEY : str = "request-id"
3241# Codes that are retried upon by google.api_core.
33- _RETRY_STATUS_CODES = (StatusCode .INTERNAL , StatusCode .RESOURCE_EXHAUSTED )
42+ _RETRY_STATUS_CODES : Tuple [StatusCode ]= (StatusCode .INTERNAL , StatusCode .RESOURCE_EXHAUSTED )
43+
44+ Metadata = Sequence [Tuple [str , AnyStr ]]
3445
3546
3647class Interceptor :
37- _SENSITIVE_INFO_MASK = "REDACTED"
48+ _SENSITIVE_INFO_MASK : str = "REDACTED"
3849
3950 @dataclass
4051 class _ClientCallDetails (ClientCallDetails ):
4152 """Wrapper class for initializing a new ClientCallDetails instance."""
4253
4354 method : str
4455 timeout : Optional [float ]
45- metadata : Optional [Sequence [ Tuple [ str , AnyStr ]] ]
56+ metadata : Optional [Metadata ]
4657 credentials : Optional [CallCredentials ]
4758
4859 @classmethod
49- def get_request_id_from_metadata (cls , trailing_metadata ):
60+ def get_request_id_from_metadata (
61+ cls , trailing_metadata : Metadata
62+ ) -> Optional [str ]:
5063 """Gets the request ID for the Google Ads API request.
5164
5265 Args:
@@ -58,12 +71,12 @@ def get_request_id_from_metadata(cls, trailing_metadata):
5871 """
5972 for kv in trailing_metadata :
6073 if kv [0 ] == _REQUEST_ID_KEY :
61- return kv [1 ] # Return the found request ID.
74+ return kv [1 ]
6275
6376 return None
6477
6578 @classmethod
66- def parse_metadata_to_json (cls , metadata ) :
79+ def parse_metadata_to_json (cls , metadata : Optional [ Metadata ]) -> str :
6780 """Parses metadata from gRPC request and response messages to a JSON str.
6881
6982 Obscures the value for "developer-token".
@@ -74,23 +87,23 @@ def parse_metadata_to_json(cls, metadata):
7487 Returns:
7588 A str of metadata formatted as JSON key/value pairs.
7689 """
77- metadata_dict = {}
90+ metadata_dict : Dict = {}
7891
7992 if metadata is None :
8093 return "{}"
8194
8295 for datum in metadata :
83- key = datum [0 ]
96+ key : str = datum [0 ]
8497 if key == "developer-token" :
8598 metadata_dict [key ] = cls ._SENSITIVE_INFO_MASK
8699 else :
87- value = datum [1 ]
100+ value : AnyStr = datum [1 ]
88101 metadata_dict [key ] = value
89102
90103 return cls .format_json_object (metadata_dict )
91104
92105 @classmethod
93- def format_json_object (cls , obj ) :
106+ def format_json_object (cls , obj : Dict ) -> str :
94107 """Parses a serializable object into a consistently formatted JSON string.
95108
96109 Returns:
@@ -102,8 +115,7 @@ def format_json_object(cls, obj):
102115 Returns:
103116 A str of metadata formatted as JSON key/value pairs.
104117 """
105-
106- def default_serializer (value ):
118+ def default_serializer (value : Any ) -> Optional [str ]:
107119 if isinstance (value , bytes ):
108120 return value .decode (errors = "ignore" )
109121 else :
@@ -121,7 +133,9 @@ def default_serializer(value):
121133 )
122134
123135 @classmethod
124- def get_trailing_metadata_from_interceptor_exception (cls , exception ):
136+ def get_trailing_metadata_from_interceptor_exception (
137+ cls , exception : RpcError
138+ ) -> Metadata :
125139 """Retrieves trailing metadata from an exception object.
126140
127141 Args:
@@ -146,8 +160,12 @@ def get_trailing_metadata_from_interceptor_exception(cls, exception):
146160
147161 @classmethod
148162 def get_client_call_details_instance (
149- cls , method , timeout , metadata , credentials = None
150- ):
163+ cls ,
164+ method : str ,
165+ timeout : float ,
166+ metadata : List [Tuple [str , AnyStr ]],
167+ credentials : Optional [CallCredentials ] = None ,
168+ ) -> ClientCallDetails :
151169 """Initializes an instance of the ClientCallDetails with the given data.
152170
153171 Args:
@@ -161,14 +179,14 @@ def get_client_call_details_instance(
161179 """
162180 return cls ._ClientCallDetails (method , timeout , metadata , credentials )
163181
164- def __init__ (self , api_version ):
165- self ._error_protos = None
166- self ._failure_key = (
182+ def __init__ (self , api_version : str ):
183+ self ._error_protos : Optional [ ModuleType ] = None
184+ self ._failure_key : str = (
167185 f"google.ads.googleads.{ api_version } .errors.googleadsfailure-bin"
168186 )
169- self ._api_version = api_version
187+ self ._api_version : str = api_version
170188
171- def _get_error_from_response (self , response ) :
189+ def _get_error_from_response (self , response : Call ) -> Call :
172190 """Attempts to wrap failed responses as GoogleAdsException instances.
173191
174192 Handles failed gRPC responses of by attempting to convert them
@@ -192,15 +210,17 @@ def _get_error_from_response(self, response):
192210 Exception: If not a GoogleAdsException or RpcException the error
193211 will be raised as-is.
194212 """
195- status_code = response .code ()
196- response_exception = response .exception ()
213+ status_code : StatusCode = response .code ()
214+ response_exception : Call = response .exception ()
197215
198216 if status_code not in _RETRY_STATUS_CODES :
199- trailing_metadata = response .trailing_metadata ()
200- google_ads_failure = self ._get_google_ads_failure (trailing_metadata )
217+ trailing_metadata : Metadata = response .trailing_metadata ()
218+ google_ads_failure : Optional [Message ] = self ._get_google_ads_failure (
219+ trailing_metadata
220+ )
201221
202- if google_ads_failure :
203- request_id = self .get_request_id_from_metadata (
222+ if google_ads_failure and response_exception :
223+ request_id : Optional [ str ] = self .get_request_id_from_metadata (
204224 trailing_metadata
205225 )
206226
@@ -211,17 +231,18 @@ def _get_error_from_response(self, response):
211231 return GoogleAdsException (
212232 response_exception , response , google_ads_failure , request_id
213233 )
214- else :
234+ elif response_exception :
215235 # Raise the original exception if not a GoogleAdsFailure. This
216236 # type of error is generally caused by problems at the request
217237 # level, such as when an invalid endpoint is given.
218238 return response_exception
219- else :
239+ elif response_exception :
220240 # Raise the original exception if error has status code
221241 # INTERNAL or RESOURCE_EXHAUSTED, meaning that
222242 return response_exception
243+ raise response .exception ()
223244
224- def _get_google_ads_failure (self , trailing_metadata ) :
245+ def _get_google_ads_failure (self , trailing_metadata : Metadata ) -> Optional [ Message ] :
225246 """Gets the Google Ads failure details if they exist.
226247
227248 Args:
0 commit comments