23
23
from functools import cached_property
24
24
except ImportError :
25
25
from cached_property import cached_property
26
- from google .ads .google_ads .client import GoogleAdsClient
27
- from google .ads .google_ads .errors import GoogleAdsException
28
- from google .ads .google_ads . v2 . types import GoogleAdsRow
26
+ from google .ads .googleads .client import GoogleAdsClient
27
+ from google .ads .googleads .errors import GoogleAdsException
28
+ from google .ads .googleads . v8 . services . types . google_ads_service import GoogleAdsRow
29
29
from google .api_core .page_iterator import GRPCIterator
30
30
from google .auth .exceptions import GoogleAuthError
31
31
from googleapiclient .discovery import Resource
@@ -76,7 +76,7 @@ class GoogleAdsHook(BaseHook):
76
76
:rtype: list[GoogleAdsRow]
77
77
"""
78
78
79
- default_api_version = "v5 "
79
+ default_api_version = "v8 "
80
80
81
81
def __init__ (
82
82
self ,
@@ -90,15 +90,92 @@ def __init__(
90
90
self .google_ads_conn_id = google_ads_conn_id
91
91
self .google_ads_config : Dict [str , Any ] = {}
92
92
93
+ def search (
94
+ self , client_ids : List [str ], query : str , page_size : int = 10000 , ** kwargs
95
+ ) -> List [GoogleAdsRow ]:
96
+ """
97
+ Pulls data from the Google Ads API and returns it as native protobuf
98
+ message instances (those seen in versions prior to 10.0.0 of the
99
+ google-ads library).
100
+
101
+ This method is for backwards compatibility with older versions of the
102
+ google_ads_hook.
103
+
104
+ Check out the search_proto_plus method to get API results in the new
105
+ default format of the google-ads library since v10.0.0 that behave
106
+ more like conventional python object (using proto-plus-python).
107
+
108
+ :param client_ids: Google Ads client ID(s) to query the API for.
109
+ :type client_ids: List[str]
110
+ :param query: Google Ads Query Language query.
111
+ :type query: str
112
+ :param page_size: Number of results to return per page. Max 10000.
113
+ :type page_size: int
114
+ :return: Google Ads API response, converted to Google Ads Row objects
115
+ :rtype: list[GoogleAdsRow]
116
+ """
117
+ data_proto_plus = self ._search (client_ids , query , page_size , ** kwargs )
118
+ data_native_pb = [row ._pb for row in data_proto_plus ]
119
+
120
+ return data_native_pb
121
+
122
+ def search_proto_plus (
123
+ self , client_ids : List [str ], query : str , page_size : int = 10000 , ** kwargs
124
+ ) -> List [GoogleAdsRow ]:
125
+ """
126
+ Pulls data from the Google Ads API and returns it as proto-plus-python
127
+ message instances that behave more like conventional python objects.
128
+
129
+ :param client_ids: Google Ads client ID(s) to query the API for.
130
+ :type client_ids: List[str]
131
+ :param query: Google Ads Query Language query.
132
+ :type query: str
133
+ :param page_size: Number of results to return per page. Max 10000.
134
+ :type page_size: int
135
+ :return: Google Ads API response, converted to Google Ads Row objects
136
+ :rtype: list[GoogleAdsRow]
137
+ """
138
+ return self ._search (client_ids , query , page_size , ** kwargs )
139
+
140
+ def list_accessible_customers (self ) -> List [str ]:
141
+ """
142
+ Returns resource names of customers directly accessible by the user authenticating the call.
143
+ The resulting list of customers is based on your OAuth credentials. The request returns a list
144
+ of all accounts that you are able to act upon directly given your current credentials. This will
145
+ not necessarily include all accounts within the account hierarchy; rather, it will only include
146
+ accounts where your authenticated user has been added with admin or other rights in the account.
147
+
148
+ ..seealso::
149
+ https://developers.google.com/google-ads/api/reference/rpc
150
+
151
+ :return: List of names of customers
152
+ """
153
+ try :
154
+ accessible_customers = self ._get_customer_service .list_accessible_customers ()
155
+ return accessible_customers .resource_names
156
+ except GoogleAdsException as ex :
157
+ for error in ex .failure .errors :
158
+ self .log .error ('\t Error with message "%s".' , error .message )
159
+ if error .location :
160
+ for field_path_element in error .location .field_path_elements :
161
+ self .log .error ('\t \t On field: %s' , field_path_element .field_name )
162
+ raise
163
+
93
164
@cached_property
94
165
def _get_service (self ) -> Resource :
95
166
"""Connects and authenticates with the Google Ads API using a service account"""
167
+
168
+ client = self ._get_client
169
+ return client .get_service ("GoogleAdsService" , version = self .api_version )
170
+
171
+ @cached_property
172
+ def _get_client (self ) -> Resource :
96
173
with NamedTemporaryFile ("w" , suffix = ".json" ) as secrets_temp :
97
174
self ._get_config ()
98
175
self ._update_config_with_secret (secrets_temp )
99
176
try :
100
177
client = GoogleAdsClient .load_from_dict (self .google_ads_config )
101
- return client . get_service ( "GoogleAdsService" , version = self . api_version )
178
+ return client
102
179
except GoogleAuthError as e :
103
180
self .log .error ("Google Auth Error: %s" , e )
104
181
raise
@@ -140,7 +217,7 @@ def _update_config_with_secret(self, secrets_temp: IO[str]) -> None:
140
217
141
218
self .google_ads_config ["path_to_private_key_file" ] = secrets_temp .name
142
219
143
- def search (
220
+ def _search (
144
221
self , client_ids : List [str ], query : str , page_size : int = 10000 , ** kwargs
145
222
) -> List [GoogleAdsRow ]:
146
223
"""
@@ -157,9 +234,17 @@ def search(
157
234
:rtype: list[GoogleAdsRow]
158
235
"""
159
236
service = self ._get_service
160
- iterators = (
161
- service .search (client_id , query = query , page_size = page_size , ** kwargs ) for client_id in client_ids
162
- )
237
+
238
+ iterators = []
239
+ for client_id in client_ids :
240
+ request = self ._get_client .get_type ("SearchGoogleAdsRequest" )
241
+ request .customer_id = client_id
242
+ request .query = query
243
+ request .page_size = 10000
244
+
245
+ iterator = service .search (request = request )
246
+ iterators .append (iterator )
247
+
163
248
self .log .info ("Fetched Google Ads Iterators" )
164
249
165
250
return self ._extract_rows (iterators )
@@ -189,27 +274,3 @@ def _extract_rows(self, iterators: Generator[GRPCIterator, None, None]) -> List[
189
274
for field_path_element in error .location .field_path_elements :
190
275
self .log .error ("\t \t On field: %s" , field_path_element .field_name )
191
276
raise
192
-
193
- def list_accessible_customers (self ) -> List [str ]:
194
- """
195
- Returns resource names of customers directly accessible by the user authenticating the call.
196
- The resulting list of customers is based on your OAuth credentials. The request returns a list
197
- of all accounts that you are able to act upon directly given your current credentials. This will
198
- not necessarily include all accounts within the account hierarchy; rather, it will only include
199
- accounts where your authenticated user has been added with admin or other rights in the account.
200
-
201
- ..seealso::
202
- https://developers.google.com/google-ads/api/reference/rpc
203
-
204
- :return: List of names of customers
205
- """
206
- try :
207
- accessible_customers = self ._get_customer_service .list_accessible_customers ()
208
- return accessible_customers .resource_names
209
- except GoogleAdsException as ex :
210
- for error in ex .failure .errors :
211
- self .log .error ('\t Error with message "%s".' , error .message )
212
- if error .location :
213
- for field_path_element in error .location .field_path_elements :
214
- self .log .error ('\t \t On field: %s' , field_path_element .field_name )
215
- raise
0 commit comments