apache-airflow-providers-google 10.23.0__py3-none-any.whl → 10.24.0__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.
@@ -29,7 +29,7 @@ from airflow import __version__ as airflow_version
29
29
 
30
30
  __all__ = ["__version__"]
31
31
 
32
- __version__ = "10.23.0"
32
+ __version__ = "10.24.0"
33
33
 
34
34
  if packaging.version.parse(packaging.version.parse(airflow_version).base_version) < packaging.version.parse(
35
35
  "2.8.0"
@@ -2418,10 +2418,6 @@ class BigQueryHook(GoogleBaseHook, DbApiHook):
2418
2418
  f"{var_print(var_name)}Expect format of (<project.|<project:)<dataset>.<table>, "
2419
2419
  f"got {table_input}"
2420
2420
  )
2421
-
2422
- # Exclude partition from the table name
2423
- table_id = table_id.split("$")[0]
2424
-
2425
2421
  if project_id is None:
2426
2422
  if var_name is not None:
2427
2423
  self.log.info(
@@ -1124,18 +1124,17 @@ class DataflowHook(GoogleBaseHook):
1124
1124
 
1125
1125
  return safe_job_name
1126
1126
 
1127
- @_fallback_to_location_from_variables
1128
1127
  @_fallback_to_project_id_from_variables
1129
1128
  @GoogleBaseHook.fallback_to_default_project_id
1130
1129
  def is_job_dataflow_running(
1131
1130
  self,
1132
1131
  name: str,
1133
1132
  project_id: str,
1134
- location: str = DEFAULT_DATAFLOW_LOCATION,
1133
+ location: str | None = None,
1135
1134
  variables: dict | None = None,
1136
1135
  ) -> bool:
1137
1136
  """
1138
- Check if jos is still running in dataflow.
1137
+ Check if job is still running in dataflow.
1139
1138
 
1140
1139
  :param name: The name of the job.
1141
1140
  :param project_id: Optional, the Google Cloud project ID in which to start a job.
@@ -1145,11 +1144,21 @@ class DataflowHook(GoogleBaseHook):
1145
1144
  """
1146
1145
  if variables:
1147
1146
  warnings.warn(
1148
- "The variables parameter has been deprecated. You should pass location using "
1149
- "the location parameter.",
1147
+ "The variables parameter has been deprecated. You should pass project_id using "
1148
+ "the project_id parameter.",
1150
1149
  AirflowProviderDeprecationWarning,
1151
1150
  stacklevel=4,
1152
1151
  )
1152
+
1153
+ if location is None:
1154
+ location = DEFAULT_DATAFLOW_LOCATION
1155
+ warnings.warn(
1156
+ "The location argument will be become mandatory in future versions, "
1157
+ f"currently, it defaults to {DEFAULT_DATAFLOW_LOCATION}, please set the location explicitly.",
1158
+ AirflowProviderDeprecationWarning,
1159
+ stacklevel=4,
1160
+ )
1161
+
1153
1162
  jobs_controller = _DataflowJobsController(
1154
1163
  dataflow=self.get_conn(),
1155
1164
  project_number=project_id,
@@ -59,6 +59,10 @@ if TYPE_CHECKING:
59
59
  from google.type.interval_pb2 import Interval
60
60
 
61
61
 
62
+ class DataprocResourceIsNotReadyError(AirflowException):
63
+ """Raise when resource is not ready for create Dataproc cluster."""
64
+
65
+
62
66
  class DataProcJobBuilder:
63
67
  """A helper class for building Dataproc job."""
64
68
 
@@ -281,6 +285,8 @@ class DataprocHook(GoogleBaseHook):
281
285
  return operation.result(timeout=timeout, retry=result_retry)
282
286
  except Exception:
283
287
  error = operation.exception(timeout=timeout)
288
+ if self.check_error_for_resource_is_not_ready_msg(error.message):
289
+ raise DataprocResourceIsNotReadyError(error.message)
284
290
  raise AirflowException(error)
285
291
 
286
292
  @GoogleBaseHook.fallback_to_default_project_id
@@ -1192,6 +1198,11 @@ class DataprocHook(GoogleBaseHook):
1192
1198
 
1193
1199
  return result
1194
1200
 
1201
+ def check_error_for_resource_is_not_ready_msg(self, error_msg: str) -> bool:
1202
+ """Check that reason of error is resource is not ready."""
1203
+ key_words = ["The resource", "is not ready"]
1204
+ return all([word in error_msg for word in key_words])
1205
+
1195
1206
 
1196
1207
  class DataprocAsyncHook(GoogleBaseHook):
1197
1208
  """
@@ -59,6 +59,7 @@ if TYPE_CHECKING:
59
59
 
60
60
  from aiohttp import ClientSession
61
61
  from google.api_core.retry import Retry
62
+ from google.cloud.storage.blob import Blob
62
63
 
63
64
 
64
65
  RT = TypeVar("RT")
@@ -597,11 +598,7 @@ class GCSHook(GoogleBaseHook):
597
598
  :param object_name: The name of the blob to get updated time from the Google cloud
598
599
  storage bucket.
599
600
  """
600
- client = self.get_conn()
601
- bucket = client.bucket(bucket_name)
602
- blob = bucket.get_blob(blob_name=object_name)
603
- if blob is None:
604
- raise ValueError(f"Object ({object_name}) not found in Bucket ({bucket_name})")
601
+ blob = self._get_blob(bucket_name, object_name)
605
602
  return blob.updated
606
603
 
607
604
  def is_updated_after(self, bucket_name: str, object_name: str, ts: datetime) -> bool:
@@ -957,19 +954,35 @@ class GCSHook(GoogleBaseHook):
957
954
  break
958
955
  return ids
959
956
 
960
- def get_size(self, bucket_name: str, object_name: str) -> int:
957
+ def _get_blob(self, bucket_name: str, object_name: str) -> Blob:
961
958
  """
962
- Get the size of a file in Google Cloud Storage.
959
+ Get a blob object in Google Cloud Storage.
963
960
 
964
961
  :param bucket_name: The Google Cloud Storage bucket where the blob_name is.
965
962
  :param object_name: The name of the object to check in the Google
966
963
  cloud storage bucket_name.
967
964
 
968
965
  """
969
- self.log.info("Checking the file size of object: %s in bucket_name: %s", object_name, bucket_name)
970
966
  client = self.get_conn()
971
967
  bucket = client.bucket(bucket_name)
972
968
  blob = bucket.get_blob(blob_name=object_name)
969
+
970
+ if blob is None:
971
+ raise ValueError(f"Object ({object_name}) not found in Bucket ({bucket_name})")
972
+
973
+ return blob
974
+
975
+ def get_size(self, bucket_name: str, object_name: str) -> int:
976
+ """
977
+ Get the size of a file in Google Cloud Storage.
978
+
979
+ :param bucket_name: The Google Cloud Storage bucket where the blob_name is.
980
+ :param object_name: The name of the object to check in the Google
981
+ cloud storage bucket_name.
982
+
983
+ """
984
+ self.log.info("Checking the file size of object: %s in bucket_name: %s", object_name, bucket_name)
985
+ blob = self._get_blob(bucket_name, object_name)
973
986
  blob_size = blob.size
974
987
  self.log.info("The file size of %s is %s bytes.", object_name, blob_size)
975
988
  return blob_size
@@ -987,9 +1000,7 @@ class GCSHook(GoogleBaseHook):
987
1000
  object_name,
988
1001
  bucket_name,
989
1002
  )
990
- client = self.get_conn()
991
- bucket = client.bucket(bucket_name)
992
- blob = bucket.get_blob(blob_name=object_name)
1003
+ blob = self._get_blob(bucket_name, object_name)
993
1004
  blob_crc32c = blob.crc32c
994
1005
  self.log.info("The crc32c checksum of %s is %s", object_name, blob_crc32c)
995
1006
  return blob_crc32c
@@ -1003,9 +1014,7 @@ class GCSHook(GoogleBaseHook):
1003
1014
  storage bucket_name.
1004
1015
  """
1005
1016
  self.log.info("Retrieving the MD5 hash of object: %s in bucket: %s", object_name, bucket_name)
1006
- client = self.get_conn()
1007
- bucket = client.bucket(bucket_name)
1008
- blob = bucket.get_blob(blob_name=object_name)
1017
+ blob = self._get_blob(bucket_name, object_name)
1009
1018
  blob_md5hash = blob.md5_hash
1010
1019
  self.log.info("The md5Hash of %s is %s", object_name, blob_md5hash)
1011
1020
  return blob_md5hash
@@ -1019,11 +1028,7 @@ class GCSHook(GoogleBaseHook):
1019
1028
  :return: The metadata associated with the object
1020
1029
  """
1021
1030
  self.log.info("Retrieving the metadata dict of object (%s) in bucket (%s)", object_name, bucket_name)
1022
- client = self.get_conn()
1023
- bucket = client.bucket(bucket_name)
1024
- blob = bucket.get_blob(blob_name=object_name)
1025
- if blob is None:
1026
- raise ValueError("Object (%s) not found in bucket (%s)", object_name, bucket_name)
1031
+ blob = self._get_blob(bucket_name, object_name)
1027
1032
  blob_metadata = blob.metadata
1028
1033
  if blob_metadata:
1029
1034
  self.log.info("Retrieved metadata of object (%s) with %s fields", object_name, len(blob_metadata))
@@ -129,12 +129,7 @@ class GCSTaskHandler(FileTaskHandler, LoggingMixin):
129
129
  )
130
130
 
131
131
  def set_context(self, ti: TaskInstance, *, identifier: str | None = None) -> None:
132
- # todo: remove-at-min-airflow-version-2.8
133
- # after Airflow 2.8 can always pass `identifier`
134
- if getattr(super(), "supports_task_context_logging", False):
135
- super().set_context(ti, identifier=identifier)
136
- else:
137
- super().set_context(ti)
132
+ super().set_context(ti, identifier=identifier)
138
133
  # Log relative path is used to construct local and remote
139
134
  # log path to upload log files into GCS and read from the
140
135
  # remote location.
@@ -34,7 +34,7 @@ from google.cloud.automl_v1beta1 import (
34
34
  TableSpec,
35
35
  )
36
36
 
37
- from airflow.exceptions import AirflowException
37
+ from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
38
38
  from airflow.providers.google.cloud.hooks.automl import CloudAutoMLHook
39
39
  from airflow.providers.google.cloud.hooks.vertex_ai.prediction_service import PredictionServiceHook
40
40
  from airflow.providers.google.cloud.links.translate import (
@@ -45,6 +45,7 @@ from airflow.providers.google.cloud.links.translate import (
45
45
  TranslationLegacyModelTrainLink,
46
46
  )
47
47
  from airflow.providers.google.cloud.operators.cloud_base import GoogleCloudBaseOperator
48
+ from airflow.providers.google.common.deprecated import deprecated
48
49
  from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID
49
50
 
50
51
  if TYPE_CHECKING:
@@ -338,6 +339,11 @@ class AutoMLPredictOperator(GoogleCloudBaseOperator):
338
339
  return PredictResponse.to_dict(result)
339
340
 
340
341
 
342
+ @deprecated(
343
+ planned_removal_date="January 01, 2025",
344
+ use_instead="airflow.providers.google.cloud.operators.vertex_ai.batch_prediction_job",
345
+ category=AirflowProviderDeprecationWarning,
346
+ )
341
347
  class AutoMLBatchPredictOperator(GoogleCloudBaseOperator):
342
348
  """
343
349
  Perform a batch prediction on Google Cloud AutoML.
@@ -432,11 +432,13 @@ class DataflowCreateJavaJobOperator(GoogleCloudBaseOperator):
432
432
  is_running = self.dataflow_hook.is_job_dataflow_running(
433
433
  name=self.job_name,
434
434
  variables=pipeline_options,
435
+ location=self.location,
435
436
  )
436
437
  while is_running and self.check_if_running == CheckJobRunning.WaitForRun:
437
438
  is_running = self.dataflow_hook.is_job_dataflow_running(
438
439
  name=self.job_name,
439
440
  variables=pipeline_options,
441
+ location=self.location,
440
442
  )
441
443
  if not is_running:
442
444
  pipeline_options["jobName"] = job_name
@@ -40,7 +40,11 @@ from google.cloud.dataproc_v1 import Batch, Cluster, ClusterStatus, JobStatus
40
40
 
41
41
  from airflow.configuration import conf
42
42
  from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
43
- from airflow.providers.google.cloud.hooks.dataproc import DataprocHook, DataProcJobBuilder
43
+ from airflow.providers.google.cloud.hooks.dataproc import (
44
+ DataprocHook,
45
+ DataProcJobBuilder,
46
+ DataprocResourceIsNotReadyError,
47
+ )
44
48
  from airflow.providers.google.cloud.hooks.gcs import GCSHook
45
49
  from airflow.providers.google.cloud.links.dataproc import (
46
50
  DATAPROC_BATCH_LINK,
@@ -593,6 +597,8 @@ class DataprocCreateClusterOperator(GoogleCloudBaseOperator):
593
597
  :param delete_on_error: If true the cluster will be deleted if created with ERROR state. Default
594
598
  value is true.
595
599
  :param use_if_exists: If true use existing cluster
600
+ :param num_retries_if_resource_is_not_ready: Optional. The number of retry for cluster creation request
601
+ when resource is not ready error appears.
596
602
  :param request_id: Optional. A unique id used to identify the request. If the server receives two
597
603
  ``DeleteClusterRequest`` requests with the same id, then the second request will be ignored and the
598
604
  first ``google.longrunning.Operation`` created and stored in the backend is returned.
@@ -639,6 +645,7 @@ class DataprocCreateClusterOperator(GoogleCloudBaseOperator):
639
645
  request_id: str | None = None,
640
646
  delete_on_error: bool = True,
641
647
  use_if_exists: bool = True,
648
+ num_retries_if_resource_is_not_ready: int = 0,
642
649
  retry: AsyncRetry | _MethodDefault | Retry = DEFAULT,
643
650
  timeout: float = 1 * 60 * 60,
644
651
  metadata: Sequence[tuple[str, str]] = (),
@@ -695,6 +702,7 @@ class DataprocCreateClusterOperator(GoogleCloudBaseOperator):
695
702
  self.virtual_cluster_config = virtual_cluster_config
696
703
  self.deferrable = deferrable
697
704
  self.polling_interval_seconds = polling_interval_seconds
705
+ self.num_retries_if_resource_is_not_ready = num_retries_if_resource_is_not_ready
698
706
 
699
707
  def _create_cluster(self, hook: DataprocHook):
700
708
  return hook.create_cluster(
@@ -729,20 +737,26 @@ class DataprocCreateClusterOperator(GoogleCloudBaseOperator):
729
737
  return
730
738
  self.log.info("Cluster is in ERROR state")
731
739
  self.log.info("Gathering diagnostic information.")
732
- operation = hook.diagnose_cluster(
733
- region=self.region, cluster_name=self.cluster_name, project_id=self.project_id
734
- )
735
- operation.result()
736
- gcs_uri = str(operation.operation.response.value)
737
- self.log.info("Diagnostic information for cluster %s available at: %s", self.cluster_name, gcs_uri)
738
-
739
- if self.delete_on_error:
740
- self._delete_cluster(hook)
741
- # The delete op is asynchronous and can cause further failure if the cluster finishes
742
- # deleting between catching AlreadyExists and checking state
743
- self._wait_for_cluster_in_deleting_state(hook)
744
- raise AirflowException("Cluster was created in an ERROR state then deleted.")
745
- raise AirflowException("Cluster was created but is in ERROR state")
740
+ try:
741
+ operation = hook.diagnose_cluster(
742
+ region=self.region, cluster_name=self.cluster_name, project_id=self.project_id
743
+ )
744
+ operation.result()
745
+ gcs_uri = str(operation.operation.response.value)
746
+ self.log.info(
747
+ "Diagnostic information for cluster %s available at: %s", self.cluster_name, gcs_uri
748
+ )
749
+ except Exception as diagnose_error:
750
+ self.log.info("Some error occurred when trying to diagnose cluster.")
751
+ self.log.exception(diagnose_error)
752
+ finally:
753
+ if self.delete_on_error:
754
+ self._delete_cluster(hook)
755
+ # The delete op is asynchronous and can cause further failure if the cluster finishes
756
+ # deleting between catching AlreadyExists and checking state
757
+ self._wait_for_cluster_in_deleting_state(hook)
758
+ raise AirflowException("Cluster was created in an ERROR state then deleted.")
759
+ raise AirflowException("Cluster was created but is in ERROR state")
746
760
 
747
761
  def _wait_for_cluster_in_deleting_state(self, hook: DataprocHook) -> None:
748
762
  time_left = self.timeout
@@ -780,6 +794,16 @@ class DataprocCreateClusterOperator(GoogleCloudBaseOperator):
780
794
  )
781
795
  return hook.wait_for_operation(timeout=self.timeout, result_retry=self.retry, operation=op)
782
796
 
797
+ def _retry_cluster_creation(self, hook: DataprocHook):
798
+ self.log.info("Retrying creation process for Cluster %s", self.cluster_name)
799
+ self._delete_cluster(hook)
800
+ self._wait_for_cluster_in_deleting_state(hook)
801
+ self.log.info("Starting a new creation for Cluster %s", self.cluster_name)
802
+ operation = self._create_cluster(hook)
803
+ cluster = hook.wait_for_operation(timeout=self.timeout, result_retry=self.retry, operation=operation)
804
+ self.log.info("Cluster created.")
805
+ return Cluster.to_dict(cluster)
806
+
783
807
  def execute(self, context: Context) -> dict:
784
808
  self.log.info("Creating cluster: %s", self.cluster_name)
785
809
  hook = DataprocHook(gcp_conn_id=self.gcp_conn_id, impersonation_chain=self.impersonation_chain)
@@ -829,6 +853,25 @@ class DataprocCreateClusterOperator(GoogleCloudBaseOperator):
829
853
  raise
830
854
  self.log.info("Cluster already exists.")
831
855
  cluster = self._get_cluster(hook)
856
+ except DataprocResourceIsNotReadyError as resource_not_ready_error:
857
+ if self.num_retries_if_resource_is_not_ready:
858
+ attempt = self.num_retries_if_resource_is_not_ready
859
+ while attempt > 0:
860
+ attempt -= 1
861
+ try:
862
+ cluster = self._retry_cluster_creation(hook)
863
+ except DataprocResourceIsNotReadyError:
864
+ continue
865
+ else:
866
+ return cluster
867
+ self.log.info(
868
+ "Retrying Cluster %s creation because of resource not ready was unsuccessful.",
869
+ self.cluster_name,
870
+ )
871
+ if self.delete_on_error:
872
+ self._delete_cluster(hook)
873
+ self._wait_for_cluster_in_deleting_state(hook)
874
+ raise resource_not_ready_error
832
875
  except AirflowException as ae:
833
876
  # There still could be a cluster created here in an ERROR state which
834
877
  # should be deleted immediately rather than consuming another retry attempt
@@ -2948,6 +2991,8 @@ class DataprocCreateBatchOperator(GoogleCloudBaseOperator):
2948
2991
  :param request_id: Optional. A unique id used to identify the request. If the server receives two
2949
2992
  ``CreateBatchRequest`` requests with the same id, then the second request will be ignored and
2950
2993
  the first ``google.longrunning.Operation`` created and stored in the backend is returned.
2994
+ :param num_retries_if_resource_is_not_ready: Optional. The number of retry for cluster creation request
2995
+ when resource is not ready error appears.
2951
2996
  :param retry: A retry object used to retry requests. If ``None`` is specified, requests will not be
2952
2997
  retried.
2953
2998
  :param result_retry: Result retry object used to retry requests. Is used to decrease delay between
@@ -2988,6 +3033,7 @@ class DataprocCreateBatchOperator(GoogleCloudBaseOperator):
2988
3033
  batch: dict | Batch,
2989
3034
  batch_id: str | None = None,
2990
3035
  request_id: str | None = None,
3036
+ num_retries_if_resource_is_not_ready: int = 0,
2991
3037
  retry: Retry | _MethodDefault = DEFAULT,
2992
3038
  timeout: float | None = None,
2993
3039
  metadata: Sequence[tuple[str, str]] = (),
@@ -3007,6 +3053,7 @@ class DataprocCreateBatchOperator(GoogleCloudBaseOperator):
3007
3053
  self.batch = batch
3008
3054
  self.batch_id = batch_id
3009
3055
  self.request_id = request_id
3056
+ self.num_retries_if_resource_is_not_ready = num_retries_if_resource_is_not_ready
3010
3057
  self.retry = retry
3011
3058
  self.result_retry = result_retry
3012
3059
  self.timeout = timeout
@@ -3028,6 +3075,14 @@ class DataprocCreateBatchOperator(GoogleCloudBaseOperator):
3028
3075
  if self.batch_id:
3029
3076
  batch_id = self.batch_id
3030
3077
  self.log.info("Starting batch %s", batch_id)
3078
+ # Persist the link earlier so users can observe the progress
3079
+ DataprocBatchLink.persist(
3080
+ context=context,
3081
+ operator=self,
3082
+ project_id=self.project_id,
3083
+ region=self.region,
3084
+ batch_id=self.batch_id,
3085
+ )
3031
3086
  else:
3032
3087
  self.log.info("Starting batch. The batch ID will be generated since it was not provided.")
3033
3088
 
@@ -3091,6 +3146,15 @@ class DataprocCreateBatchOperator(GoogleCloudBaseOperator):
3091
3146
  timeout=self.timeout,
3092
3147
  metadata=self.metadata,
3093
3148
  )
3149
+ if self.num_retries_if_resource_is_not_ready and self.hook.check_error_for_resource_is_not_ready_msg(
3150
+ batch.state_message
3151
+ ):
3152
+ attempt = self.num_retries_if_resource_is_not_ready
3153
+ while attempt > 0:
3154
+ attempt -= 1
3155
+ batch, batch_id = self.retry_batch_creation(batch_id)
3156
+ if not self.hook.check_error_for_resource_is_not_ready_msg(batch.state_message):
3157
+ break
3094
3158
 
3095
3159
  self.handle_batch_status(context, batch.state, batch_id, batch.state_message)
3096
3160
  return Batch.to_dict(batch)
@@ -3133,6 +3197,50 @@ class DataprocCreateBatchOperator(GoogleCloudBaseOperator):
3133
3197
  raise AirflowException(f"Batch job {batch_id} unspecified. Driver logs: {link}")
3134
3198
  self.log.info("Batch job %s completed. Driver logs: %s", batch_id, link)
3135
3199
 
3200
+ def retry_batch_creation(
3201
+ self,
3202
+ previous_batch_id: str,
3203
+ ):
3204
+ self.log.info("Retrying creation process for batch_id %s", self.batch_id)
3205
+ self.log.info("Deleting previous failed Batch")
3206
+ self.hook.delete_batch(
3207
+ batch_id=previous_batch_id,
3208
+ region=self.region,
3209
+ project_id=self.project_id,
3210
+ retry=self.retry,
3211
+ timeout=self.timeout,
3212
+ metadata=self.metadata,
3213
+ )
3214
+ self.log.info("Starting a new creation for batch_id %s", self.batch_id)
3215
+ try:
3216
+ self.operation = self.hook.create_batch(
3217
+ region=self.region,
3218
+ project_id=self.project_id,
3219
+ batch=self.batch,
3220
+ batch_id=self.batch_id,
3221
+ request_id=self.request_id,
3222
+ retry=self.retry,
3223
+ timeout=self.timeout,
3224
+ metadata=self.metadata,
3225
+ )
3226
+ except AlreadyExists:
3227
+ self.log.info("Batch with given id already exists.")
3228
+ self.log.info("Attaching to the job %s if it is still running.", self.batch_id)
3229
+ else:
3230
+ batch_id = self.operation.metadata.batch.split("/")[-1]
3231
+ self.log.info("The batch %s was created.", batch_id)
3232
+
3233
+ self.log.info("Waiting for the completion of batch job %s", batch_id)
3234
+ batch = self.hook.wait_for_batch(
3235
+ batch_id=batch_id,
3236
+ region=self.region,
3237
+ project_id=self.project_id,
3238
+ retry=self.retry,
3239
+ timeout=self.timeout,
3240
+ metadata=self.metadata,
3241
+ )
3242
+ return batch, batch_id
3243
+
3136
3244
 
3137
3245
  class DataprocDeleteBatchOperator(GoogleCloudBaseOperator):
3138
3246
  """
@@ -113,15 +113,14 @@ class CloudSpeechToTextRecognizeSpeechOperator(GoogleCloudBaseOperator):
113
113
  gcp_conn_id=self.gcp_conn_id,
114
114
  impersonation_chain=self.impersonation_chain,
115
115
  )
116
-
117
- FileDetailsLink.persist(
118
- context=context,
119
- task_instance=self,
120
- # Slice from: "gs://{BUCKET_NAME}/{FILE_NAME}" to: "{BUCKET_NAME}/{FILE_NAME}"
121
- uri=self.audio["uri"][5:],
122
- project_id=self.project_id or hook.project_id,
123
- )
124
-
116
+ if self.audio.uri:
117
+ FileDetailsLink.persist(
118
+ context=context,
119
+ task_instance=self,
120
+ # Slice from: "gs://{BUCKET_NAME}/{FILE_NAME}" to: "{BUCKET_NAME}/{FILE_NAME}"
121
+ uri=self.audio.uri[5:],
122
+ project_id=self.project_id or hook.project_id,
123
+ )
125
124
  response = hook.recognize_speech(
126
125
  config=self.config, audio=self.audio, retry=self.retry, timeout=self.timeout
127
126
  )
@@ -169,7 +169,14 @@ class CloudTranslateSpeechOperator(GoogleCloudBaseOperator):
169
169
  raise AirflowException(
170
170
  f"Wrong response '{recognize_dict}' returned - it should contain {key} field"
171
171
  )
172
-
172
+ if self.audio.uri:
173
+ FileDetailsLink.persist(
174
+ context=context,
175
+ task_instance=self,
176
+ # Slice from: "gs://{BUCKET_NAME}/{FILE_NAME}" to: "{BUCKET_NAME}/{FILE_NAME}"
177
+ uri=self.audio.uri[5:],
178
+ project_id=self.project_id or translate_hook.project_id,
179
+ )
173
180
  try:
174
181
  translation = translate_hook.translate(
175
182
  values=transcript,
@@ -179,12 +186,6 @@ class CloudTranslateSpeechOperator(GoogleCloudBaseOperator):
179
186
  model=self.model,
180
187
  )
181
188
  self.log.info("Translated output: %s", translation)
182
- FileDetailsLink.persist(
183
- context=context,
184
- task_instance=self,
185
- uri=self.audio["uri"][5:],
186
- project_id=self.project_id or translate_hook.project_id,
187
- )
188
189
  return translation
189
190
  except ValueError as e:
190
191
  self.log.error("An error has been thrown from translate speech method:")
@@ -22,6 +22,7 @@ from __future__ import annotations
22
22
  from datetime import timedelta
23
23
  from typing import TYPE_CHECKING, Any, Callable, Sequence
24
24
 
25
+ from google.cloud import pubsub_v1
25
26
  from google.cloud.pubsub_v1.types import ReceivedMessage
26
27
 
27
28
  from airflow.configuration import conf
@@ -34,6 +35,10 @@ if TYPE_CHECKING:
34
35
  from airflow.utils.context import Context
35
36
 
36
37
 
38
+ class PubSubMessageTransformException(AirflowException):
39
+ """Raise when messages failed to convert pubsub received format."""
40
+
41
+
37
42
  class PubSubPullSensor(BaseSensorOperator):
38
43
  """
39
44
  Pulls messages from a PubSub subscription and passes them through XCom.
@@ -170,7 +175,6 @@ class PubSubPullSensor(BaseSensorOperator):
170
175
  subscription=self.subscription,
171
176
  max_messages=self.max_messages,
172
177
  ack_messages=self.ack_messages,
173
- messages_callback=self.messages_callback,
174
178
  poke_interval=self.poke_interval,
175
179
  gcp_conn_id=self.gcp_conn_id,
176
180
  impersonation_chain=self.impersonation_chain,
@@ -178,14 +182,28 @@ class PubSubPullSensor(BaseSensorOperator):
178
182
  method_name="execute_complete",
179
183
  )
180
184
 
181
- def execute_complete(self, context: dict[str, Any], event: dict[str, str | list[str]]) -> str | list[str]:
182
- """Return immediately and relies on trigger to throw a success event. Callback for the trigger."""
185
+ def execute_complete(self, context: Context, event: dict[str, str | list[str]]) -> Any:
186
+ """If messages_callback is provided, execute it; otherwise, return immediately with trigger event message."""
183
187
  if event["status"] == "success":
184
188
  self.log.info("Sensor pulls messages: %s", event["message"])
189
+ if self.messages_callback:
190
+ received_messages = self._convert_to_received_messages(event["message"])
191
+ _return_value = self.messages_callback(received_messages, context)
192
+ return _return_value
193
+
185
194
  return event["message"]
186
195
  self.log.info("Sensor failed: %s", event["message"])
187
196
  raise AirflowException(event["message"])
188
197
 
198
+ def _convert_to_received_messages(self, messages: Any) -> list[ReceivedMessage]:
199
+ try:
200
+ received_messages = [pubsub_v1.types.ReceivedMessage(msg) for msg in messages]
201
+ return received_messages
202
+ except Exception as e:
203
+ raise PubSubMessageTransformException(
204
+ f"Error converting triggerer event message back to received message format: {e}"
205
+ )
206
+
189
207
  def _default_message_callback(
190
208
  self,
191
209
  pulled_messages: list[ReceivedMessage],
@@ -19,16 +19,14 @@
19
19
  from __future__ import annotations
20
20
 
21
21
  import asyncio
22
- from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Sequence
22
+ from functools import cached_property
23
+ from typing import Any, AsyncIterator, Sequence
24
+
25
+ from google.cloud.pubsub_v1.types import ReceivedMessage
23
26
 
24
27
  from airflow.providers.google.cloud.hooks.pubsub import PubSubAsyncHook
25
28
  from airflow.triggers.base import BaseTrigger, TriggerEvent
26
29
 
27
- if TYPE_CHECKING:
28
- from google.cloud.pubsub_v1.types import ReceivedMessage
29
-
30
- from airflow.utils.context import Context
31
-
32
30
 
33
31
  class PubsubPullTrigger(BaseTrigger):
34
32
  """
@@ -41,11 +39,6 @@ class PubsubPullTrigger(BaseTrigger):
41
39
  :param ack_messages: If True, each message will be acknowledged
42
40
  immediately rather than by any downstream tasks
43
41
  :param gcp_conn_id: Reference to google cloud connection id
44
- :param messages_callback: (Optional) Callback to process received messages.
45
- Its return value will be saved to XCom.
46
- If you are pulling large messages, you probably want to provide a custom callback.
47
- If not provided, the default implementation will convert `ReceivedMessage` objects
48
- into JSON-serializable dicts using `google.protobuf.json_format.MessageToDict` function.
49
42
  :param poke_interval: polling period in seconds to check for the status
50
43
  :param impersonation_chain: Optional service account to impersonate using short-term
51
44
  credentials, or chained list of accounts required to get the access_token
@@ -64,7 +57,6 @@ class PubsubPullTrigger(BaseTrigger):
64
57
  max_messages: int,
65
58
  ack_messages: bool,
66
59
  gcp_conn_id: str,
67
- messages_callback: Callable[[list[ReceivedMessage], Context], Any] | None = None,
68
60
  poke_interval: float = 10.0,
69
61
  impersonation_chain: str | Sequence[str] | None = None,
70
62
  ):
@@ -73,11 +65,9 @@ class PubsubPullTrigger(BaseTrigger):
73
65
  self.subscription = subscription
74
66
  self.max_messages = max_messages
75
67
  self.ack_messages = ack_messages
76
- self.messages_callback = messages_callback
77
68
  self.poke_interval = poke_interval
78
69
  self.gcp_conn_id = gcp_conn_id
79
70
  self.impersonation_chain = impersonation_chain
80
- self.hook = PubSubAsyncHook()
81
71
 
82
72
  def serialize(self) -> tuple[str, dict[str, Any]]:
83
73
  """Serialize PubsubPullTrigger arguments and classpath."""
@@ -88,7 +78,6 @@ class PubsubPullTrigger(BaseTrigger):
88
78
  "subscription": self.subscription,
89
79
  "max_messages": self.max_messages,
90
80
  "ack_messages": self.ack_messages,
91
- "messages_callback": self.messages_callback,
92
81
  "poke_interval": self.poke_interval,
93
82
  "gcp_conn_id": self.gcp_conn_id,
94
83
  "impersonation_chain": self.impersonation_chain,
@@ -106,7 +95,10 @@ class PubsubPullTrigger(BaseTrigger):
106
95
  ):
107
96
  if self.ack_messages:
108
97
  await self.message_acknowledgement(pulled_messages)
109
- yield TriggerEvent({"status": "success", "message": pulled_messages})
98
+
99
+ messages_json = [ReceivedMessage.to_dict(m) for m in pulled_messages]
100
+
101
+ yield TriggerEvent({"status": "success", "message": messages_json})
110
102
  return
111
103
  self.log.info("Sleeping for %s seconds.", self.poke_interval)
112
104
  await asyncio.sleep(self.poke_interval)
@@ -121,3 +113,11 @@ class PubsubPullTrigger(BaseTrigger):
121
113
  messages=pulled_messages,
122
114
  )
123
115
  self.log.info("Acknowledged ack_ids from subscription %s", self.subscription)
116
+
117
+ @cached_property
118
+ def hook(self) -> PubSubAsyncHook:
119
+ return PubSubAsyncHook(
120
+ gcp_conn_id=self.gcp_conn_id,
121
+ impersonation_chain=self.impersonation_chain,
122
+ project_id=self.project_id,
123
+ )
@@ -28,8 +28,9 @@ def get_provider_info():
28
28
  "name": "Google",
29
29
  "description": "Google services including:\n\n - `Google Ads <https://ads.google.com/>`__\n - `Google Cloud (GCP) <https://cloud.google.com/>`__\n - `Google Firebase <https://firebase.google.com/>`__\n - `Google LevelDB <https://github.com/google/leveldb/>`__\n - `Google Marketing Platform <https://marketingplatform.google.com/>`__\n - `Google Workspace <https://workspace.google.com/>`__ (formerly Google Suite)\n",
30
30
  "state": "ready",
31
- "source-date-epoch": 1726860901,
31
+ "source-date-epoch": 1728485162,
32
32
  "versions": [
33
+ "10.24.0",
33
34
  "10.23.0",
34
35
  "10.22.0",
35
36
  "10.21.1",
@@ -921,6 +922,10 @@ def get_provider_info():
921
922
  },
922
923
  ],
923
924
  "filesystems": ["airflow.providers.google.cloud.fs.gcs"],
925
+ "asset-uris": [
926
+ {"schemes": ["gcp"], "handler": None},
927
+ {"schemes": ["bigquery"], "handler": "airflow.providers.google.datasets.bigquery.sanitize_uri"},
928
+ ],
924
929
  "dataset-uris": [
925
930
  {"schemes": ["gcp"], "handler": None},
926
931
  {"schemes": ["bigquery"], "handler": "airflow.providers.google.datasets.bigquery.sanitize_uri"},
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apache-airflow-providers-google
3
- Version: 10.23.0
3
+ Version: 10.24.0
4
4
  Summary: Provider package apache-airflow-providers-google for Apache Airflow
5
5
  Keywords: airflow-provider,google,airflow,integration
6
6
  Author-email: Apache Software Foundation <dev@airflow.apache.org>
7
7
  Maintainer-email: Apache Software Foundation <dev@airflow.apache.org>
8
- Requires-Python: ~=3.8
8
+ Requires-Python: ~=3.9
9
9
  Description-Content-Type: text/x-rst
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Environment :: Console
@@ -15,7 +15,6 @@ Classifier: Intended Audience :: System Administrators
15
15
  Classifier: Framework :: Apache Airflow
16
16
  Classifier: Framework :: Apache Airflow :: Provider
17
17
  Classifier: License :: OSI Approved :: Apache Software License
18
- Classifier: Programming Language :: Python :: 3.8
19
18
  Classifier: Programming Language :: Python :: 3.9
20
19
  Classifier: Programming Language :: Python :: 3.10
21
20
  Classifier: Programming Language :: Python :: 3.11
@@ -108,8 +107,8 @@ Requires-Dist: apache-airflow-providers-sftp ; extra == "sftp"
108
107
  Requires-Dist: apache-airflow-providers-ssh ; extra == "ssh"
109
108
  Requires-Dist: apache-airflow-providers-trino ; extra == "trino"
110
109
  Project-URL: Bug Tracker, https://github.com/apache/airflow/issues
111
- Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-google/10.23.0/changelog.html
112
- Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-google/10.23.0
110
+ Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-google/10.24.0/changelog.html
111
+ Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-google/10.24.0
113
112
  Project-URL: Slack Chat, https://s.apache.org/airflow-slack
114
113
  Project-URL: Source Code, https://github.com/apache/airflow
115
114
  Project-URL: Twitter, https://twitter.com/ApacheAirflow
@@ -178,7 +177,7 @@ Provides-Extra: trino
178
177
 
179
178
  Package ``apache-airflow-providers-google``
180
179
 
181
- Release: ``10.23.0``
180
+ Release: ``10.24.0``
182
181
 
183
182
 
184
183
  Google services including:
@@ -198,7 +197,7 @@ This is a provider package for ``google`` provider. All classes for this provide
198
197
  are in ``airflow.providers.google`` python package.
199
198
 
200
199
  You can find package information and changelog for the provider
201
- in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-google/10.23.0/>`_.
200
+ in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-google/10.24.0/>`_.
202
201
 
203
202
  Installation
204
203
  ------------
@@ -207,7 +206,7 @@ You can install this package on top of an existing Airflow 2 installation (see `
207
206
  for the minimum Airflow version supported) via
208
207
  ``pip install apache-airflow-providers-google``
209
208
 
210
- The package supports the following python versions: 3.8,3.9,3.10,3.11,3.12
209
+ The package supports the following python versions: 3.9,3.10,3.11,3.12
211
210
 
212
211
  Requirements
213
212
  ------------
@@ -320,4 +319,4 @@ Dependent package
320
319
  ======================================================================================================================== ====================
321
320
 
322
321
  The changelog for the provider package can be found in the
323
- `changelog <https://airflow.apache.org/docs/apache-airflow-providers-google/10.23.0/changelog.html>`_.
322
+ `changelog <https://airflow.apache.org/docs/apache-airflow-providers-google/10.24.0/changelog.html>`_.
@@ -1,6 +1,6 @@
1
1
  airflow/providers/google/LICENSE,sha256=FFb4jd2AXnOOf7XLP04pQW6jbdhG49TxlGY6fFpCV1Y,13609
2
- airflow/providers/google/__init__.py,sha256=sMGFVct_ABQsayQ_2QxNDFdXJgTappCi9J26BK092Ew,1495
3
- airflow/providers/google/get_provider_info.py,sha256=ht4juR2pn4NyEaKYOq5l1JKVyy9gggcjC4YQIugAB3c,81987
2
+ airflow/providers/google/__init__.py,sha256=HCd-PmeEVd99eSEuOle0bVEuyyRdbC-TeYHy2An3dqw,1495
3
+ airflow/providers/google/get_provider_info.py,sha256=gJcV9EN6FkM8I98xA3n0KHMLwDVJxonPO04qrwBVj_E,82205
4
4
  airflow/providers/google/go_module_utils.py,sha256=XVM-IGME6CPgJA8fgDgkusFc4fz3lEghZaZ4elBkv7s,1780
5
5
  airflow/providers/google/ads/.gitignore,sha256=z_qaKzblF2LuVvP-06iDord9JBeyzIlNeJ4bx3LbtGc,167
6
6
  airflow/providers/google/ads/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
@@ -23,7 +23,7 @@ airflow/providers/google/cloud/fs/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2x
23
23
  airflow/providers/google/cloud/fs/gcs.py,sha256=fJBGhHEE46_U5Rmbs1W0uenvGhECv13CtVSh3z7pM60,2457
24
24
  airflow/providers/google/cloud/hooks/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
25
25
  airflow/providers/google/cloud/hooks/automl.py,sha256=5fp8vZ96at8jH-a4yYipu4FI3J809b2E6XLCOQVhzmY,28959
26
- airflow/providers/google/cloud/hooks/bigquery.py,sha256=JCnnwspuJ9IJJCPhfqRArPcXKjq082gQckcMl1qlcz4,157695
26
+ airflow/providers/google/cloud/hooks/bigquery.py,sha256=iTe6KLIzQWJl4Jp3Mz1KVmPWbRfrl9sOGiaLcVQ7jBs,157603
27
27
  airflow/providers/google/cloud/hooks/bigquery_dts.py,sha256=3wLKj-6tQwWphjwKBLGg1rjoXAAknv0WLh6T3MqsNWA,15228
28
28
  airflow/providers/google/cloud/hooks/bigtable.py,sha256=wReDIbDyQGP8oZIzg0vsfgD6zrLmY-oYghBNCPVPorw,12580
29
29
  airflow/providers/google/cloud/hooks/cloud_batch.py,sha256=FjpR_Av7z8oMnB4Q7S-aPTMO8HZMxAo_1akdHpE7iA8,7809
@@ -36,18 +36,18 @@ airflow/providers/google/cloud/hooks/cloud_storage_transfer_service.py,sha256=BI
36
36
  airflow/providers/google/cloud/hooks/compute.py,sha256=sBpi7oZjJwV4JPkWm3iKw23l7cAjHDET2MU9S8FOc58,40673
37
37
  airflow/providers/google/cloud/hooks/compute_ssh.py,sha256=GTSiuhDFpeN-7n8ggrF-XBaPQ2hfk80tWChGImYGpTo,15689
38
38
  airflow/providers/google/cloud/hooks/datacatalog.py,sha256=KoOcXUE-YhCR81wgHNJQ_YwTr5LYYyoDXTFJWZz_mds,54292
39
- airflow/providers/google/cloud/hooks/dataflow.py,sha256=QROW4JcCjzA_A_QRAWe729Qilklt0ACHt2HTtResXJk,71655
39
+ airflow/providers/google/cloud/hooks/dataflow.py,sha256=-FtTNvJ5bIEphLwobO4WpxVnV4erUcOEuV9K4p3lkxw,72002
40
40
  airflow/providers/google/cloud/hooks/dataform.py,sha256=fLeYwtFgXTZMhdqFKBzAA9VfsC5eQ92GycbmDApdg6Q,27796
41
41
  airflow/providers/google/cloud/hooks/datafusion.py,sha256=un_0r0fwiLPffNG-9tWN05FVWcx9ogaoLSI5XKUGHIg,26195
42
42
  airflow/providers/google/cloud/hooks/datapipeline.py,sha256=HPNO7tkQeb_N1JQZInZeO-YWZADcNLZZijjtVAKkWcE,2637
43
43
  airflow/providers/google/cloud/hooks/dataplex.py,sha256=hOAQ5gXBE0V6fw5Y_7Q8BymD6_GmFGsc8TPvd4SwJPM,38347
44
44
  airflow/providers/google/cloud/hooks/dataprep.py,sha256=GH46CoEMnc63RoMiJ7aKvsHlGFvsBl_QcRgbmWwJ5tU,12187
45
- airflow/providers/google/cloud/hooks/dataproc.py,sha256=L6NxhRIJpdAWUxrdwj9fi0vZ4MOkyMnF_BK90rwzumg,83954
45
+ airflow/providers/google/cloud/hooks/dataproc.py,sha256=q1kw1AJ1AjSFb2ylljJNHVryycOQMbhB_sxeZ6Yn0PU,84496
46
46
  airflow/providers/google/cloud/hooks/dataproc_metastore.py,sha256=Oh6I6PbawdCb0hkfrFNU4BVbxWangCcjIJdOBAh7q2Q,32152
47
47
  airflow/providers/google/cloud/hooks/datastore.py,sha256=JuXTZqL-FAohbKBHQVYLCS3tY9pvMDjlg-dSphKiyPU,12158
48
48
  airflow/providers/google/cloud/hooks/dlp.py,sha256=U1mnUEIQBcvh0bxf9RgeKLK2gjWx09qGh-hvCDOL_8k,67586
49
49
  airflow/providers/google/cloud/hooks/functions.py,sha256=Zz1MCy_6j4oG-SXeeiVdqo4Ld68pVQg4rIuSm7RrPEo,9290
50
- airflow/providers/google/cloud/hooks/gcs.py,sha256=vdaeNnu52Z1M_VV3HbHfC1FR0jIKou2cUXNCnzpgm-4,59925
50
+ airflow/providers/google/cloud/hooks/gcs.py,sha256=j7SO8bxDh_-sO0XdFvfhOA9RuAw325y-2ef3mnKXKwQ,59974
51
51
  airflow/providers/google/cloud/hooks/gdm.py,sha256=fCTu6SXtyQ3sn56GfIdgj6Myj_cc8UWdFVbYDMRMhZY,4123
52
52
  airflow/providers/google/cloud/hooks/kms.py,sha256=CSIoyXgfZOujEPWOk2bn2bmwcKuDWXCu8eFSvi8MV9w,6574
53
53
  airflow/providers/google/cloud/hooks/kubernetes_engine.py,sha256=VzpGcO8sf7FsAkLniatmvjyRpH_x2DV9cVYsl0ICAt4,24204
@@ -110,7 +110,7 @@ airflow/providers/google/cloud/links/translate.py,sha256=p0tHVr_CHPJswCmNheQAnpP
110
110
  airflow/providers/google/cloud/links/vertex_ai.py,sha256=T5WGK77wKIPTiHtxKuQXvokArjVQYwZPjX5IgJX1dds,11138
111
111
  airflow/providers/google/cloud/links/workflows.py,sha256=Ux7bwq2fspvSoNT4X3xFXX2SSmp8EuwDyPQsTO-z7bI,3303
112
112
  airflow/providers/google/cloud/log/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
113
- airflow/providers/google/cloud/log/gcs_task_handler.py,sha256=B2GEAFSdrQEYBZFDYShh2pTEVqJ-NR7qs67wBkxWawQ,10321
113
+ airflow/providers/google/cloud/log/gcs_task_handler.py,sha256=LeIK9lF7tpKDCid-AFxEIS23AanCmE92tlPH3NB8efc,10089
114
114
  airflow/providers/google/cloud/log/stackdriver_task_handler.py,sha256=5yh-Zgh2Me5BCrB_Nd52o5RP5gyv-tZjvOG2qnSZuRU,15526
115
115
  airflow/providers/google/cloud/openlineage/BigQueryErrorRunFacet.json,sha256=3whXAY38LjxmQTpCnExiIU1Q1-8dZGtWjiK0A4JQWTA,688
116
116
  airflow/providers/google/cloud/openlineage/BigQueryJobRunFacet.json,sha256=sWvE1o30bCqBBmB19n6wFZyL6BBcc22kCGWe0qcsYBc,850
@@ -118,7 +118,7 @@ airflow/providers/google/cloud/openlineage/__init__.py,sha256=9hdXHABrVpkbpjZgUf
118
118
  airflow/providers/google/cloud/openlineage/mixins.py,sha256=5blMJ1heK9rMYBWR5p-lBj1y_EA1qJyjfb-fwdBM31k,12908
119
119
  airflow/providers/google/cloud/openlineage/utils.py,sha256=iBeHh68qMumZ1pc-PWRBgQW8sycwmdtkJV-oCvYplPA,5781
120
120
  airflow/providers/google/cloud/operators/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
121
- airflow/providers/google/cloud/operators/automl.py,sha256=uZ-PSDqfBBviH0YWxh8gefr4DU5xiEkucYGRtSyDOG8,63479
121
+ airflow/providers/google/cloud/operators/automl.py,sha256=2S5gziRfU-3ptHNTHmRMXo9CfQcl8trNqPEqAVCRlZQ,63779
122
122
  airflow/providers/google/cloud/operators/bigquery.py,sha256=l8wLnRdCsH1IGWsxZrdb-YzHlyOssymQo19lnNgxdyA,131077
123
123
  airflow/providers/google/cloud/operators/bigquery_dts.py,sha256=6VJISM4HoMBQ3EQ5nz3zxFk8tfluGA1d2vcUNUlYLPc,17695
124
124
  airflow/providers/google/cloud/operators/bigtable.py,sha256=BnWHnTEscyPbsKWFaSreLr62W68fmHu5loQVZex7LPs,26921
@@ -132,13 +132,13 @@ airflow/providers/google/cloud/operators/cloud_sql.py,sha256=VA_RRg_Zv3zo4cKmpEf
132
132
  airflow/providers/google/cloud/operators/cloud_storage_transfer_service.py,sha256=YQsVg8pDegEDvsWsZCbGrSqCln3iQyLQErZS_XZTnBo,48066
133
133
  airflow/providers/google/cloud/operators/compute.py,sha256=lFGCacevkKJvAszJhfSLAOfetlsbYrCoImTeWXS5bqw,74607
134
134
  airflow/providers/google/cloud/operators/datacatalog.py,sha256=TY0KZtphd28mNmZF4f3pV-G4-K61nwlOzBok1ZHqG_E,92962
135
- airflow/providers/google/cloud/operators/dataflow.py,sha256=eWGyhI3BnS6eoLHkgGtodEnIemIbKL4-YpKJdBC4v5E,79819
135
+ airflow/providers/google/cloud/operators/dataflow.py,sha256=xwo0KFuHv85Wo_HESrQd1YsaWt3AKDEoiQ20GkqvOuk,79911
136
136
  airflow/providers/google/cloud/operators/dataform.py,sha256=MkRDkn12gm2PJHOIfCs61N8nTuF3bfrcbWT4zSCXOdI,48745
137
137
  airflow/providers/google/cloud/operators/datafusion.py,sha256=mXBCOhKVfHc1ZudMIT9UgBWL8w9qwBwnxTDWEO-xegA,41557
138
138
  airflow/providers/google/cloud/operators/datapipeline.py,sha256=OuF0RxHpQxqPDjCq3jNpiOTEQHQgL5UXwNo7sk5fpEA,2362
139
139
  airflow/providers/google/cloud/operators/dataplex.py,sha256=IgGwt95uW72IeLi1oHpGk8V0fKyt9apsc4kUpBz_7YQ,91195
140
140
  airflow/providers/google/cloud/operators/dataprep.py,sha256=jTDDgRccd2zIUqGzJebZpbNTJsFdRi5RnMtldXHqiMs,10477
141
- airflow/providers/google/cloud/operators/dataproc.py,sha256=SV0AL50fmraX7CqlkBduImH8wN6ld76sVTdkVCFxGgY,151960
141
+ airflow/providers/google/cloud/operators/dataproc.py,sha256=GBdojsHucUR1FAo1YG8OSyuBXrQn_HVGwWq5-ciXJl0,156776
142
142
  airflow/providers/google/cloud/operators/dataproc_metastore.py,sha256=mJOqDv4GEqQ7tx32ar-mMsPhIjYC_B1AZyiVDZBKOio,50402
143
143
  airflow/providers/google/cloud/operators/datastore.py,sha256=di00jFy3Z1v0GcmcQ0df8NJ32yxcseOqWuojC4TKdmY,24927
144
144
  airflow/providers/google/cloud/operators/dlp.py,sha256=SQCGml0RIKl0UrvXHIUiOskg5ayTj4F5_4k4rztClvM,120742
@@ -151,12 +151,12 @@ airflow/providers/google/cloud/operators/mlengine.py,sha256=AyJJDekzHN65PSRYfVbs
151
151
  airflow/providers/google/cloud/operators/natural_language.py,sha256=mVi1R1QXU_aJXEGgyPiQXxAWlmOEInia6DpayxGhRwo,13719
152
152
  airflow/providers/google/cloud/operators/pubsub.py,sha256=oo7nXjlexuLmp_-NHDa0Ko3vn15Sl81iTFfH0MGf-kQ,35508
153
153
  airflow/providers/google/cloud/operators/spanner.py,sha256=Gpzr1LNB3e2zLaOb-LwORR9Vv9tMTDzNIcyV728u7Pw,24938
154
- airflow/providers/google/cloud/operators/speech_to_text.py,sha256=ZVuE1m1nSta0HUzsK6azVslnIf1PC2edRsG7LqHPmy4,5646
154
+ airflow/providers/google/cloud/operators/speech_to_text.py,sha256=AcMK8aY9OqVPwWSBfzZJEYB2oZM7C0NaTbvmXJMqwmQ,5696
155
155
  airflow/providers/google/cloud/operators/stackdriver.py,sha256=Tei_f5oodxTp4K-m15U_M98_WhZr3v0JynTzlJHDOws,39205
156
156
  airflow/providers/google/cloud/operators/tasks.py,sha256=zy3kgQkcVLx9a7r1Ojsk5-crVOzmmKC7_dO9WuKTwDY,48427
157
157
  airflow/providers/google/cloud/operators/text_to_speech.py,sha256=y51bA2Ksr8NvaBKFn2dZBV3K04YqAu47yssK86t9MtQ,6956
158
158
  airflow/providers/google/cloud/operators/translate.py,sha256=yYN4IRcRHXllZsChMJd71UDMigdD2iKid9G27jIVOlM,5007
159
- airflow/providers/google/cloud/operators/translate_speech.py,sha256=ALehMdOuSspEb-7h9Cr5ml8TYFsUnc8vvHEULpKZxa4,7817
159
+ airflow/providers/google/cloud/operators/translate_speech.py,sha256=UjI-quI4IcgDZ_X4925mb9aQiI7yLIi2m4txieowYn4,7935
160
160
  airflow/providers/google/cloud/operators/video_intelligence.py,sha256=NQvEueDegdpPBSqMkJF_qb9x3WeZT7XJL-yE8Sqlz_U,14165
161
161
  airflow/providers/google/cloud/operators/vision.py,sha256=iKEEj33nVLrHUcJr2sE72NC1mAAZ7Gz-_XGdLgO4dqA,67720
162
162
  airflow/providers/google/cloud/operators/workflows.py,sha256=fnyWLqRHz0UYu6AnQKKZIMlfSIg_v5nNbZAt6ASe4fI,28977
@@ -187,7 +187,7 @@ airflow/providers/google/cloud/sensors/dataproc.py,sha256=ANSRHFkApFjb-GVt1SBiRw
187
187
  airflow/providers/google/cloud/sensors/dataproc_metastore.py,sha256=h4ToV-9FpKqE_4Gsmt7GButSB2hrcthb4JlfFU2o6Ik,5432
188
188
  airflow/providers/google/cloud/sensors/gcs.py,sha256=S6FohDoiQQJPm4DvdW4NVpcGHRdl3HlR-vJuA8pIGzY,24490
189
189
  airflow/providers/google/cloud/sensors/looker.py,sha256=zwtfCjxoowBoR3iuHlVpKzgwuN4ft6WGy2gzojlflvo,3609
190
- airflow/providers/google/cloud/sensors/pubsub.py,sha256=MvMQ6-iXZHMTCs5i0psKvEmP6DjVe-PE71t3ZBi4xC4,8977
190
+ airflow/providers/google/cloud/sensors/pubsub.py,sha256=gzo0uaPom-R_FPttRZD1ENX6hFeq_2VD-C9_u-lNRu0,9742
191
191
  airflow/providers/google/cloud/sensors/tasks.py,sha256=Y2t5OYIH98tsIN7G2LwSKnYZsOAUCkLqoOYMdQvYlHc,3485
192
192
  airflow/providers/google/cloud/sensors/workflows.py,sha256=Lsp_F9wYDtC0KtWvoQq0B8oBzFuX1PF3du7abnW2Esc,5133
193
193
  airflow/providers/google/cloud/transfers/__init__.py,sha256=9hdXHABrVpkbpjZgUft39kOFL2xSGeG4GEua0Hmelus,785
@@ -237,7 +237,7 @@ airflow/providers/google/cloud/triggers/dataproc.py,sha256=xK2tZdS2gZTAqgQEQ9kQ9
237
237
  airflow/providers/google/cloud/triggers/gcs.py,sha256=pMjeNOkWHkOyiAxeK-JoyDInUf2VNtefOZxp8K-aNjw,18973
238
238
  airflow/providers/google/cloud/triggers/kubernetes_engine.py,sha256=OWjts1J4TIZWiXPP3GpE2mZTNneTfFAhnK0fpapVcE4,15689
239
239
  airflow/providers/google/cloud/triggers/mlengine.py,sha256=qpOa9Gz8FmHDxXvPWrXO3M7snGbRTq92gy6kGafCUiY,5265
240
- airflow/providers/google/cloud/triggers/pubsub.py,sha256=3t6foghoMpa_I_al8IQMkmxktqpcZbcuIhMIOe1MvZo,5604
240
+ airflow/providers/google/cloud/triggers/pubsub.py,sha256=IbomKaGpO1qbF3bpM7cF7rWY2X6T7D1UttHq08hq1tg,5234
241
241
  airflow/providers/google/cloud/triggers/vertex_ai.py,sha256=IKeVp6p5weU-G_3SgIqwCK__vt_q0NAavgBpWmLfLqI,9932
242
242
  airflow/providers/google/cloud/utils/__init__.py,sha256=mlJxuZLkd5x-iq2SBwD3mvRQpt3YR7wjz_nceyF1IaI,787
243
243
  airflow/providers/google/cloud/utils/bigquery.py,sha256=nMPUMpfsf-7QQEJG3wo1QqKuPGPwDUwKLGhE9SBjCaI,2145
@@ -310,7 +310,7 @@ airflow/providers/google/suite/transfers/gcs_to_gdrive.py,sha256=CxtVhp3wlEOBtjR
310
310
  airflow/providers/google/suite/transfers/gcs_to_sheets.py,sha256=4nwXWkTySeBXNuThPxzO7uww_hH6PthpppTeuShn27Q,4363
311
311
  airflow/providers/google/suite/transfers/local_to_drive.py,sha256=ZSK0b1Rd6x_xsP2DVcUzeYu3qoo9Bsp3VmnKyBsFRH8,6105
312
312
  airflow/providers/google/suite/transfers/sql_to_sheets.py,sha256=sORkYSUDArRPnvi8WCiXP7YIXtpAgpEPhf8cqgpu644,5220
313
- apache_airflow_providers_google-10.23.0.dist-info/entry_points.txt,sha256=Ay1Uo7uHxdXCxWew3CyBHumZ44Ld-iR7AcSR2fY-PLw,102
314
- apache_airflow_providers_google-10.23.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
315
- apache_airflow_providers_google-10.23.0.dist-info/METADATA,sha256=XrjgnsEHMrI5psXWdWWKmlCoj6rPIS7rASo8fJQTS58,17245
316
- apache_airflow_providers_google-10.23.0.dist-info/RECORD,,
313
+ apache_airflow_providers_google-10.24.0.dist-info/entry_points.txt,sha256=Ay1Uo7uHxdXCxWew3CyBHumZ44Ld-iR7AcSR2fY-PLw,102
314
+ apache_airflow_providers_google-10.24.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
315
+ apache_airflow_providers_google-10.24.0.dist-info/METADATA,sha256=E4nXJ-g-KYQRTW388l-AtGr4sy0ckOnUgTIhQ4bXZhY,17191
316
+ apache_airflow_providers_google-10.24.0.dist-info/RECORD,,