apache-airflow-providers-google 18.0.0__py3-none-any.whl → 18.1.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.
Potentially problematic release.
This version of apache-airflow-providers-google might be problematic. Click here for more details.
- airflow/providers/google/__init__.py +1 -1
- airflow/providers/google/ads/hooks/ads.py +5 -5
- airflow/providers/google/assets/gcs.py +1 -11
- airflow/providers/google/cloud/bundles/__init__.py +16 -0
- airflow/providers/google/cloud/bundles/gcs.py +161 -0
- airflow/providers/google/cloud/hooks/bigquery.py +45 -42
- airflow/providers/google/cloud/hooks/cloud_composer.py +131 -1
- airflow/providers/google/cloud/hooks/cloud_sql.py +88 -13
- airflow/providers/google/cloud/hooks/cloud_storage_transfer_service.py +16 -0
- airflow/providers/google/cloud/hooks/dataflow.py +1 -1
- airflow/providers/google/cloud/hooks/dataprep.py +1 -1
- airflow/providers/google/cloud/hooks/dataproc.py +3 -0
- airflow/providers/google/cloud/hooks/gcs.py +107 -3
- airflow/providers/google/cloud/hooks/gen_ai.py +196 -0
- airflow/providers/google/cloud/hooks/looker.py +1 -1
- airflow/providers/google/cloud/hooks/spanner.py +45 -0
- airflow/providers/google/cloud/hooks/vertex_ai/generative_model.py +30 -0
- airflow/providers/google/cloud/links/base.py +11 -11
- airflow/providers/google/cloud/links/dataproc.py +2 -10
- airflow/providers/google/cloud/openlineage/CloudStorageTransferJobFacet.json +68 -0
- airflow/providers/google/cloud/openlineage/CloudStorageTransferRunFacet.json +60 -0
- airflow/providers/google/cloud/openlineage/DataFusionRunFacet.json +32 -0
- airflow/providers/google/cloud/openlineage/facets.py +102 -1
- airflow/providers/google/cloud/openlineage/mixins.py +3 -1
- airflow/providers/google/cloud/operators/bigquery.py +2 -9
- airflow/providers/google/cloud/operators/cloud_run.py +2 -1
- airflow/providers/google/cloud/operators/cloud_sql.py +1 -1
- airflow/providers/google/cloud/operators/cloud_storage_transfer_service.py +89 -6
- airflow/providers/google/cloud/operators/datafusion.py +36 -7
- airflow/providers/google/cloud/operators/gen_ai.py +389 -0
- airflow/providers/google/cloud/operators/spanner.py +22 -6
- airflow/providers/google/cloud/operators/vertex_ai/auto_ml.py +7 -0
- airflow/providers/google/cloud/operators/vertex_ai/generative_model.py +30 -0
- airflow/providers/google/cloud/operators/workflows.py +17 -6
- airflow/providers/google/cloud/sensors/bigquery.py +1 -1
- airflow/providers/google/cloud/sensors/bigquery_dts.py +1 -6
- airflow/providers/google/cloud/sensors/bigtable.py +1 -6
- airflow/providers/google/cloud/sensors/cloud_composer.py +65 -31
- airflow/providers/google/cloud/sensors/cloud_storage_transfer_service.py +1 -6
- airflow/providers/google/cloud/sensors/dataflow.py +1 -1
- airflow/providers/google/cloud/sensors/dataform.py +1 -6
- airflow/providers/google/cloud/sensors/datafusion.py +1 -6
- airflow/providers/google/cloud/sensors/dataplex.py +1 -6
- airflow/providers/google/cloud/sensors/dataprep.py +1 -6
- airflow/providers/google/cloud/sensors/dataproc.py +1 -6
- airflow/providers/google/cloud/sensors/dataproc_metastore.py +1 -6
- airflow/providers/google/cloud/sensors/gcs.py +1 -7
- airflow/providers/google/cloud/sensors/looker.py +1 -6
- airflow/providers/google/cloud/sensors/pubsub.py +1 -6
- airflow/providers/google/cloud/sensors/tasks.py +1 -6
- airflow/providers/google/cloud/sensors/vertex_ai/feature_store.py +1 -6
- airflow/providers/google/cloud/sensors/workflows.py +1 -6
- airflow/providers/google/cloud/transfers/bigquery_to_gcs.py +2 -1
- airflow/providers/google/cloud/transfers/gcs_to_bigquery.py +2 -1
- airflow/providers/google/cloud/transfers/sftp_to_gcs.py +11 -2
- airflow/providers/google/cloud/triggers/bigquery.py +15 -3
- airflow/providers/google/cloud/triggers/cloud_composer.py +51 -21
- airflow/providers/google/cloud/triggers/cloud_run.py +1 -1
- airflow/providers/google/cloud/triggers/cloud_storage_transfer_service.py +90 -0
- airflow/providers/google/cloud/triggers/pubsub.py +14 -18
- airflow/providers/google/common/hooks/base_google.py +1 -1
- airflow/providers/google/get_provider_info.py +15 -0
- airflow/providers/google/leveldb/hooks/leveldb.py +1 -1
- airflow/providers/google/marketing_platform/links/analytics_admin.py +2 -8
- airflow/providers/google/marketing_platform/sensors/campaign_manager.py +1 -6
- airflow/providers/google/marketing_platform/sensors/display_video.py +1 -6
- airflow/providers/google/suite/sensors/drive.py +1 -6
- airflow/providers/google/version_compat.py +0 -20
- {apache_airflow_providers_google-18.0.0.dist-info → apache_airflow_providers_google-18.1.0rc1.dist-info}/METADATA +15 -15
- {apache_airflow_providers_google-18.0.0.dist-info → apache_airflow_providers_google-18.1.0rc1.dist-info}/RECORD +72 -65
- {apache_airflow_providers_google-18.0.0.dist-info → apache_airflow_providers_google-18.1.0rc1.dist-info}/WHEEL +0 -0
- {apache_airflow_providers_google-18.0.0.dist-info → apache_airflow_providers_google-18.1.0rc1.dist-info}/entry_points.txt +0 -0
|
@@ -20,9 +20,10 @@ import datetime
|
|
|
20
20
|
import json
|
|
21
21
|
import re
|
|
22
22
|
import uuid
|
|
23
|
-
from collections.abc import Sequence
|
|
23
|
+
from collections.abc import Collection, Sequence
|
|
24
24
|
from typing import TYPE_CHECKING
|
|
25
25
|
|
|
26
|
+
import pendulum
|
|
26
27
|
from google.api_core.exceptions import AlreadyExists
|
|
27
28
|
from google.api_core.gapic_v1.method import DEFAULT, _MethodDefault
|
|
28
29
|
from google.cloud.workflows.executions_v1beta import Execution
|
|
@@ -36,12 +37,13 @@ from airflow.providers.google.cloud.links.workflows import (
|
|
|
36
37
|
)
|
|
37
38
|
from airflow.providers.google.cloud.operators.cloud_base import GoogleCloudBaseOperator
|
|
38
39
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
|
|
40
|
+
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
39
41
|
|
|
40
42
|
if TYPE_CHECKING:
|
|
41
43
|
from google.api_core.retry import Retry
|
|
42
44
|
from google.protobuf.field_mask_pb2 import FieldMask
|
|
43
45
|
|
|
44
|
-
from airflow.
|
|
46
|
+
from airflow.sdk import Context
|
|
45
47
|
|
|
46
48
|
from airflow.utils.hashlib_wrapper import md5
|
|
47
49
|
|
|
@@ -69,7 +71,7 @@ class WorkflowsCreateWorkflowOperator(GoogleCloudBaseOperator):
|
|
|
69
71
|
:param metadata: Additional metadata that is provided to the method.
|
|
70
72
|
"""
|
|
71
73
|
|
|
72
|
-
template_fields:
|
|
74
|
+
template_fields: Collection[str] = ("location", "workflow", "workflow_id")
|
|
73
75
|
template_fields_renderers = {"workflow": "json"}
|
|
74
76
|
operator_extra_links = (WorkflowsWorkflowDetailsLink(),)
|
|
75
77
|
|
|
@@ -101,7 +103,7 @@ class WorkflowsCreateWorkflowOperator(GoogleCloudBaseOperator):
|
|
|
101
103
|
self.impersonation_chain = impersonation_chain
|
|
102
104
|
self.force_rerun = force_rerun
|
|
103
105
|
|
|
104
|
-
def _workflow_id(self, context):
|
|
106
|
+
def _workflow_id(self, context: Context) -> str:
|
|
105
107
|
if self.workflow_id and not self.force_rerun:
|
|
106
108
|
# If users provide workflow id then assuring the idempotency
|
|
107
109
|
# is on their side
|
|
@@ -114,8 +116,17 @@ class WorkflowsCreateWorkflowOperator(GoogleCloudBaseOperator):
|
|
|
114
116
|
|
|
115
117
|
# We are limited by allowed length of workflow_id so
|
|
116
118
|
# we use hash of whole information
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
if AIRFLOW_V_3_0_PLUS:
|
|
120
|
+
if dag_run := context.get("dag_run"):
|
|
121
|
+
run_after = pendulum.instance(dag_run.run_after)
|
|
122
|
+
else:
|
|
123
|
+
run_after = pendulum.now("UTC")
|
|
124
|
+
else:
|
|
125
|
+
if logical_date := context.get("logical_date"):
|
|
126
|
+
run_after = pendulum.instance(logical_date)
|
|
127
|
+
else:
|
|
128
|
+
run_after = pendulum.now("UTC")
|
|
129
|
+
base = f"airflow_{self.dag_id}_{self.task_id}_{run_after.isoformat()}_{hash_base}"
|
|
119
130
|
workflow_id = md5(base.encode()).hexdigest()
|
|
120
131
|
return re.sub(r"[:\-+.]", "_", workflow_id)
|
|
121
132
|
|
|
@@ -26,12 +26,12 @@ from typing import TYPE_CHECKING, Any
|
|
|
26
26
|
|
|
27
27
|
from airflow.configuration import conf
|
|
28
28
|
from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
|
|
29
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
29
30
|
from airflow.providers.google.cloud.hooks.bigquery import BigQueryHook
|
|
30
31
|
from airflow.providers.google.cloud.triggers.bigquery import (
|
|
31
32
|
BigQueryTableExistenceTrigger,
|
|
32
33
|
BigQueryTablePartitionExistenceTrigger,
|
|
33
34
|
)
|
|
34
|
-
from airflow.providers.google.version_compat import BaseSensorOperator
|
|
35
35
|
|
|
36
36
|
if TYPE_CHECKING:
|
|
37
37
|
from airflow.utils.context import Context
|
|
@@ -26,14 +26,9 @@ from google.api_core.gapic_v1.method import DEFAULT, _MethodDefault
|
|
|
26
26
|
from google.cloud.bigquery_datatransfer_v1 import TransferState
|
|
27
27
|
|
|
28
28
|
from airflow.exceptions import AirflowException
|
|
29
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
29
30
|
from airflow.providers.google.cloud.hooks.bigquery_dts import BiqQueryDataTransferServiceHook
|
|
30
31
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
|
|
31
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
32
|
-
|
|
33
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
34
|
-
from airflow.sdk import BaseSensorOperator
|
|
35
|
-
else:
|
|
36
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
37
32
|
|
|
38
33
|
if TYPE_CHECKING:
|
|
39
34
|
from google.api_core.retry import Retry
|
|
@@ -26,16 +26,11 @@ import google.api_core.exceptions
|
|
|
26
26
|
from google.cloud.bigtable import enums
|
|
27
27
|
from google.cloud.bigtable.table import ClusterState
|
|
28
28
|
|
|
29
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
29
30
|
from airflow.providers.google.cloud.hooks.bigtable import BigtableHook
|
|
30
31
|
from airflow.providers.google.cloud.links.bigtable import BigtableTablesLink
|
|
31
32
|
from airflow.providers.google.cloud.operators.bigtable import BigtableValidationMixin
|
|
32
33
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
|
|
33
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
34
|
-
|
|
35
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
36
|
-
from airflow.sdk import BaseSensorOperator
|
|
37
|
-
else:
|
|
38
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
39
34
|
|
|
40
35
|
if TYPE_CHECKING:
|
|
41
36
|
from airflow.utils.context import Context
|
|
@@ -26,19 +26,15 @@ from functools import cached_property
|
|
|
26
26
|
from typing import TYPE_CHECKING
|
|
27
27
|
|
|
28
28
|
from dateutil import parser
|
|
29
|
+
from google.api_core.exceptions import NotFound
|
|
29
30
|
from google.cloud.orchestration.airflow.service_v1.types import Environment, ExecuteAirflowCommandResponse
|
|
30
31
|
|
|
31
32
|
from airflow.configuration import conf
|
|
32
33
|
from airflow.exceptions import AirflowException
|
|
34
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
33
35
|
from airflow.providers.google.cloud.hooks.cloud_composer import CloudComposerHook
|
|
34
36
|
from airflow.providers.google.cloud.triggers.cloud_composer import CloudComposerDAGRunTrigger
|
|
35
37
|
from airflow.providers.google.common.consts import GOOGLE_DEFAULT_DEFERRABLE_METHOD_NAME
|
|
36
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
37
|
-
|
|
38
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
39
|
-
from airflow.sdk import BaseSensorOperator
|
|
40
|
-
else:
|
|
41
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
42
38
|
from airflow.utils.state import TaskInstanceState
|
|
43
39
|
|
|
44
40
|
if TYPE_CHECKING:
|
|
@@ -97,6 +93,7 @@ class CloudComposerDAGRunSensor(BaseSensorOperator):
|
|
|
97
93
|
impersonation_chain: str | Sequence[str] | None = None,
|
|
98
94
|
deferrable: bool = conf.getboolean("operators", "default_deferrable", fallback=False),
|
|
99
95
|
poll_interval: int = 10,
|
|
96
|
+
use_rest_api: bool = False,
|
|
100
97
|
**kwargs,
|
|
101
98
|
) -> None:
|
|
102
99
|
super().__init__(**kwargs)
|
|
@@ -111,6 +108,7 @@ class CloudComposerDAGRunSensor(BaseSensorOperator):
|
|
|
111
108
|
self.impersonation_chain = impersonation_chain
|
|
112
109
|
self.deferrable = deferrable
|
|
113
110
|
self.poll_interval = poll_interval
|
|
111
|
+
self.use_rest_api = use_rest_api
|
|
114
112
|
|
|
115
113
|
if self.composer_dag_run_id and self.execution_range:
|
|
116
114
|
self.log.warning(
|
|
@@ -118,15 +116,22 @@ class CloudComposerDAGRunSensor(BaseSensorOperator):
|
|
|
118
116
|
)
|
|
119
117
|
|
|
120
118
|
def _get_logical_dates(self, context) -> tuple[datetime, datetime]:
|
|
119
|
+
logical_date = context.get("logical_date", None)
|
|
120
|
+
if logical_date is None:
|
|
121
|
+
raise RuntimeError(
|
|
122
|
+
"logical_date is None. Please make sure the sensor is not used in an asset-triggered Dag. "
|
|
123
|
+
"CloudComposerDAGRunSensor was designed to be used in time-based scheduled Dags only, "
|
|
124
|
+
"and asset-triggered Dags do not have logical_date. "
|
|
125
|
+
)
|
|
121
126
|
if isinstance(self.execution_range, timedelta):
|
|
122
127
|
if self.execution_range < timedelta(0):
|
|
123
|
-
return
|
|
124
|
-
return
|
|
128
|
+
return logical_date, logical_date - self.execution_range
|
|
129
|
+
return logical_date - self.execution_range, logical_date
|
|
125
130
|
if isinstance(self.execution_range, list) and len(self.execution_range) > 0:
|
|
126
131
|
return self.execution_range[0], self.execution_range[1] if len(
|
|
127
132
|
self.execution_range
|
|
128
|
-
) > 1 else
|
|
129
|
-
return
|
|
133
|
+
) > 1 else logical_date
|
|
134
|
+
return logical_date - timedelta(1), logical_date
|
|
130
135
|
|
|
131
136
|
def poke(self, context: Context) -> bool:
|
|
132
137
|
start_date, end_date = self._get_logical_dates(context)
|
|
@@ -161,26 +166,51 @@ class CloudComposerDAGRunSensor(BaseSensorOperator):
|
|
|
161
166
|
|
|
162
167
|
def _pull_dag_runs(self) -> list[dict]:
|
|
163
168
|
"""Pull the list of dag runs."""
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
169
|
+
if self.use_rest_api:
|
|
170
|
+
try:
|
|
171
|
+
environment = self.hook.get_environment(
|
|
172
|
+
project_id=self.project_id,
|
|
173
|
+
region=self.region,
|
|
174
|
+
environment_id=self.environment_id,
|
|
175
|
+
timeout=self.timeout,
|
|
176
|
+
)
|
|
177
|
+
except NotFound as not_found_err:
|
|
178
|
+
self.log.info("The Composer environment %s does not exist.", self.environment_id)
|
|
179
|
+
raise AirflowException(not_found_err)
|
|
180
|
+
composer_airflow_uri = environment.config.airflow_uri
|
|
181
|
+
|
|
182
|
+
self.log.info(
|
|
183
|
+
"Pulling the DAG %s runs from the %s environment...",
|
|
184
|
+
self.composer_dag_id,
|
|
185
|
+
self.environment_id,
|
|
186
|
+
)
|
|
187
|
+
dag_runs_response = self.hook.get_dag_runs(
|
|
188
|
+
composer_airflow_uri=composer_airflow_uri,
|
|
189
|
+
composer_dag_id=self.composer_dag_id,
|
|
190
|
+
timeout=self.timeout,
|
|
191
|
+
)
|
|
192
|
+
dag_runs = dag_runs_response["dag_runs"]
|
|
193
|
+
else:
|
|
194
|
+
cmd_parameters = (
|
|
195
|
+
["-d", self.composer_dag_id, "-o", "json"]
|
|
196
|
+
if self._composer_airflow_version < 3
|
|
197
|
+
else [self.composer_dag_id, "-o", "json"]
|
|
198
|
+
)
|
|
199
|
+
dag_runs_cmd = self.hook.execute_airflow_command(
|
|
200
|
+
project_id=self.project_id,
|
|
201
|
+
region=self.region,
|
|
202
|
+
environment_id=self.environment_id,
|
|
203
|
+
command="dags",
|
|
204
|
+
subcommand="list-runs",
|
|
205
|
+
parameters=cmd_parameters,
|
|
206
|
+
)
|
|
207
|
+
cmd_result = self.hook.wait_command_execution_result(
|
|
208
|
+
project_id=self.project_id,
|
|
209
|
+
region=self.region,
|
|
210
|
+
environment_id=self.environment_id,
|
|
211
|
+
execution_cmd_info=ExecuteAirflowCommandResponse.to_dict(dag_runs_cmd),
|
|
212
|
+
)
|
|
213
|
+
dag_runs = json.loads(cmd_result["output"][0]["content"])
|
|
184
214
|
return dag_runs
|
|
185
215
|
|
|
186
216
|
def _check_dag_runs_states(
|
|
@@ -213,7 +243,10 @@ class CloudComposerDAGRunSensor(BaseSensorOperator):
|
|
|
213
243
|
|
|
214
244
|
def _check_composer_dag_run_id_states(self, dag_runs: list[dict]) -> bool:
|
|
215
245
|
for dag_run in dag_runs:
|
|
216
|
-
if
|
|
246
|
+
if (
|
|
247
|
+
dag_run["dag_run_id" if self.use_rest_api else "run_id"] == self.composer_dag_run_id
|
|
248
|
+
and dag_run["state"] in self.allowed_states
|
|
249
|
+
):
|
|
217
250
|
return True
|
|
218
251
|
return False
|
|
219
252
|
|
|
@@ -236,6 +269,7 @@ class CloudComposerDAGRunSensor(BaseSensorOperator):
|
|
|
236
269
|
impersonation_chain=self.impersonation_chain,
|
|
237
270
|
poll_interval=self.poll_interval,
|
|
238
271
|
composer_airflow_version=self._composer_airflow_version,
|
|
272
|
+
use_rest_api=self.use_rest_api,
|
|
239
273
|
),
|
|
240
274
|
method_name=GOOGLE_DEFAULT_DEFERRABLE_METHOD_NAME,
|
|
241
275
|
)
|
|
@@ -24,6 +24,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
24
24
|
|
|
25
25
|
from airflow.configuration import conf
|
|
26
26
|
from airflow.exceptions import AirflowException
|
|
27
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
27
28
|
from airflow.providers.google.cloud.hooks.cloud_storage_transfer_service import (
|
|
28
29
|
COUNTERS,
|
|
29
30
|
METADATA,
|
|
@@ -35,12 +36,6 @@ from airflow.providers.google.cloud.triggers.cloud_storage_transfer_service impo
|
|
|
35
36
|
CloudStorageTransferServiceCheckJobStatusTrigger,
|
|
36
37
|
)
|
|
37
38
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
|
|
38
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
39
|
-
|
|
40
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
41
|
-
from airflow.sdk import BaseSensorOperator
|
|
42
|
-
else:
|
|
43
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
44
39
|
|
|
45
40
|
if TYPE_CHECKING:
|
|
46
41
|
from airflow.utils.context import Context
|
|
@@ -25,6 +25,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
25
25
|
|
|
26
26
|
from airflow.configuration import conf
|
|
27
27
|
from airflow.exceptions import AirflowException
|
|
28
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator, PokeReturnValue
|
|
28
29
|
from airflow.providers.google.cloud.hooks.dataflow import (
|
|
29
30
|
DEFAULT_DATAFLOW_LOCATION,
|
|
30
31
|
DataflowHook,
|
|
@@ -37,7 +38,6 @@ from airflow.providers.google.cloud.triggers.dataflow import (
|
|
|
37
38
|
DataflowJobStatusTrigger,
|
|
38
39
|
)
|
|
39
40
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
|
|
40
|
-
from airflow.providers.google.version_compat import BaseSensorOperator, PokeReturnValue
|
|
41
41
|
|
|
42
42
|
if TYPE_CHECKING:
|
|
43
43
|
from airflow.utils.context import Context
|
|
@@ -23,13 +23,8 @@ from collections.abc import Iterable, Sequence
|
|
|
23
23
|
from typing import TYPE_CHECKING
|
|
24
24
|
|
|
25
25
|
from airflow.exceptions import AirflowException
|
|
26
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
26
27
|
from airflow.providers.google.cloud.hooks.dataform import DataformHook
|
|
27
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
28
|
-
|
|
29
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
30
|
-
from airflow.sdk import BaseSensorOperator
|
|
31
|
-
else:
|
|
32
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
33
28
|
|
|
34
29
|
if TYPE_CHECKING:
|
|
35
30
|
from airflow.utils.context import Context
|
|
@@ -23,14 +23,9 @@ from collections.abc import Iterable, Sequence
|
|
|
23
23
|
from typing import TYPE_CHECKING
|
|
24
24
|
|
|
25
25
|
from airflow.exceptions import AirflowException, AirflowNotFoundException
|
|
26
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
26
27
|
from airflow.providers.google.cloud.hooks.datafusion import DataFusionHook
|
|
27
28
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
|
|
28
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
29
|
-
|
|
30
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
31
|
-
from airflow.sdk import BaseSensorOperator
|
|
32
|
-
else:
|
|
33
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
34
29
|
|
|
35
30
|
if TYPE_CHECKING:
|
|
36
31
|
from airflow.utils.context import Context
|
|
@@ -32,17 +32,12 @@ from google.api_core.gapic_v1.method import DEFAULT, _MethodDefault
|
|
|
32
32
|
from google.cloud.dataplex_v1.types import DataScanJob
|
|
33
33
|
|
|
34
34
|
from airflow.exceptions import AirflowException
|
|
35
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
35
36
|
from airflow.providers.google.cloud.hooks.dataplex import (
|
|
36
37
|
AirflowDataQualityScanException,
|
|
37
38
|
AirflowDataQualityScanResultTimeoutException,
|
|
38
39
|
DataplexHook,
|
|
39
40
|
)
|
|
40
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
41
|
-
|
|
42
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
43
|
-
from airflow.sdk import BaseSensorOperator
|
|
44
|
-
else:
|
|
45
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
46
41
|
|
|
47
42
|
|
|
48
43
|
class TaskState:
|
|
@@ -22,13 +22,8 @@ from __future__ import annotations
|
|
|
22
22
|
from collections.abc import Sequence
|
|
23
23
|
from typing import TYPE_CHECKING
|
|
24
24
|
|
|
25
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
25
26
|
from airflow.providers.google.cloud.hooks.dataprep import GoogleDataprepHook, JobGroupStatuses
|
|
26
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
27
|
-
|
|
28
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
29
|
-
from airflow.sdk import BaseSensorOperator
|
|
30
|
-
else:
|
|
31
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
32
27
|
|
|
33
28
|
if TYPE_CHECKING:
|
|
34
29
|
from airflow.utils.context import Context
|
|
@@ -27,14 +27,9 @@ from google.api_core.exceptions import ServerError
|
|
|
27
27
|
from google.cloud.dataproc_v1.types import Batch, JobStatus
|
|
28
28
|
|
|
29
29
|
from airflow.exceptions import AirflowException
|
|
30
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
30
31
|
from airflow.providers.google.cloud.hooks.dataproc import DataprocHook
|
|
31
32
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
|
|
32
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
33
|
-
|
|
34
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
35
|
-
from airflow.sdk import BaseSensorOperator
|
|
36
|
-
else:
|
|
37
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
38
33
|
|
|
39
34
|
if TYPE_CHECKING:
|
|
40
35
|
from airflow.utils.context import Context
|
|
@@ -21,14 +21,9 @@ from collections.abc import Sequence
|
|
|
21
21
|
from typing import TYPE_CHECKING
|
|
22
22
|
|
|
23
23
|
from airflow.exceptions import AirflowException
|
|
24
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
24
25
|
from airflow.providers.google.cloud.hooks.dataproc_metastore import DataprocMetastoreHook
|
|
25
26
|
from airflow.providers.google.cloud.hooks.gcs import parse_json_from_gcs
|
|
26
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
27
|
-
|
|
28
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
29
|
-
from airflow.sdk import BaseSensorOperator
|
|
30
|
-
else:
|
|
31
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
32
27
|
|
|
33
28
|
if TYPE_CHECKING:
|
|
34
29
|
from google.api_core.operation import Operation
|
|
@@ -29,6 +29,7 @@ from google.cloud.storage.retry import DEFAULT_RETRY
|
|
|
29
29
|
|
|
30
30
|
from airflow.configuration import conf
|
|
31
31
|
from airflow.exceptions import AirflowException
|
|
32
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator, poke_mode_only
|
|
32
33
|
from airflow.providers.google.cloud.hooks.gcs import GCSHook
|
|
33
34
|
from airflow.providers.google.cloud.triggers.gcs import (
|
|
34
35
|
GCSBlobTrigger,
|
|
@@ -36,13 +37,6 @@ from airflow.providers.google.cloud.triggers.gcs import (
|
|
|
36
37
|
GCSPrefixBlobTrigger,
|
|
37
38
|
GCSUploadSessionTrigger,
|
|
38
39
|
)
|
|
39
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
40
|
-
|
|
41
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
42
|
-
from airflow.sdk import BaseSensorOperator
|
|
43
|
-
from airflow.sdk.bases.sensor import poke_mode_only
|
|
44
|
-
else:
|
|
45
|
-
from airflow.sensors.base import BaseSensorOperator, poke_mode_only # type: ignore[no-redef]
|
|
46
40
|
|
|
47
41
|
if TYPE_CHECKING:
|
|
48
42
|
from google.api_core.retry import Retry
|
|
@@ -22,13 +22,8 @@ from __future__ import annotations
|
|
|
22
22
|
from typing import TYPE_CHECKING
|
|
23
23
|
|
|
24
24
|
from airflow.exceptions import AirflowException
|
|
25
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
25
26
|
from airflow.providers.google.cloud.hooks.looker import JobStatus, LookerHook
|
|
26
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
27
|
-
|
|
28
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
29
|
-
from airflow.sdk import BaseSensorOperator
|
|
30
|
-
else:
|
|
31
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
32
27
|
|
|
33
28
|
if TYPE_CHECKING:
|
|
34
29
|
from airflow.utils.context import Context
|
|
@@ -28,14 +28,9 @@ from google.cloud.pubsub_v1.types import ReceivedMessage
|
|
|
28
28
|
|
|
29
29
|
from airflow.configuration import conf
|
|
30
30
|
from airflow.exceptions import AirflowException
|
|
31
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
31
32
|
from airflow.providers.google.cloud.hooks.pubsub import PubSubHook
|
|
32
33
|
from airflow.providers.google.cloud.triggers.pubsub import PubsubPullTrigger
|
|
33
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
34
|
-
|
|
35
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
36
|
-
from airflow.sdk import BaseSensorOperator
|
|
37
|
-
else:
|
|
38
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
39
34
|
|
|
40
35
|
if TYPE_CHECKING:
|
|
41
36
|
from airflow.utils.context import Context
|
|
@@ -22,14 +22,9 @@ from __future__ import annotations
|
|
|
22
22
|
from collections.abc import Sequence
|
|
23
23
|
from typing import TYPE_CHECKING
|
|
24
24
|
|
|
25
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
25
26
|
from airflow.providers.google.cloud.hooks.tasks import CloudTasksHook
|
|
26
27
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
|
|
27
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
28
|
-
|
|
29
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
30
|
-
from airflow.sdk import BaseSensorOperator
|
|
31
|
-
else:
|
|
32
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
33
28
|
|
|
34
29
|
if TYPE_CHECKING:
|
|
35
30
|
from airflow.utils.context import Context
|
|
@@ -24,13 +24,8 @@ from collections.abc import Sequence
|
|
|
24
24
|
from typing import TYPE_CHECKING
|
|
25
25
|
|
|
26
26
|
from airflow.exceptions import AirflowException
|
|
27
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
27
28
|
from airflow.providers.google.cloud.hooks.vertex_ai.feature_store import FeatureStoreHook
|
|
28
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
29
|
-
|
|
30
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
31
|
-
from airflow.sdk import BaseSensorOperator
|
|
32
|
-
else:
|
|
33
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
34
29
|
|
|
35
30
|
if TYPE_CHECKING:
|
|
36
31
|
from airflow.utils.context import Context
|
|
@@ -23,14 +23,9 @@ from google.api_core.gapic_v1.method import DEFAULT, _MethodDefault
|
|
|
23
23
|
from google.cloud.workflows.executions_v1beta import Execution
|
|
24
24
|
|
|
25
25
|
from airflow.exceptions import AirflowException
|
|
26
|
+
from airflow.providers.common.compat.sdk import BaseSensorOperator
|
|
26
27
|
from airflow.providers.google.cloud.hooks.workflows import WorkflowsHook
|
|
27
28
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
|
|
28
|
-
from airflow.providers.google.version_compat import AIRFLOW_V_3_0_PLUS
|
|
29
|
-
|
|
30
|
-
if AIRFLOW_V_3_0_PLUS:
|
|
31
|
-
from airflow.sdk import BaseSensorOperator
|
|
32
|
-
else:
|
|
33
|
-
from airflow.sensors.base import BaseSensorOperator # type: ignore[no-redef]
|
|
34
29
|
|
|
35
30
|
if TYPE_CHECKING:
|
|
36
31
|
from google.api_core.retry import Retry
|
|
@@ -215,8 +215,9 @@ class BigQueryToGCSOperator(BaseOperator):
|
|
|
215
215
|
job_id=self.job_id,
|
|
216
216
|
dag_id=self.dag_id,
|
|
217
217
|
task_id=self.task_id,
|
|
218
|
-
logical_date=
|
|
218
|
+
logical_date=None,
|
|
219
219
|
configuration=configuration,
|
|
220
|
+
run_after=hook.get_run_after_or_logical_date(context),
|
|
220
221
|
force_rerun=self.force_rerun,
|
|
221
222
|
)
|
|
222
223
|
|
|
@@ -346,8 +346,9 @@ class GCSToBigQueryOperator(BaseOperator):
|
|
|
346
346
|
job_id=self.job_id,
|
|
347
347
|
dag_id=self.dag_id,
|
|
348
348
|
task_id=self.task_id,
|
|
349
|
-
logical_date=
|
|
349
|
+
logical_date=None,
|
|
350
350
|
configuration=self.configuration,
|
|
351
|
+
run_after=hook.get_run_after_or_logical_date(context),
|
|
351
352
|
force_rerun=self.force_rerun,
|
|
352
353
|
)
|
|
353
354
|
|
|
@@ -78,6 +78,8 @@ class SFTPToGCSOperator(BaseOperator):
|
|
|
78
78
|
then uploads (may require significant disk space).
|
|
79
79
|
When ``True``, the file streams directly without using local disk.
|
|
80
80
|
Defaults to ``False``.
|
|
81
|
+
:param fail_on_file_not_exist: If True, operator fails when file does not exist,
|
|
82
|
+
if False, operator will not fail and skips transfer. Default is True.
|
|
81
83
|
"""
|
|
82
84
|
|
|
83
85
|
template_fields: Sequence[str] = (
|
|
@@ -101,6 +103,7 @@ class SFTPToGCSOperator(BaseOperator):
|
|
|
101
103
|
impersonation_chain: str | Sequence[str] | None = None,
|
|
102
104
|
sftp_prefetch: bool = True,
|
|
103
105
|
use_stream: bool = False,
|
|
106
|
+
fail_on_file_not_exist: bool = True,
|
|
104
107
|
**kwargs,
|
|
105
108
|
) -> None:
|
|
106
109
|
super().__init__(**kwargs)
|
|
@@ -116,6 +119,7 @@ class SFTPToGCSOperator(BaseOperator):
|
|
|
116
119
|
self.impersonation_chain = impersonation_chain
|
|
117
120
|
self.sftp_prefetch = sftp_prefetch
|
|
118
121
|
self.use_stream = use_stream
|
|
122
|
+
self.fail_on_file_not_exist = fail_on_file_not_exist
|
|
119
123
|
|
|
120
124
|
@cached_property
|
|
121
125
|
def sftp_hook(self):
|
|
@@ -156,7 +160,13 @@ class SFTPToGCSOperator(BaseOperator):
|
|
|
156
160
|
destination_object = (
|
|
157
161
|
self.destination_path if self.destination_path else self.source_path.rsplit("/", 1)[1]
|
|
158
162
|
)
|
|
159
|
-
|
|
163
|
+
try:
|
|
164
|
+
self._copy_single_object(gcs_hook, self.sftp_hook, self.source_path, destination_object)
|
|
165
|
+
except FileNotFoundError as e:
|
|
166
|
+
if self.fail_on_file_not_exist:
|
|
167
|
+
raise e
|
|
168
|
+
self.log.info("File %s not found on SFTP server. Skipping transfer.", self.source_path)
|
|
169
|
+
return
|
|
160
170
|
|
|
161
171
|
def _copy_single_object(
|
|
162
172
|
self,
|
|
@@ -172,7 +182,6 @@ class SFTPToGCSOperator(BaseOperator):
|
|
|
172
182
|
self.destination_bucket,
|
|
173
183
|
destination_object,
|
|
174
184
|
)
|
|
175
|
-
|
|
176
185
|
if self.use_stream:
|
|
177
186
|
dest_bucket = gcs_hook.get_bucket(self.destination_bucket)
|
|
178
187
|
dest_blob = dest_bucket.blob(destination_object)
|
|
@@ -167,6 +167,7 @@ class BigQueryInsertJobTrigger(BaseTrigger):
|
|
|
167
167
|
job_id=self.job_id, project_id=self.project_id, location=self.location
|
|
168
168
|
)
|
|
169
169
|
if job_status["status"] == "success":
|
|
170
|
+
self.log.info("BigQuery Job succeeded")
|
|
170
171
|
yield TriggerEvent(
|
|
171
172
|
{
|
|
172
173
|
"job_id": self.job_id,
|
|
@@ -176,7 +177,13 @@ class BigQueryInsertJobTrigger(BaseTrigger):
|
|
|
176
177
|
)
|
|
177
178
|
return
|
|
178
179
|
elif job_status["status"] == "error":
|
|
179
|
-
|
|
180
|
+
self.log.info("BigQuery Job failed: %s", job_status)
|
|
181
|
+
yield TriggerEvent(
|
|
182
|
+
{
|
|
183
|
+
"status": job_status["status"],
|
|
184
|
+
"message": job_status["message"],
|
|
185
|
+
}
|
|
186
|
+
)
|
|
180
187
|
return
|
|
181
188
|
else:
|
|
182
189
|
self.log.info(
|
|
@@ -334,7 +341,12 @@ class BigQueryGetDataTrigger(BigQueryInsertJobTrigger):
|
|
|
334
341
|
)
|
|
335
342
|
return
|
|
336
343
|
elif job_status["status"] == "error":
|
|
337
|
-
yield TriggerEvent(
|
|
344
|
+
yield TriggerEvent(
|
|
345
|
+
{
|
|
346
|
+
"status": job_status["status"],
|
|
347
|
+
"message": job_status["message"],
|
|
348
|
+
}
|
|
349
|
+
)
|
|
338
350
|
return
|
|
339
351
|
else:
|
|
340
352
|
self.log.info(
|
|
@@ -773,7 +785,7 @@ class BigQueryTablePartitionExistenceTrigger(BigQueryTableExistenceTrigger):
|
|
|
773
785
|
return
|
|
774
786
|
job_id = None
|
|
775
787
|
elif job_status["status"] == "error":
|
|
776
|
-
yield TriggerEvent(job_status)
|
|
788
|
+
yield TriggerEvent({"status": job_status["status"]})
|
|
777
789
|
return
|
|
778
790
|
self.log.info("Sleeping for %s seconds.", self.poll_interval)
|
|
779
791
|
await asyncio.sleep(self.poll_interval)
|