Skip to content

Commit 71db47a

Browse files
Łukasz Wyszomirskipotiuk
andauthored
Update DV360 operators to use API v2 (#30326)
* Update DV360 operators to use API v2 * Update display_video.rst * fixup! Update display_video.rst * fixup! Update display_video.rst --------- Co-authored-by: Jarek Potiuk <jarek@potiuk.com>
1 parent 806b027 commit 71db47a

File tree

13 files changed

+928
-18
lines changed

13 files changed

+928
-18
lines changed

β€Žairflow/providers/google/CHANGELOG.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,14 @@
2323
Changelog
2424
---------
2525

26-
8.12.1
27-
......
26+
9.0.0
27+
.....
28+
29+
Breaking changes
30+
~~~~~~~~~~~~~~~~
31+
32+
Google announced sunset of Bid manager API v1 and v1.1 by April 27, 2023 for more information
33+
please check: `docs <https://developers.google.com/bid-manager/v1.1>`_ As a result default value of api_version in GoogleDisplayVideo360Hook and related operators updated to v2
2834

2935
This version of provider contains a temporary workaround to issue with ``v11`` version of
3036
google-ads API being discontinued, while the google provider dependencies preventing installing

β€Žairflow/providers/google/marketing_platform/example_dags/example_display_video.py

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,22 @@
2929
from airflow.providers.google.cloud.transfers.gcs_to_bigquery import GCSToBigQueryOperator
3030
from airflow.providers.google.marketing_platform.hooks.display_video import GoogleDisplayVideo360Hook
3131
from airflow.providers.google.marketing_platform.operators.display_video import (
32+
GoogleDisplayVideo360CreateQueryOperator,
3233
GoogleDisplayVideo360CreateReportOperator,
3334
GoogleDisplayVideo360CreateSDFDownloadTaskOperator,
3435
GoogleDisplayVideo360DeleteReportOperator,
3536
GoogleDisplayVideo360DownloadLineItemsOperator,
3637
GoogleDisplayVideo360DownloadReportOperator,
38+
GoogleDisplayVideo360DownloadReportV2Operator,
39+
GoogleDisplayVideo360RunQueryOperator,
3740
GoogleDisplayVideo360RunReportOperator,
3841
GoogleDisplayVideo360SDFtoGCSOperator,
3942
GoogleDisplayVideo360UploadLineItemsOperator,
4043
)
4144
from airflow.providers.google.marketing_platform.sensors.display_video import (
4245
GoogleDisplayVideo360GetSDFDownloadOperationSensor,
4346
GoogleDisplayVideo360ReportSensor,
47+
GoogleDisplayVideo360RunQuerySensor,
4448
)
4549

4650
# [START howto_display_video_env_variables]
@@ -50,7 +54,7 @@
5054
PATH_TO_UPLOAD_FILE = os.environ.get("GCP_GCS_PATH_TO_UPLOAD_FILE", "test-gcs-example.txt")
5155
PATH_TO_SAVED_FILE = os.environ.get("GCP_GCS_PATH_TO_SAVED_FILE", "test-gcs-example-download.txt")
5256
BUCKET_FILE_LOCATION = PATH_TO_UPLOAD_FILE.rpartition("/")[-1]
53-
SDF_VERSION = os.environ.get("GMP_SDF_VERSION", "SDF_VERSION_5_1")
57+
SDF_VERSION = os.environ.get("GMP_SDF_VERSION", "SDF_VERSION_5_5")
5458
BQ_DATA_SET = os.environ.get("GMP_BQ_DATA_SET", "airflow_test")
5559
GMP_PARTNER_ID = os.environ.get("GMP_PARTNER_ID", 123)
5660
ENTITY_TYPE = os.environ.get("GMP_ENTITY_TYPE", "LineItem")
@@ -74,7 +78,25 @@
7478
"schedule": {"frequency": "ONE_TIME"},
7579
}
7680

77-
PARAMETERS = {"dataRange": "LAST_14_DAYS", "timezoneCode": "America/New_York"}
81+
REPORT_V2 = {
82+
"metadata": {
83+
"title": "Airflow Test Report",
84+
"dataRange": {"range": "LAST_7_DAYS"},
85+
"format": "CSV",
86+
"sendNotification": False,
87+
},
88+
"params": {
89+
"type": "STANDARD",
90+
"groupBys": ["FILTER_DATE", "FILTER_PARTNER"],
91+
"filters": [{"type": "FILTER_PARTNER", "value": ADVERTISER_ID}],
92+
"metrics": ["METRIC_IMPRESSIONS", "METRIC_CLICKS"],
93+
},
94+
"schedule": {"frequency": "ONE_TIME"},
95+
}
96+
97+
PARAMETERS = {
98+
"dataRange": {"range": "LAST_7_DAYS"},
99+
}
78100

79101
CREATE_SDF_DOWNLOAD_TASK_BODY_REQUEST: dict = {
80102
"version": SDF_VERSION,
@@ -209,3 +231,46 @@
209231

210232
# Task dependency created via `XComArgs`:
211233
# save_sdf_in_gcs >> upload_sdf_to_big_query
234+
235+
with models.DAG(
236+
"example_display_video_v2",
237+
start_date=START_DATE,
238+
catchup=False,
239+
) as dag:
240+
# [START howto_google_display_video_create_query_operator]
241+
create_query_v2 = GoogleDisplayVideo360CreateQueryOperator(body=REPORT_V2, task_id="create_query")
242+
243+
query_id = cast(str, XComArg(create_query_v2, key="query_id"))
244+
# [END howto_google_display_video_create_query_operator]
245+
246+
# [START howto_google_display_video_run_query_report_operator]
247+
run_query_v2 = GoogleDisplayVideo360RunQueryOperator(
248+
query_id=query_id, parameters=PARAMETERS, task_id="run_report"
249+
)
250+
251+
query_id = cast(str, XComArg(run_query_v2, key="query_id"))
252+
report_id = cast(str, XComArg(run_query_v2, key="report_id"))
253+
# [END howto_google_display_video_run_query_report_operator]
254+
255+
# [START howto_google_display_video_wait_run_query_sensor]
256+
wait_for_query = GoogleDisplayVideo360RunQuerySensor(
257+
task_id="wait_for_query",
258+
query_id=query_id,
259+
report_id=report_id,
260+
)
261+
# [END howto_google_display_video_wait_run_query_sensor]
262+
263+
# [START howto_google_display_video_get_report_operator]
264+
get_report_v2 = GoogleDisplayVideo360DownloadReportV2Operator(
265+
query_id=query_id,
266+
report_id=report_id,
267+
task_id="get_report",
268+
bucket_name=BUCKET,
269+
report_name="test1.csv",
270+
)
271+
# # [END howto_google_display_video_get_report_operator]
272+
# # [START howto_google_display_video_delete_query_report_operator]
273+
delete_report_v2 = GoogleDisplayVideo360DeleteReportOperator(report_id=report_id, task_id="delete_report")
274+
# # [END howto_google_display_video_delete_query_report_operator]
275+
276+
create_query_v2 >> run_query_v2 >> wait_for_query >> get_report_v2 >> delete_report_v2

β€Žairflow/providers/google/marketing_platform/hooks/display_video.py

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"""This module contains Google DisplayVideo hook."""
1919
from __future__ import annotations
2020

21+
import warnings
2122
from typing import Any, Sequence
2223

2324
from googleapiclient.discovery import Resource, build
@@ -32,7 +33,7 @@ class GoogleDisplayVideo360Hook(GoogleBaseHook):
3233

3334
def __init__(
3435
self,
35-
api_version: str = "v1",
36+
api_version: str = "v2",
3637
gcp_conn_id: str = "google_cloud_default",
3738
delegate_to: str | None = None,
3839
impersonation_chain: str | Sequence[str] | None = None,
@@ -42,6 +43,11 @@ def __init__(
4243
delegate_to=delegate_to,
4344
impersonation_chain=impersonation_chain,
4445
)
46+
if api_version in ["v1", "v1.1"]:
47+
warnings.warn(
48+
f"API {api_version} is deprecated and shortly will be removed please use v2",
49+
DeprecationWarning,
50+
)
4551
self.api_version = api_version
4652

4753
def get_conn(self) -> Resource:
@@ -93,7 +99,10 @@ def create_query(self, query: dict[str, Any]) -> dict:
9399
94100
:param query: Query object to be passed to request body.
95101
"""
96-
response = self.get_conn().queries().createquery(body=query).execute(num_retries=self.num_retries)
102+
if self.api_version in ["v1", "v1.1"]:
103+
response = self.get_conn().queries().createquery(body=query).execute(num_retries=self.num_retries)
104+
else:
105+
response = self.get_conn().queries().create(body=query).execute(num_retries=self.num_retries)
97106
return response
98107

99108
def delete_query(self, query_id: str) -> None:
@@ -102,33 +111,67 @@ def delete_query(self, query_id: str) -> None:
102111
103112
:param query_id: Query ID to delete.
104113
"""
105-
(self.get_conn().queries().deletequery(queryId=query_id).execute(num_retries=self.num_retries))
114+
if self.api_version in ["v1", "v1.1"]:
115+
self.get_conn().queries().deletequery(queryId=query_id).execute(num_retries=self.num_retries)
116+
else:
117+
self.get_conn().queries().delete(queryId=query_id).execute(num_retries=self.num_retries)
106118

107119
def get_query(self, query_id: str) -> dict:
108120
"""
109121
Retrieves a stored query.
110122
111123
:param query_id: Query ID to retrieve.
112124
"""
113-
response = self.get_conn().queries().getquery(queryId=query_id).execute(num_retries=self.num_retries)
125+
if self.api_version in ["v1", "v1.1"]:
126+
response = (
127+
self.get_conn().queries().getquery(queryId=query_id).execute(num_retries=self.num_retries)
128+
)
129+
else:
130+
response = self.get_conn().queries().get(queryId=query_id).execute(num_retries=self.num_retries)
114131
return response
115132

116133
def list_queries(self) -> list[dict]:
117134
"""Retrieves stored queries."""
118-
response = self.get_conn().queries().listqueries().execute(num_retries=self.num_retries)
135+
if self.api_version in ["v1", "v1.1"]:
136+
response = self.get_conn().queries().listqueries().execute(num_retries=self.num_retries)
137+
else:
138+
response = self.get_conn().queries().list().execute(num_retries=self.num_retries)
119139
return response.get("queries", [])
120140

121-
def run_query(self, query_id: str, params: dict[str, Any] | None) -> None:
141+
def run_query(self, query_id: str, params: dict[str, Any] | None) -> dict:
122142
"""
123143
Runs a stored query to generate a report.
124144
125145
:param query_id: Query ID to run.
126146
:param params: Parameters for the report.
127147
"""
128-
(
148+
if self.api_version in ["v1", "v1.1"]:
149+
return (
150+
self.get_conn()
151+
.queries()
152+
.runquery(queryId=query_id, body=params)
153+
.execute(num_retries=self.num_retries)
154+
)
155+
else:
156+
return (
157+
self.get_conn()
158+
.queries()
159+
.run(queryId=query_id, body=params)
160+
.execute(num_retries=self.num_retries)
161+
)
162+
163+
def get_report(self, query_id: str, report_id: str) -> dict:
164+
"""
165+
Retrieves a report.
166+
167+
:param query_id: Query ID for which report was generated.
168+
:param report_id: Report ID to retrieve.
169+
"""
170+
return (
129171
self.get_conn()
130172
.queries()
131-
.runquery(queryId=query_id, body=params)
173+
.reports()
174+
.get(queryId=query_id, reportId=report_id)
132175
.execute(num_retries=self.num_retries)
133176
)
134177

0 commit comments

Comments
 (0)