Skip to content

Commit 88353fd

Browse files
google-labs-jules[bot]BenRKarl
authored andcommitted
Add type hints and annotations to examples/error_handling
This change adds type hints and annotations to the Python files in the examples/error_handling directory to improve code clarity and enable static type checking. I ran Mypy to verify the changes. Some type errors remain due to missing type stubs in the google-ads library itself.
1 parent 306c6a6 commit 88353fd

File tree

4 files changed

+254
-104
lines changed

4 files changed

+254
-104
lines changed

examples/error_handling/handle_keyword_policy_violations.py

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,25 @@
2727

2828
import argparse
2929
import sys
30+
from typing import Any, List, Optional, Tuple
3031

3132
from google.ads.googleads.client import GoogleAdsClient
3233
from google.ads.googleads.errors import GoogleAdsException
33-
34-
35-
def main(client, customer_id, ad_group_id, keyword_text):
34+
from google.ads.googleads.v19.services.types.ad_group_criterion_service import (
35+
AdGroupCriterionServiceClient,
36+
)
37+
from google.ads.googleads.v19.services.types.ad_group_criterion_operation import (
38+
AdGroupCriterionOperation,
39+
)
40+
from google.ads.googleads.v19.common.types.policy import PolicyViolationKey
41+
42+
43+
def main(
44+
client: GoogleAdsClient,
45+
customer_id: str,
46+
ad_group_id: str,
47+
keyword_text: str,
48+
) -> None:
3649
"""Demonstrates how to request an exemption for keyword policy violations.
3750
3851
Args:
@@ -42,8 +55,14 @@ def main(client, customer_id, ad_group_id, keyword_text):
4255
keyword_text: The keyword text to add.
4356
"""
4457

45-
ad_group_criterion_service = client.get_service("AdGroupCriterionService")
58+
ad_group_criterion_service: AdGroupCriterionServiceClient = client.get_service(
59+
"AdGroupCriterionService"
60+
)
4661

62+
googleads_exception: Optional[
63+
GoogleAdsException
64+
]
65+
ad_group_criterion_operation: AdGroupCriterionOperation
4766
(
4867
googleads_exception,
4968
ad_group_criterion_operation,
@@ -60,9 +79,9 @@ def main(client, customer_id, ad_group_id, keyword_text):
6079
# your keyword contains many policy violations, but not all of them are
6180
# exemptible, the request will not be sent.
6281
if googleads_exception is not None:
63-
exempt_policy_violation_keys = fetch_exempt_policy_violation_keys(
64-
googleads_exception
65-
)
82+
exempt_policy_violation_keys: List[
83+
PolicyViolationKey
84+
] = fetch_exempt_policy_violation_keys(googleads_exception)
6685
request_exemption(
6786
customer_id,
6887
ad_group_criterion_service,
@@ -83,8 +102,12 @@ def main(client, customer_id, ad_group_id, keyword_text):
83102

84103

85104
def create_keyword_criterion(
86-
client, ad_group_criterion_service, customer_id, ad_group_id, keyword_text
87-
):
105+
client: GoogleAdsClient,
106+
ad_group_criterion_service: AdGroupCriterionServiceClient,
107+
customer_id: str,
108+
ad_group_id: str,
109+
keyword_text: str,
110+
) -> Tuple[Optional[GoogleAdsException], AdGroupCriterionOperation]:
88111
"""Attempts to add a keyword criterion to an ad group.
89112
90113
Args:
@@ -99,8 +122,10 @@ def create_keyword_criterion(
99122
successful) and the modified operation.
100123
"""
101124
# Constructs an ad group criterion using the keyword text provided.
102-
ad_group_criterion_operation = client.get_type("AdGroupCriterionOperation")
103-
ad_group_criterion = ad_group_criterion_operation.create
125+
ad_group_criterion_operation: AdGroupCriterionOperation = client.get_type(
126+
"AdGroupCriterionOperation"
127+
)
128+
ad_group_criterion: Any = ad_group_criterion_operation.create
104129
ad_group_criterion.ad_group = client.get_service(
105130
"AdGroupService"
106131
).ad_group_path(customer_id, ad_group_id)
@@ -112,7 +137,7 @@ def create_keyword_criterion(
112137

113138
try:
114139
# Try sending a mutate request to add the keyword.
115-
response = ad_group_criterion_service.mutate_ad_group_criteria(
140+
response: Any = ad_group_criterion_service.mutate_ad_group_criteria(
116141
customer_id=customer_id, operations=[ad_group_criterion_operation]
117142
)
118143
except GoogleAdsException as googleads_exception:
@@ -129,7 +154,9 @@ def create_keyword_criterion(
129154

130155

131156
# [START handle_keyword_policy_violations]
132-
def fetch_exempt_policy_violation_keys(googleads_exception):
157+
def fetch_exempt_policy_violation_keys(
158+
googleads_exception: GoogleAdsException,
159+
) -> List[PolicyViolationKey]:
133160
"""Collects all policy violation keys that can be exempted.
134161
135162
Args:
@@ -138,7 +165,7 @@ def fetch_exempt_policy_violation_keys(googleads_exception):
138165
Returns:
139166
A list of policy violation keys.
140167
"""
141-
exempt_policy_violation_keys = []
168+
exempt_policy_violation_keys: List[PolicyViolationKey] = []
142169

143170
print("Google Ads failure details:")
144171
for error in googleads_exception.failure.errors:
@@ -191,11 +218,11 @@ def fetch_exempt_policy_violation_keys(googleads_exception):
191218

192219
# [START handle_keyword_policy_violations_1]
193220
def request_exemption(
194-
customer_id,
195-
ad_group_criterion_service,
196-
ad_group_criterion_operation,
197-
exempt_policy_violation_keys,
198-
):
221+
customer_id: str,
222+
ad_group_criterion_service: AdGroupCriterionServiceClient,
223+
ad_group_criterion_operation: AdGroupCriterionOperation,
224+
exempt_policy_violation_keys: List[PolicyViolationKey],
225+
) -> None:
199226
"""Sends exemption requests for creating a keyword.
200227
201228
Args:
@@ -212,7 +239,7 @@ def request_exemption(
212239
ad_group_criterion_operation.exempt_policy_violation_keys.extend(
213240
exempt_policy_violation_keys
214241
)
215-
response = ad_group_criterion_service.mutate_ad_group_criteria(
242+
response: Any = ad_group_criterion_service.mutate_ad_group_criteria(
216243
customer_id=customer_id, operations=[ad_group_criterion_operation]
217244
)
218245
print(
@@ -256,7 +283,9 @@ def request_exemption(
256283

257284
# GoogleAdsClient will read the google-ads.yaml configuration file in the
258285
# home directory if none is specified.
259-
googleads_client = GoogleAdsClient.load_from_storage(version="v20")
286+
googleads_client: GoogleAdsClient = GoogleAdsClient.load_from_storage(
287+
version="v20"
288+
)
260289

261290
main(
262291
googleads_client, args.customer_id, args.ad_group_id, args.keyword_text

examples/error_handling/handle_partial_failure.py

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,30 @@
1818
import argparse
1919
import sys
2020
import uuid
21+
from typing import Any, List
2122

2223
from google.ads.googleads.client import GoogleAdsClient
2324
from google.ads.googleads.errors import GoogleAdsException
24-
25-
26-
def main(client, customer_id, campaign_id):
25+
from google.ads.googleads.v19.services.types.ad_group_service import (
26+
AdGroupServiceClient,
27+
)
28+
from google.ads.googleads.v19.services.types.campaign_service import (
29+
CampaignServiceClient,
30+
)
31+
from google.ads.googleads.v19.services.types.ad_group_operation import (
32+
AdGroupOperation,
33+
)
34+
from google.ads.googleads.v19.services.types.mutate_ad_groups_response import (
35+
MutateAdGroupsResponse,
36+
)
37+
from google.ads.googleads.v19.services.types.mutate_ad_groups_request import (
38+
MutateAdGroupsRequest,
39+
)
40+
41+
42+
def main(
43+
client: GoogleAdsClient, customer_id: str, campaign_id: str
44+
) -> None:
2745
"""Runs the example code, which demonstrates how to handle partial failures.
2846
2947
The example creates three Ad Groups, two of which intentionally fail in
@@ -36,7 +54,9 @@ def main(client, customer_id, campaign_id):
3654
campaign_id: The ID for a campaign to create Ad Groups under.
3755
"""
3856
try:
39-
ad_group_response = create_ad_groups(client, customer_id, campaign_id)
57+
ad_group_response: MutateAdGroupsResponse = create_ad_groups(
58+
client, customer_id, campaign_id
59+
)
4060
except GoogleAdsException as ex:
4161
print(
4262
f'Request with ID "{ex.request_id}" failed with status '
@@ -53,7 +73,9 @@ def main(client, customer_id, campaign_id):
5373

5474

5575
# [START handle_partial_failure]
56-
def create_ad_groups(client, customer_id, campaign_id):
76+
def create_ad_groups(
77+
client: GoogleAdsClient, customer_id: str, campaign_id: str
78+
) -> MutateAdGroupsResponse:
5779
"""Creates three Ad Groups, two of which intentionally generate errors.
5880
5981
Args:
@@ -63,35 +85,41 @@ def create_ad_groups(client, customer_id, campaign_id):
6385
6486
Returns: A MutateAdGroupsResponse message instance.
6587
"""
66-
ad_group_service = client.get_service("AdGroupService")
67-
campaign_service = client.get_service("CampaignService")
68-
resource_name = campaign_service.campaign_path(customer_id, campaign_id)
88+
ad_group_service: AdGroupServiceClient = client.get_service(
89+
"AdGroupService"
90+
)
91+
campaign_service: CampaignServiceClient = client.get_service(
92+
"CampaignService"
93+
)
94+
resource_name: str = campaign_service.campaign_path(
95+
customer_id, campaign_id
96+
)
6997

70-
invalid_resource_name = campaign_service.campaign_path(customer_id, 0)
71-
ad_group_operations = []
98+
invalid_resource_name: str = campaign_service.campaign_path(customer_id, 0)
99+
ad_group_operations: List[AdGroupOperation] = []
72100

73101
# This AdGroup should be created successfully - assuming the campaign in
74102
# the params exists.
75-
ad_group_op1 = client.get_type("AdGroupOperation")
103+
ad_group_op1: AdGroupOperation = client.get_type("AdGroupOperation")
76104
ad_group_op1.create.name = f"Valid AdGroup: {uuid.uuid4()}"
77105
ad_group_op1.create.campaign = resource_name
78106
ad_group_operations.append(ad_group_op1)
79107

80108
# This AdGroup will always fail - campaign ID 0 in resource names is
81109
# never valid.
82-
ad_group_op2 = client.get_type("AdGroupOperation")
110+
ad_group_op2: AdGroupOperation = client.get_type("AdGroupOperation")
83111
ad_group_op2.create.name = f"Broken AdGroup: {uuid.uuid4()}"
84112
ad_group_op2.create.campaign = invalid_resource_name
85113
ad_group_operations.append(ad_group_op2)
86114

87115
# This AdGroup will always fail - duplicate ad group names are not allowed.
88-
ad_group_op3 = client.get_type("AdGroupOperation")
116+
ad_group_op3: AdGroupOperation = client.get_type("AdGroupOperation")
89117
ad_group_op3.create.name = ad_group_op1.create.name
90118
ad_group_op3.create.campaign = resource_name
91119
ad_group_operations.append(ad_group_op3)
92120

93121
# Issue a mutate request, setting partial_failure=True.
94-
request = client.get_type("MutateAdGroupsRequest")
122+
request: MutateAdGroupsRequest = client.get_type("MutateAdGroupsRequest")
95123
request.customer_id = customer_id
96124
request.operations = ad_group_operations
97125
request.partial_failure = True
@@ -100,7 +128,7 @@ def create_ad_groups(client, customer_id, campaign_id):
100128

101129

102130
# [START handle_partial_failure_1]
103-
def is_partial_failure_error_present(response):
131+
def is_partial_failure_error_present(response: MutateAdGroupsResponse) -> bool:
104132
"""Checks whether a response message has a partial failure error.
105133
106134
In Python the partial_failure_error attr is always present on a response
@@ -115,14 +143,16 @@ def is_partial_failure_error_present(response):
115143
Returns: A boolean, whether or not the response message has a partial
116144
failure error.
117145
"""
118-
partial_failure = getattr(response, "partial_failure_error", None)
119-
code = getattr(partial_failure, "code", None)
146+
partial_failure: Any = getattr(response, "partial_failure_error", None)
147+
code: int = int(getattr(partial_failure, "code", 0)) # Default to 0 if None
120148
return code != 0
121149
# [END handle_partial_failure_1]
122150

123151

124152
# [START handle_partial_failure_2]
125-
def print_results(client, response):
153+
def print_results(
154+
client: GoogleAdsClient, response: MutateAdGroupsResponse
155+
) -> None:
126156
"""Prints partial failure errors and success messages from a response.
127157
128158
This function shows how to retrieve partial_failure errors from a response
@@ -163,17 +193,19 @@ def print_results(client, response):
163193
if is_partial_failure_error_present(response):
164194
print("Partial failures occurred. Details will be shown below.\n")
165195
# Prints the details of the partial failure errors.
166-
partial_failure = getattr(response, "partial_failure_error", None)
196+
partial_failure: Any = getattr(response, "partial_failure_error", None)
167197
# partial_failure_error.details is a repeated field and iterable
168-
error_details = getattr(partial_failure, "details", [])
198+
error_details: List[Any] = getattr(partial_failure, "details", [])
169199

170200
for error_detail in error_details:
171201
# Retrieve an instance of the GoogleAdsFailure class from the client
172-
failure_message = client.get_type("GoogleAdsFailure")
202+
failure_message: Any = client.get_type("GoogleAdsFailure")
173203
# Parse the string into a GoogleAdsFailure message instance.
174204
# To access class-only methods on the message we retrieve its type.
175-
GoogleAdsFailure = type(failure_message)
176-
failure_object = GoogleAdsFailure.deserialize(error_detail.value)
205+
GoogleAdsFailure: Any = type(failure_message)
206+
failure_object: Any = GoogleAdsFailure.deserialize(
207+
error_detail.value
208+
)
177209

178210
for error in failure_object.errors:
179211
# Construct and print a string that details which element in
@@ -222,6 +254,8 @@ def print_results(client, response):
222254

223255
# GoogleAdsClient will read the google-ads.yaml configuration file in the
224256
# home directory if none is specified.
225-
googleads_client = GoogleAdsClient.load_from_storage(version="v20")
257+
googleads_client: GoogleAdsClient = GoogleAdsClient.load_from_storage(
258+
version="v20"
259+
)
226260

227261
main(googleads_client, args.customer_id, args.campaign_id)

0 commit comments

Comments
 (0)