Skip to content

Commit 54ca916

Browse files
committed
Add type annotations to interceptor and fix style issues in helpers
Change-Id: I6f570470fada9980b1486dfda77201b4e865f701
1 parent fd4794a commit 54ca916

File tree

2 files changed

+55
-34
lines changed

2 files changed

+55
-34
lines changed

google/ads/googleads/interceptors/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from typing import Any, Dict, List, Tuple, Union
1717

1818
from google.protobuf.descriptor import FieldDescriptor
19-
from google.protobuf.message import ProtobufMessage
19+
from google.protobuf.message import Message as ProtobufMessage
2020
from proto import Message as ProtoPlusMessage
2121

2222
from google.ads.googleads.util import (

google/ads/googleads/interceptors/interceptor.py

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,46 @@
2020

2121
from dataclasses import dataclass
2222
from 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+
)
2433
import 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

2938
from 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

3647
class 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

Comments
 (0)