Skip to content

Commit 276b843

Browse files
authored
Add annotations to examples/account_management (#937)
1 parent 6ec1528 commit 276b843

9 files changed

+406
-134
lines changed

examples/account_management/create_customer.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,28 @@
2727

2828
from google.ads.googleads.client import GoogleAdsClient
2929
from google.ads.googleads.errors import GoogleAdsException
30+
from google.ads.googleads.v20.resources.types.customer import Customer
31+
from google.ads.googleads.v20.services.services.customer_service.client import (
32+
CustomerServiceClient,
33+
)
34+
from google.ads.googleads.v20.services.types.customer_service import (
35+
CreateCustomerClientResponse,
36+
)
3037

3138

3239
# [START create_customer]
33-
def main(client, manager_customer_id):
34-
customer_service = client.get_service("CustomerService")
35-
customer = client.get_type("Customer")
36-
now = datetime.today().strftime("%Y%m%d %H:%M:%S")
40+
def main(client: GoogleAdsClient, manager_customer_id: str) -> None:
41+
"""The main method that creates all necessary entities for the example.
42+
43+
Args:
44+
client: an initialized GoogleAdsClient instance.
45+
manager_customer_id: a manager client customer ID.
46+
"""
47+
customer_service: CustomerServiceClient = client.get_service(
48+
"CustomerService"
49+
)
50+
customer: Customer = client.get_type("Customer")
51+
now: str = datetime.today().strftime("%Y%m%d %H:%M:%S")
3752
customer.descriptive_name = f"Account created with CustomerService on {now}"
3853
# For a list of valid currency codes and time zones see this documentation:
3954
# https://developers.google.com/google-ads/api/reference/data/codes-formats
@@ -43,11 +58,13 @@ def main(client, manager_customer_id):
4358
# options see: https://support.google.com/google-ads/answer/6305348
4459
customer.tracking_url_template = "{lpurl}?device={device}"
4560
customer.final_url_suffix = (
46-
"keyword={keyword}&matchtype={matchtype}" "&adgroupid={adgroupid}"
61+
"keyword={keyword}&matchtype={matchtype}&adgroupid={adgroupid}"
4762
)
4863

49-
response = customer_service.create_customer_client(
50-
customer_id=manager_customer_id, customer_client=customer
64+
response: CreateCustomerClientResponse = (
65+
customer_service.create_customer_client(
66+
customer_id=manager_customer_id, customer_client=customer
67+
)
5168
)
5269
print(
5370
f'Customer created with resource name "{response.resource_name}" '

examples/account_management/get_account_hierarchy.py

Lines changed: 76 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,31 @@
2424

2525
import argparse
2626
import sys
27+
from typing import Optional, List, Dict
2728

2829
from google.ads.googleads.client import GoogleAdsClient
2930
from google.ads.googleads.errors import GoogleAdsException
30-
31-
32-
def main(client, login_customer_id=None):
31+
from google.ads.googleads.v20.services.services.google_ads_service.client import (
32+
GoogleAdsServiceClient,
33+
)
34+
from google.ads.googleads.v20.services.services.customer_service.client import (
35+
CustomerServiceClient,
36+
)
37+
from google.ads.googleads.v20.resources.types.customer_client import (
38+
CustomerClient,
39+
)
40+
from google.ads.googleads.v20.services.types.google_ads_service import (
41+
SearchPagedResponse,
42+
GoogleAdsRow,
43+
)
44+
45+
# ListAccessibleCustomersResponse is not directly used for a variable type,
46+
# but its attribute .resource_names is used, which is List[str].
47+
48+
49+
def main(
50+
client: GoogleAdsClient, login_customer_id: Optional[str] = None
51+
) -> None:
3352
"""Gets the account hierarchy of the given MCC and login customer ID.
3453
3554
Args:
@@ -38,13 +57,16 @@ def main(client, login_customer_id=None):
3857
method will instead list the accounts accessible from the
3958
authenticated Google Ads account.
4059
"""
41-
4260
# Gets instances of the GoogleAdsService and CustomerService clients.
43-
googleads_service = client.get_service("GoogleAdsService")
44-
customer_service = client.get_service("CustomerService")
61+
googleads_service: GoogleAdsServiceClient = client.get_service(
62+
"GoogleAdsService"
63+
)
64+
customer_service: CustomerServiceClient = client.get_service(
65+
"CustomerService"
66+
)
4567

4668
# A collection of customer IDs to handle.
47-
seed_customer_ids = []
69+
seed_customer_ids: List[str] = []
4870

4971
# Creates a query that retrieves all child accounts of the manager
5072
# specified in search calls below.
@@ -64,69 +86,84 @@ def main(client, login_customer_id=None):
6486
# the only ID in the list. Otherwise, we will issue a request for all
6587
# customers accessible by this authenticated Google account.
6688
if login_customer_id is not None:
89+
# Ensure login_customer_id is treated as a string for this list.
6790
seed_customer_ids = [login_customer_id]
6891
else:
6992
print(
7093
"No manager ID is specified. The example will print the "
7194
"hierarchies of all accessible customer IDs."
7295
)
7396

74-
customer_resource_names = (
97+
customer_resource_names: List[str] = (
7598
customer_service.list_accessible_customers().resource_names
7699
)
77100

78101
for customer_resource_name in customer_resource_names:
79-
customer_id = googleads_service.parse_customer_path(
102+
# customer_id here is a string as returned by parse_customer_path
103+
customer_id_from_parse: str = googleads_service.parse_customer_path(
80104
customer_resource_name
81105
)["customer_id"]
82-
print(customer_id)
83-
seed_customer_ids.append(customer_id)
106+
print(customer_id_from_parse)
107+
seed_customer_ids.append(customer_id_from_parse)
84108

85-
for seed_customer_id in seed_customer_ids:
109+
for (
110+
seed_customer_id_str
111+
) in seed_customer_ids: # seed_customer_id_str is a string
86112
# Performs a breadth-first search to build a Dictionary that maps
87113
# managers to their child accounts (customerIdsToChildAccounts).
88-
unprocessed_customer_ids = [seed_customer_id]
89-
customer_ids_to_child_accounts = dict()
90-
root_customer_client = None
114+
# unprocessed_customer_ids should store integers.
115+
unprocessed_customer_ids: List[int] = [int(seed_customer_id_str)]
116+
customer_ids_to_child_accounts: Dict[int, List[CustomerClient]] = dict()
117+
root_customer_client: CustomerClient | None = None
91118

92119
while unprocessed_customer_ids:
93-
customer_id = int(unprocessed_customer_ids.pop(0))
94-
response = googleads_service.search(
95-
customer_id=str(customer_id), query=query
120+
customer_id_loop: int = unprocessed_customer_ids.pop(
121+
0
122+
) # customer_id_loop is an int
123+
# The search method expects customer_id to be a string.
124+
response: SearchPagedResponse = googleads_service.search(
125+
customer_id=str(customer_id_loop), query=query
96126
)
97127

98128
# Iterates over all rows in all pages to get all customer
99129
# clients under the specified customer's hierarchy.
130+
googleads_row: GoogleAdsRow
100131
for googleads_row in response:
101-
customer_client = googleads_row.customer_client
132+
customer_client_loop_var: CustomerClient = (
133+
googleads_row.customer_client
134+
)
102135

103136
# The customer client that with level 0 is the specified
104137
# customer.
105-
if customer_client.level == 0:
138+
if customer_client_loop_var.level == 0:
106139
if root_customer_client is None:
107-
root_customer_client = customer_client
140+
root_customer_client = customer_client_loop_var
108141
continue
109142

110143
# For all level-1 (direct child) accounts that are a
111144
# manager account, the above query will be run against them
112145
# to create a Dictionary of managers mapped to their child
113146
# accounts for printing the hierarchy afterwards.
114-
if customer_id not in customer_ids_to_child_accounts:
115-
customer_ids_to_child_accounts[customer_id] = []
147+
if customer_id_loop not in customer_ids_to_child_accounts:
148+
customer_ids_to_child_accounts[customer_id_loop] = []
116149

117-
customer_ids_to_child_accounts[customer_id].append(
118-
customer_client
150+
customer_ids_to_child_accounts[customer_id_loop].append(
151+
customer_client_loop_var
119152
)
120153

121-
if customer_client.manager:
154+
if customer_client_loop_var.manager:
122155
# A customer can be managed by multiple managers, so to
123156
# prevent visiting the same customer many times, we
124157
# need to check if it's already in the Dictionary.
158+
# Assuming customer_client_loop_var.id is an int
125159
if (
126-
customer_client.id not in customer_ids_to_child_accounts
127-
and customer_client.level == 1
160+
customer_client_loop_var.id
161+
not in customer_ids_to_child_accounts
162+
and customer_client_loop_var.level == 1
128163
):
129-
unprocessed_customer_ids.append(customer_client.id)
164+
unprocessed_customer_ids.append(
165+
customer_client_loop_var.id
166+
)
130167

131168
if root_customer_client is not None:
132169
print(
@@ -145,8 +182,10 @@ def main(client, login_customer_id=None):
145182

146183

147184
def print_account_hierarchy(
148-
customer_client, customer_ids_to_child_accounts, depth
149-
):
185+
customer_client: CustomerClient,
186+
customer_ids_to_child_accounts: Dict[int, List[CustomerClient]],
187+
depth: int,
188+
) -> None:
150189
"""Prints the specified account's hierarchy using recursion.
151190
152191
Args:
@@ -160,17 +199,19 @@ def print_account_hierarchy(
160199
if depth == 0:
161200
print("Customer ID (Descriptive Name, Currency Code, Time Zone)")
162201

163-
customer_id = customer_client.id
202+
# Assuming customer_client.id is an int based on previous analysis for keys in customer_ids_to_child_accounts
203+
customer_id_print: int = customer_client.id
164204
print("-" * (depth * 2), end="")
165205
print(
166-
f"{customer_id} ({customer_client.descriptive_name}, "
206+
f"{customer_id_print} ({customer_client.descriptive_name}, "
167207
f"{customer_client.currency_code}, "
168208
f"{customer_client.time_zone})"
169209
)
170210

171211
# Recursively call this function for all child accounts of customer_client.
172-
if customer_id in customer_ids_to_child_accounts:
173-
for child_account in customer_ids_to_child_accounts[customer_id]:
212+
if customer_id_print in customer_ids_to_child_accounts:
213+
child_account: CustomerClient
214+
for child_account in customer_ids_to_child_accounts[customer_id_print]:
174215
print_account_hierarchy(
175216
child_account, customer_ids_to_child_accounts, depth + 1
176217
)

examples/account_management/get_change_details.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,35 @@
2121
import argparse
2222
from datetime import datetime, timedelta
2323
import sys
24+
from typing import Any
2425

2526
from proto.enums import ProtoEnumMeta
2627

2728
from google.ads.googleads.client import GoogleAdsClient
2829
from google.ads.googleads.errors import GoogleAdsException
2930
from google.ads.googleads.util import get_nested_attr
31+
from google.ads.googleads.v20.services.services.google_ads_service.client import (
32+
GoogleAdsServiceClient,
33+
)
34+
from google.ads.googleads.v20.services.types.google_ads_service import (
35+
SearchGoogleAdsRequest,
36+
SearchPagedResponse,
37+
GoogleAdsRow,
38+
)
39+
from google.ads.googleads.v20.resources.types.change_event import ChangeEvent
3040

3141

3242
# [START get_change_details]
33-
def main(client, customer_id):
43+
def main(client: GoogleAdsClient, customer_id: str) -> None:
3444
"""Gets specific details about the most recent changes in the given account.
3545
3646
Args:
3747
client: The Google Ads client.
3848
customer_id: The Google Ads customer ID.
3949
"""
40-
googleads_service = client.get_service("GoogleAdsService")
50+
googleads_service: GoogleAdsServiceClient = client.get_service(
51+
"GoogleAdsService"
52+
)
4153

4254
# Construct a query to find details for recent changes in your account.
4355
# The LIMIT clause is required for the change_event resource.
@@ -46,9 +58,9 @@ def main(client, customer_id):
4658
# https://developers.google.com/google-ads/api/docs/change-event#getting_changes
4759
# The WHERE clause on change_date_time is also required. It must specify a
4860
# window within the past 30 days.
49-
tomorrow = (datetime.now() + timedelta(1)).strftime("%Y-%m-%d")
50-
two_weeks_ago = (datetime.now() + timedelta(-14)).strftime("%Y-%m-%d")
51-
query = f"""
61+
tomorrow: str = (datetime.now() + timedelta(1)).strftime("%Y-%m-%d")
62+
two_weeks_ago: str = (datetime.now() + timedelta(-14)).strftime("%Y-%m-%d")
63+
query: str = f"""
5264
SELECT
5365
change_event.resource_name,
5466
change_event.change_date_time,
@@ -66,15 +78,22 @@ def main(client, customer_id):
6678
ORDER BY change_event.change_date_time DESC
6779
LIMIT 5"""
6880

69-
search_request = client.get_type("SearchGoogleAdsRequest")
81+
search_request: SearchGoogleAdsRequest = client.get_type(
82+
"SearchGoogleAdsRequest"
83+
)
7084
search_request.customer_id = customer_id
7185
search_request.query = query
7286

73-
results = googleads_service.search(request=search_request)
87+
results: SearchPagedResponse = googleads_service.search(
88+
request=search_request
89+
)
7490

91+
row: GoogleAdsRow
7592
for row in results:
76-
event = row.change_event
77-
resource_type = event.change_resource_type.name
93+
event: ChangeEvent = row.change_event
94+
resource_type: str = event.change_resource_type.name
95+
old_resource: Any
96+
new_resource: Any
7897
if resource_type == "AD":
7998
old_resource = event.old_resource.ad
8099
new_resource = event.new_resource.ad
@@ -148,17 +167,18 @@ def main(client, customer_id):
148167
f"'{event.change_resource_name}'"
149168
)
150169

151-
operation_type = event.resource_change_operation.name
170+
operation_type: str = event.resource_change_operation.name
152171

153172
if operation_type in ("UPDATE", "CREATE"):
154-
for changed_field in event.changed_fields.paths:
173+
for changed_field_path in event.changed_fields.paths:
174+
changed_field: str = changed_field_path
155175
# Change field name from "type" to "type_" so that it doesn't
156176
# raise an exception when accessed on the protobuf object, see:
157177
# https://developers.google.com/google-ads/api/docs/client-libs/python/library-version-10#field_names_that_are_reserved_words
158178
if changed_field == "type":
159179
changed_field = "type_"
160180

161-
new_value = get_nested_attr(new_resource, changed_field)
181+
new_value: Any = get_nested_attr(new_resource, changed_field)
162182
# If the field value is an Enum get the human readable name
163183
# so that it is printed instead of the field ID integer.
164184
if isinstance(type(new_value), ProtoEnumMeta):
@@ -167,7 +187,9 @@ def main(client, customer_id):
167187
if operation_type == "CREATE":
168188
print(f"\t{changed_field} set to {new_value}")
169189
else:
170-
old_value = get_nested_attr(old_resource, changed_field)
190+
old_value: Any = get_nested_attr(
191+
old_resource, changed_field
192+
)
171193
# If the field value is an Enum get the human readable name
172194
# so that it is printed instead of the field ID integer.
173195
if isinstance(type(old_value), ProtoEnumMeta):

0 commit comments

Comments
 (0)