This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 25c100c870a Emit GCSToGCSOperator deprecation warnings after rendering
(#70449)
25c100c870a is described below
commit 25c100c870a15bb96b6fc9d4562f7a0c8277fe19
Author: Haseeb Malik <[email protected]>
AuthorDate: Fri Jul 31 14:20:09 2026 -0400
Emit GCSToGCSOperator deprecation warnings after rendering (#70449)
---
.../providers/google/cloud/transfers/gcs_to_gcs.py | 40 +++++++-------
.../unit/google/cloud/transfers/test_gcs_to_gcs.py | 63 +++++++++++++---------
.../ci/prek/validate_operators_init_exemptions.txt | 1 -
3 files changed, 60 insertions(+), 44 deletions(-)
diff --git
a/providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_gcs.py
b/providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_gcs.py
index aa027e71d85..b6f7e4f3729 100644
---
a/providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_gcs.py
+++
b/providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_gcs.py
@@ -217,28 +217,10 @@ class GCSToGCSOperator(BaseOperator):
super().__init__(**kwargs)
self.source_bucket = source_bucket
- if source_object and WILDCARD in source_object:
- warnings.warn(
- "Usage of wildcard (*) in 'source_object' is deprecated,
utilize 'match_glob' instead. Planned removal date: October 5, 2026.",
- AirflowProviderDeprecationWarning,
- stacklevel=2,
- )
self.source_object = source_object
- if source_objects and any(WILDCARD in obj for obj in source_objects):
- warnings.warn(
- "Usage of wildcard (*) in 'source_objects' is deprecated,
utilize 'match_glob' instead. Planned removal date: October 5, 2026.",
- AirflowProviderDeprecationWarning,
- stacklevel=2,
- )
self.source_objects = source_objects
self.destination_bucket = destination_bucket
self.destination_object = destination_object
- if delimiter:
- warnings.warn(
- "Usage of 'delimiter' is deprecated, please use 'match_glob'
instead. Planned removal date: October 5, 2026.",
- AirflowProviderDeprecationWarning,
- stacklevel=2,
- )
self.delimiter = delimiter
self.move_object = move_object
self.replace = replace
@@ -253,7 +235,29 @@ class GCSToGCSOperator(BaseOperator):
self.retain_until_time = retain_until_time
self.retention_mode = retention_mode
+ def _warn_on_deprecated_template_fields(self) -> None:
+ if self.source_object and WILDCARD in self.source_object:
+ warnings.warn(
+ "Usage of wildcard (*) in 'source_object' is deprecated,
utilize 'match_glob' instead. Planned removal date: October 5, 2026.",
+ AirflowProviderDeprecationWarning,
+ stacklevel=2,
+ )
+ if self.source_objects and any(WILDCARD in obj for obj in
self.source_objects):
+ warnings.warn(
+ "Usage of wildcard (*) in 'source_objects' is deprecated,
utilize 'match_glob' instead. Planned removal date: October 5, 2026.",
+ AirflowProviderDeprecationWarning,
+ stacklevel=2,
+ )
+ if self.delimiter:
+ warnings.warn(
+ "Usage of 'delimiter' is deprecated, please use 'match_glob'
instead. Planned removal date: October 5, 2026.",
+ AirflowProviderDeprecationWarning,
+ stacklevel=2,
+ )
+
def execute(self, context: Context) -> list[str]:
+ self._warn_on_deprecated_template_fields()
+
hook = GCSHook(
gcp_conn_id=self.gcp_conn_id,
impersonation_chain=self.impersonation_chain,
diff --git
a/providers/google/tests/unit/google/cloud/transfers/test_gcs_to_gcs.py
b/providers/google/tests/unit/google/cloud/transfers/test_gcs_to_gcs.py
index 7bbfa1c2285..bfd2c8f586f 100644
--- a/providers/google/tests/unit/google/cloud/transfers/test_gcs_to_gcs.py
+++ b/providers/google/tests/unit/google/cloud/transfers/test_gcs_to_gcs.py
@@ -24,7 +24,7 @@ import pytest
from airflow.exceptions import AirflowProviderDeprecationWarning
from airflow.providers.common.compat.openlineage.facet import Dataset
-from airflow.providers.common.compat.sdk import AirflowException
+from airflow.providers.common.compat.sdk import DAG, AirflowException
from airflow.providers.google.cloud.transfers.gcs_to_gcs import WILDCARD,
GCSToGCSOperator
TASK_ID = "test-gcs-to-gcs-operator"
@@ -1035,25 +1035,19 @@ class TestGoogleCloudStorageToCloudStorageOperator:
def test_get_openlineage_facets_on_complete(
self, mock_hook, source_objects, destination_object, inputs, outputs
):
+ operator = GCSToGCSOperator(
+ task_id=TASK_ID,
+ source_bucket=TEST_BUCKET,
+ source_objects=source_objects,
+ destination_bucket=DESTINATION_BUCKET,
+ destination_object=destination_object,
+ )
+
if source_objects and any(WILDCARD in obj for obj in source_objects):
with pytest.warns(AirflowProviderDeprecationWarning, match="Usage
of wildcard"):
- operator = GCSToGCSOperator(
- task_id=TASK_ID,
- source_bucket=TEST_BUCKET,
- source_objects=source_objects,
- destination_bucket=DESTINATION_BUCKET,
- destination_object=destination_object,
- )
+ operator.execute(None)
else:
- operator = GCSToGCSOperator(
- task_id=TASK_ID,
- source_bucket=TEST_BUCKET,
- source_objects=source_objects,
- destination_bucket=DESTINATION_BUCKET,
- destination_object=destination_object,
- )
-
- operator.execute(None)
+ operator.execute(None)
lineage = operator.get_openlineage_facets_on_complete(None)
assert len(lineage.inputs) == len(inputs)
@@ -1082,15 +1076,15 @@ class TestGoogleCloudStorageToCloudStorageOperator:
@mock.patch("airflow.providers.google.cloud.transfers.gcs_to_gcs.GCSHook")
def test_execute_returns_list_of_destination_uris_multiple_files(self,
mock_hook):
mock_hook.return_value.list.return_value = SOURCE_OBJECTS_LIST
+ operator = GCSToGCSOperator(
+ task_id=TASK_ID,
+ source_bucket=TEST_BUCKET,
+ source_object=SOURCE_OBJECT_WILDCARD_FILENAME,
+ destination_bucket=DESTINATION_BUCKET,
+ destination_object=DESTINATION_OBJECT_PREFIX,
+ )
with pytest.warns(AirflowProviderDeprecationWarning, match="Usage of
wildcard"):
- operator = GCSToGCSOperator(
- task_id=TASK_ID,
- source_bucket=TEST_BUCKET,
- source_object=SOURCE_OBJECT_WILDCARD_FILENAME,
- destination_bucket=DESTINATION_BUCKET,
- destination_object=DESTINATION_OBJECT_PREFIX,
- )
- result = operator.execute(None)
+ result = operator.execute(None)
expected = [
f"gs://{DESTINATION_BUCKET}/foo/bar/file1.txt",
f"gs://{DESTINATION_BUCKET}/foo/bar/file2.txt",
@@ -1098,6 +1092,25 @@ class TestGoogleCloudStorageToCloudStorageOperator:
]
assert sorted(result) == sorted(expected)
+ @mock.patch("airflow.providers.google.cloud.transfers.gcs_to_gcs.GCSHook")
+ def test_wildcard_deprecation_warning_uses_rendered_source_object(self,
mock_hook):
+ mock_hook.return_value.list.return_value = SOURCE_OBJECTS_LIST
+ with DAG(dag_id="test_gcs_to_gcs_wildcard_templating",
start_date=datetime(2024, 1, 1)) as dag:
+ operator = GCSToGCSOperator(
+ task_id=TASK_ID,
+ source_bucket=TEST_BUCKET,
+ source_object="{{ params.source_object }}",
+ destination_bucket=DESTINATION_BUCKET,
+ destination_object=DESTINATION_OBJECT_PREFIX,
+ dag=dag,
+ )
+
+ operator.render_template_fields({"params": {"source_object":
SOURCE_OBJECT_WILDCARD_FILENAME}})
+ assert operator.source_object == SOURCE_OBJECT_WILDCARD_FILENAME
+
+ with pytest.warns(AirflowProviderDeprecationWarning, match="Usage of
wildcard"):
+ operator.execute(mock.MagicMock())
+
@mock.patch("airflow.providers.google.cloud.transfers.gcs_to_gcs.GCSHook")
def test_execute_returns_empty_list_when_no_files_copied(self, mock_hook):
mock_hook.return_value.is_updated_after.return_value = False
diff --git a/scripts/ci/prek/validate_operators_init_exemptions.txt
b/scripts/ci/prek/validate_operators_init_exemptions.txt
index 345248323f5..6c4907fbded 100644
--- a/scripts/ci/prek/validate_operators_init_exemptions.txt
+++ b/scripts/ci/prek/validate_operators_init_exemptions.txt
@@ -23,7 +23,6 @@
providers/google/src/airflow/providers/google/cloud/sensors/cloud_composer.py::C
providers/google/src/airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py::AzureFileShareToGCSOperator
providers/google/src/airflow/providers/google/cloud/transfers/bigquery_to_mssql.py::BigQueryToMsSqlOperator
providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_bigquery.py::GCSToBigQueryOperator
-providers/google/src/airflow/providers/google/cloud/transfers/gcs_to_gcs.py::GCSToGCSOperator
providers/google/src/airflow/providers/google/marketing_platform/operators/campaign_manager.py::GoogleCampaignManagerDeleteReportOperator
providers/microsoft/azure/src/airflow/providers/microsoft/azure/transfers/gcs_to_wasb.py::GCSToAzureBlobStorageOperator
providers/microsoft/psrp/src/airflow/providers/microsoft/psrp/operators/psrp.py::PsrpOperator