apache-airflow-providers-google 10.22.0rc1__py3-none-any.whl → 10.23.0rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. airflow/providers/google/__init__.py +1 -1
  2. airflow/providers/google/cloud/hooks/bigquery.py +91 -54
  3. airflow/providers/google/cloud/hooks/cloud_build.py +3 -2
  4. airflow/providers/google/cloud/hooks/dataflow.py +112 -47
  5. airflow/providers/google/cloud/hooks/datapipeline.py +3 -3
  6. airflow/providers/google/cloud/hooks/kubernetes_engine.py +15 -26
  7. airflow/providers/google/cloud/hooks/life_sciences.py +5 -7
  8. airflow/providers/google/cloud/hooks/secret_manager.py +3 -3
  9. airflow/providers/google/cloud/hooks/vertex_ai/auto_ml.py +28 -8
  10. airflow/providers/google/cloud/hooks/vertex_ai/custom_job.py +11 -6
  11. airflow/providers/google/cloud/hooks/vertex_ai/generative_model.py +214 -34
  12. airflow/providers/google/cloud/hooks/vertex_ai/model_service.py +11 -4
  13. airflow/providers/google/cloud/links/automl.py +13 -22
  14. airflow/providers/google/cloud/log/gcs_task_handler.py +1 -2
  15. airflow/providers/google/cloud/operators/bigquery.py +6 -4
  16. airflow/providers/google/cloud/operators/dataflow.py +186 -4
  17. airflow/providers/google/cloud/operators/datafusion.py +3 -2
  18. airflow/providers/google/cloud/operators/datapipeline.py +5 -6
  19. airflow/providers/google/cloud/operators/dataproc.py +30 -33
  20. airflow/providers/google/cloud/operators/gcs.py +4 -4
  21. airflow/providers/google/cloud/operators/kubernetes_engine.py +16 -2
  22. airflow/providers/google/cloud/operators/life_sciences.py +5 -7
  23. airflow/providers/google/cloud/operators/mlengine.py +42 -65
  24. airflow/providers/google/cloud/operators/vertex_ai/auto_ml.py +18 -4
  25. airflow/providers/google/cloud/operators/vertex_ai/custom_job.py +5 -5
  26. airflow/providers/google/cloud/operators/vertex_ai/generative_model.py +280 -9
  27. airflow/providers/google/cloud/operators/vertex_ai/model_service.py +4 -0
  28. airflow/providers/google/cloud/secrets/secret_manager.py +3 -5
  29. airflow/providers/google/cloud/sensors/bigquery.py +8 -27
  30. airflow/providers/google/cloud/sensors/bigquery_dts.py +1 -4
  31. airflow/providers/google/cloud/sensors/cloud_composer.py +9 -14
  32. airflow/providers/google/cloud/sensors/dataflow.py +1 -25
  33. airflow/providers/google/cloud/sensors/dataform.py +1 -4
  34. airflow/providers/google/cloud/sensors/datafusion.py +1 -7
  35. airflow/providers/google/cloud/sensors/dataplex.py +1 -31
  36. airflow/providers/google/cloud/sensors/dataproc.py +1 -16
  37. airflow/providers/google/cloud/sensors/dataproc_metastore.py +1 -7
  38. airflow/providers/google/cloud/sensors/gcs.py +5 -27
  39. airflow/providers/google/cloud/sensors/looker.py +1 -13
  40. airflow/providers/google/cloud/sensors/pubsub.py +11 -5
  41. airflow/providers/google/cloud/sensors/workflows.py +1 -4
  42. airflow/providers/google/cloud/transfers/sftp_to_gcs.py +6 -0
  43. airflow/providers/google/cloud/triggers/dataflow.py +145 -1
  44. airflow/providers/google/cloud/triggers/kubernetes_engine.py +66 -3
  45. airflow/providers/google/common/deprecated.py +176 -0
  46. airflow/providers/google/common/hooks/base_google.py +3 -2
  47. airflow/providers/google/get_provider_info.py +8 -10
  48. airflow/providers/google/marketing_platform/hooks/analytics.py +4 -2
  49. airflow/providers/google/marketing_platform/hooks/search_ads.py +169 -30
  50. airflow/providers/google/marketing_platform/operators/analytics.py +16 -33
  51. airflow/providers/google/marketing_platform/operators/search_ads.py +217 -156
  52. airflow/providers/google/marketing_platform/sensors/display_video.py +1 -4
  53. {apache_airflow_providers_google-10.22.0rc1.dist-info → apache_airflow_providers_google-10.23.0rc1.dist-info}/METADATA +18 -16
  54. {apache_airflow_providers_google-10.22.0rc1.dist-info → apache_airflow_providers_google-10.23.0rc1.dist-info}/RECORD +56 -56
  55. airflow/providers/google/marketing_platform/sensors/search_ads.py +0 -92
  56. {apache_airflow_providers_google-10.22.0rc1.dist-info → apache_airflow_providers_google-10.23.0rc1.dist-info}/WHEEL +0 -0
  57. {apache_airflow_providers_google-10.22.0rc1.dist-info → apache_airflow_providers_google-10.23.0rc1.dist-info}/entry_points.txt +0 -0
@@ -19,73 +19,212 @@
19
19
 
20
20
  from __future__ import annotations
21
21
 
22
- from typing import Any, Sequence
22
+ from functools import cached_property
23
+ from typing import TYPE_CHECKING, Any, Sequence
23
24
 
25
+ from google.oauth2.credentials import Credentials
24
26
  from googleapiclient.discovery import build
25
27
 
28
+ from airflow.exceptions import AirflowException
26
29
  from airflow.providers.google.common.hooks.base_google import GoogleBaseHook
27
30
 
31
+ if TYPE_CHECKING:
32
+ from googleapiclient.discovery import Resource
28
33
 
29
- class GoogleSearchAdsHook(GoogleBaseHook):
30
- """Hook for Google Search Ads 360."""
34
+
35
+ class GoogleSearchAdsReportingHook(GoogleBaseHook):
36
+ """Hook for the Google Search Ads 360 Reporting API."""
31
37
 
32
38
  _conn: build | None = None
39
+ default_api_version: str = "v0"
33
40
 
34
41
  def __init__(
35
42
  self,
36
- api_version: str = "v2",
37
- gcp_conn_id: str = "google_cloud_default",
38
- delegate_to: str | None = None,
39
- impersonation_chain: str | Sequence[str] | None = None,
43
+ api_version: str | None = None,
44
+ gcp_conn_id: str = "google_search_ads_default",
40
45
  ) -> None:
41
46
  super().__init__(
42
47
  gcp_conn_id=gcp_conn_id,
43
- delegate_to=delegate_to,
44
- impersonation_chain=impersonation_chain,
45
48
  )
46
- self.api_version = api_version
49
+ self.api_version = api_version or self.default_api_version
47
50
 
48
- def get_conn(self):
49
- """Retrieve connection to Google SearchAds."""
51
+ def _get_config(self) -> None:
52
+ """
53
+ Set up Google Search Ads config from Connection.
54
+
55
+ This pulls the connections from db, and uses it to set up
56
+ ``google_search_ads_client``.
57
+ """
58
+ conn = self.get_connection(self.gcp_conn_id)
59
+ if "google_search_ads_client" not in conn.extra_dejson:
60
+ raise AirflowException("google_search_ads_client not found in extra field")
61
+
62
+ self.google_search_ads_config = conn.extra_dejson["google_search_ads_client"]
63
+
64
+ def get_credentials(self) -> Credentials:
65
+ """Return the credential instance for search ads."""
66
+ self._get_config()
67
+ self.logger().info(f"Credential configuration: {self.google_search_ads_config}")
68
+ return Credentials(**self.google_search_ads_config)
69
+
70
+ def get_conn(self) -> Resource:
50
71
  if not self._conn:
51
- http_authorized = self._authorize()
72
+ creds = self.get_credentials()
73
+
52
74
  self._conn = build(
53
- "doubleclicksearch",
75
+ "searchads360",
54
76
  self.api_version,
55
- http=http_authorized,
77
+ credentials=creds,
56
78
  cache_discovery=False,
57
79
  )
58
80
  return self._conn
59
81
 
60
- def insert_report(self, report: dict[str, Any]) -> Any:
82
+ @cached_property
83
+ def customer_service(self):
84
+ return self.get_conn().customers()
85
+
86
+ @cached_property
87
+ def fields_service(self):
88
+ return self.get_conn().searchAds360Fields()
89
+
90
+ def search(
91
+ self,
92
+ customer_id: str,
93
+ query: str,
94
+ page_token: str | None = None,
95
+ page_size: int = 10000,
96
+ return_total_results_count: bool = False,
97
+ summary_row_setting: str | None = None,
98
+ validate_only: bool = False,
99
+ ):
61
100
  """
62
- Insert a report request into the reporting system.
101
+ Search and download the report. Use pagination to download entire report.
63
102
 
64
- :param report: Report to be generated.
103
+ :param customer_id: The ID of the customer being queried.
104
+ :param query: The query to execute.
105
+ :param page_token: Token of the page to retrieve. If not specified, the first page of results will be
106
+ returned. Use the value obtained from `next_page_token` in the previous response
107
+ in order to request the next page of results.
108
+ :param page_size: Number of elements to retrieve in a single page. When too large a page is requested,
109
+ the server may decide to further limit the number of returned resources.
110
+ Default is 10000.
111
+ :param return_total_results_count: If true, the total number of results that match the query ignoring
112
+ the LIMIT clause will be included in the response. Default is false.
113
+ :param summary_row_setting: Determines whether a summary row will be returned. By default,
114
+ summary row is not returned. If requested, the summary row will be sent
115
+ in a response by itself after all others query results are returned.
116
+ :param validate_only: If true, the request is validated but not executed. Default is false.
65
117
  """
66
- response = self.get_conn().reports().request(body=report).execute(num_retries=self.num_retries)
118
+ params: dict[str, Any] = {
119
+ "query": query,
120
+ "pageSize": page_size,
121
+ "returnTotalResultsCount": return_total_results_count,
122
+ "validateOnly": validate_only,
123
+ }
124
+ if page_token is not None:
125
+ params.update({"pageToken": page_token})
126
+ if summary_row_setting is not None:
127
+ params.update({"summaryRowSetting": summary_row_setting})
128
+
129
+ response = (
130
+ self.customer_service.searchAds360()
131
+ .search(customerId=customer_id, body=params)
132
+ .execute(num_retries=self.num_retries)
133
+ )
134
+ self.log.info("Search response: %s", response)
67
135
  return response
68
136
 
69
- def get(self, report_id: str) -> Any:
137
+ def get_custom_column(self, customer_id: str, custom_column_id: str):
70
138
  """
71
- Poll for the status of a report request.
139
+ Retrieve the requested custom column in full detail.
72
140
 
73
- :param report_id: ID of the report request being polled.
141
+ :param customer_id: The customer id
142
+ :param custom_column_id: The custom column id
74
143
  """
75
- response = self.get_conn().reports().get(reportId=report_id).execute(num_retries=self.num_retries)
144
+ resource_name = f"customers/{customer_id}/customColumns/{custom_column_id}"
145
+ response = (
146
+ self.customer_service.customColumns()
147
+ .get(resourceName=resource_name)
148
+ .execute(num_retries=self.num_retries)
149
+ )
150
+ self.log.info("Retrieved custom column: %s", response)
76
151
  return response
77
152
 
78
- def get_file(self, report_fragment: int, report_id: str) -> Any:
153
+ def list_custom_columns(self, customer_id: str):
79
154
  """
80
- Download a report file encoded in UTF-8.
155
+ Retrieve all the custom columns associated with the customer in full detail.
81
156
 
82
- :param report_fragment: The index of the report fragment to download.
83
- :param report_id: ID of the report.
157
+ :param customer_id: The customer id
84
158
  """
85
159
  response = (
86
- self.get_conn()
87
- .reports()
88
- .getFile(reportFragment=report_fragment, reportId=report_id)
160
+ self.customer_service.customColumns()
161
+ .list(customerId=customer_id)
89
162
  .execute(num_retries=self.num_retries)
90
163
  )
164
+ self.log.info("Listing the custom columns: %s", response)
165
+ return response
166
+
167
+ def get_field(self, field_name: str):
168
+ """
169
+ Retrieve the requested field details.
170
+
171
+ :param field_name: The name of the field.
172
+ """
173
+ resource_name = f"searchAds360Fields/{field_name}"
174
+ response = self.fields_service.get(resourceName=resource_name).execute(num_retries=self.num_retries)
175
+ self.log.info("Retrieved field: %s", response)
91
176
  return response
177
+
178
+ def search_fields(self, query: str, page_token: str | None = None, page_size: int | None = 10000):
179
+ """
180
+ Retrieve all the fields that match with the given search.
181
+
182
+ :param query: The query string to execute.
183
+ :param page_token: Token of the page to retrieve. If not specified, the first page of results will be
184
+ returned. Use the value obtained from `next_page_token` in the previous response
185
+ in order to request the next page of results.
186
+ :param page_size: Number of elements to retrieve in a single page. When too large a page is requested,
187
+ the server may decide to further limit the number of returned resources.
188
+ Default 10000.
189
+ """
190
+ params: dict[str, Any] = {
191
+ "query": query,
192
+ "pageSize": page_size,
193
+ }
194
+ if page_token is not None:
195
+ params.update({"pageToken": page_token})
196
+ response = self.fields_service.search(body=params).execute(num_retries=self.num_retries)
197
+ self.log.info("Retrieved fields: %s", response)
198
+ return response
199
+
200
+
201
+ class GoogleSearchAdsHook(GoogleBaseHook):
202
+ """Hook for Google Search Ads 360."""
203
+
204
+ _conn: build | None = None
205
+
206
+ def __init__(
207
+ self,
208
+ api_version: str = "v2",
209
+ gcp_conn_id: str = "google_cloud_default",
210
+ delegate_to: str | None = None,
211
+ impersonation_chain: str | Sequence[str] | None = None,
212
+ ) -> None:
213
+ super().__init__(
214
+ gcp_conn_id=gcp_conn_id,
215
+ delegate_to=delegate_to,
216
+ impersonation_chain=impersonation_chain,
217
+ )
218
+ self.api_version = api_version
219
+
220
+ def get_conn(self):
221
+ """Retrieve connection to Google SearchAds."""
222
+ if not self._conn:
223
+ http_authorized = self._authorize()
224
+ self._conn = build(
225
+ "doubleclicksearch",
226
+ self.api_version,
227
+ http=http_authorized,
228
+ cache_discovery=False,
229
+ )
230
+ return self._conn
@@ -23,11 +23,10 @@ import csv
23
23
  from tempfile import NamedTemporaryFile
24
24
  from typing import TYPE_CHECKING, Any, Sequence
25
25
 
26
- from deprecated import deprecated
27
-
28
26
  from airflow.exceptions import AirflowProviderDeprecationWarning
29
27
  from airflow.models import BaseOperator
30
28
  from airflow.providers.google.cloud.hooks.gcs import GCSHook
29
+ from airflow.providers.google.common.deprecated import deprecated
31
30
  from airflow.providers.google.marketing_platform.hooks.analytics import GoogleAnalyticsHook
32
31
 
33
32
  if TYPE_CHECKING:
@@ -35,10 +34,9 @@ if TYPE_CHECKING:
35
34
 
36
35
 
37
36
  @deprecated(
38
- reason=(
39
- "The `GoogleAnalyticsListAccountsOperator` class is deprecated, please use "
40
- "`GoogleAnalyticsAdminListAccountsOperator` instead."
41
- ),
37
+ planned_removal_date="November 01, 2024",
38
+ use_instead="GoogleAnalyticsAdminListAccountsOperator",
39
+ reason="The Google Analytics API v3 has sunset and is no longer available as of July 1, 2024.",
42
40
  category=AirflowProviderDeprecationWarning,
43
41
  )
44
42
  class GoogleAnalyticsListAccountsOperator(BaseOperator):
@@ -55,10 +53,6 @@ class GoogleAnalyticsListAccountsOperator(BaseOperator):
55
53
  and for python client
56
54
  http://googleapis.github.io/google-api-python-client/docs/dyn/analytics_v3.management.accounts.html#list
57
55
 
58
- .. seealso::
59
- For more information on how to use this operator, take a look at the guide:
60
- :ref:`howto/operator:GoogleAnalyticsListAccountsOperator`
61
-
62
56
  :param api_version: The version of the api that will be requested for example 'v3'.
63
57
  :param gcp_conn_id: The connection ID to use when fetching connection info.
64
58
  :param impersonation_chain: Optional service account to impersonate using short-term
@@ -102,10 +96,9 @@ class GoogleAnalyticsListAccountsOperator(BaseOperator):
102
96
 
103
97
 
104
98
  @deprecated(
105
- reason=(
106
- "The `GoogleAnalyticsGetAdsLinkOperator` class is deprecated, please use "
107
- "`GoogleAnalyticsAdminGetGoogleAdsLinkOperator` instead."
108
- ),
99
+ planned_removal_date="November 01, 2024",
100
+ use_instead="GoogleAnalyticsAdminGetGoogleAdsLinkOperator",
101
+ reason="The Google Analytics API v3 has sunset and is no longer available as of July 1, 2024.",
109
102
  category=AirflowProviderDeprecationWarning,
110
103
  )
111
104
  class GoogleAnalyticsGetAdsLinkOperator(BaseOperator):
@@ -120,9 +113,6 @@ class GoogleAnalyticsGetAdsLinkOperator(BaseOperator):
120
113
  Check official API docs:
121
114
  https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/webPropertyAdWordsLinks/get
122
115
 
123
- .. seealso::
124
- For more information on how to use this operator, take a look at the guide:
125
- :ref:`howto/operator:GoogleAnalyticsGetAdsLinkOperator`
126
116
 
127
117
  :param account_id: ID of the account which the given web property belongs to.
128
118
  :param web_property_ad_words_link_id: Web property-Google Ads link ID.
@@ -181,10 +171,9 @@ class GoogleAnalyticsGetAdsLinkOperator(BaseOperator):
181
171
 
182
172
 
183
173
  @deprecated(
184
- reason=(
185
- "The `GoogleAnalyticsRetrieveAdsLinksListOperator` class is deprecated, please use "
186
- "`GoogleAnalyticsAdminListGoogleAdsLinksOperator` instead."
187
- ),
174
+ planned_removal_date="November 01, 2024",
175
+ use_instead="GoogleAnalyticsAdminListGoogleAdsLinksOperator",
176
+ reason="The Google Analytics API v3 has sunset and is no longer available as of July 1, 2024.",
188
177
  category=AirflowProviderDeprecationWarning,
189
178
  )
190
179
  class GoogleAnalyticsRetrieveAdsLinksListOperator(BaseOperator):
@@ -199,10 +188,6 @@ class GoogleAnalyticsRetrieveAdsLinksListOperator(BaseOperator):
199
188
  Check official API docs:
200
189
  https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/webPropertyAdWordsLinks/list#http-request
201
190
 
202
- .. seealso::
203
- For more information on how to use this operator, take a look at the guide:
204
- :ref:`howto/operator:GoogleAnalyticsRetrieveAdsLinksListOperator`
205
-
206
191
  :param account_id: ID of the account which the given web property belongs to.
207
192
  :param web_property_id: Web property UA-string to retrieve the Google Ads links for.
208
193
  :param impersonation_chain: Optional service account to impersonate using short-term
@@ -255,10 +240,9 @@ class GoogleAnalyticsRetrieveAdsLinksListOperator(BaseOperator):
255
240
 
256
241
 
257
242
  @deprecated(
258
- reason=(
259
- "The `GoogleAnalyticsDataImportUploadOperator` class is deprecated, please use "
260
- "`GoogleAnalyticsAdminCreateDataStreamOperator` instead."
261
- ),
243
+ planned_removal_date="November 01, 2024",
244
+ use_instead="GoogleAnalyticsAdminCreateDataStreamOperator",
245
+ reason="The Google Analytics API v3 has sunset and is no longer available as of July 1, 2024.",
262
246
  category=AirflowProviderDeprecationWarning,
263
247
  )
264
248
  class GoogleAnalyticsDataImportUploadOperator(BaseOperator):
@@ -362,10 +346,9 @@ class GoogleAnalyticsDataImportUploadOperator(BaseOperator):
362
346
 
363
347
 
364
348
  @deprecated(
365
- reason=(
366
- "The `GoogleAnalyticsDeletePreviousDataUploadsOperator` class is deprecated, please use "
367
- "`GoogleAnalyticsAdminDeleteDataStreamOperator` instead."
368
- ),
349
+ planned_removal_date="November 01, 2024",
350
+ use_instead="GoogleAnalyticsAdminDeleteDataStreamOperator",
351
+ reason="The Google Analytics API v3 has sunset and is no longer available as of July 1, 2024.",
369
352
  category=AirflowProviderDeprecationWarning,
370
353
  )
371
354
  class GoogleAnalyticsDeletePreviousDataUploadsOperator(BaseOperator):