This is an automated email from the ASF dual-hosted git repository.

shahar1 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 b25d19102b1 Move template-field validation out of init for Amazon 
DataSync operator (#70324)
b25d19102b1 is described below

commit b25d19102b1d38724c78df9224536a4f2bd7e1fd
Author: Mustafa Avcu <[email protected]>
AuthorDate: Fri Jul 24 01:11:34 2026 -0400

    Move template-field validation out of init for Amazon DataSync operator 
(#70324)
---
 .../providers/amazon/aws/operators/datasync.py     | 28 ++++++++--------
 .../unit/amazon/aws/operators/test_datasync.py     | 37 ++++++++++++++--------
 .../ci/prek/validate_operators_init_exemptions.txt |  1 -
 3 files changed, 38 insertions(+), 28 deletions(-)

diff --git 
a/providers/amazon/src/airflow/providers/amazon/aws/operators/datasync.py 
b/providers/amazon/src/airflow/providers/amazon/aws/operators/datasync.py
index 9345278ad53..1b97ec399af 100644
--- a/providers/amazon/src/airflow/providers/amazon/aws/operators/datasync.py
+++ b/providers/amazon/src/airflow/providers/amazon/aws/operators/datasync.py
@@ -174,19 +174,6 @@ class DataSyncOperator(AwsBaseOperator[DataSyncHook]):
         self.task_execution_kwargs = task_execution_kwargs or {}
         self.delete_task_after_execution = delete_task_after_execution
 
-        # Validations
-        valid = False
-        if self.task_arn:
-            valid = True
-        if self.source_location_uri and self.destination_location_uri:
-            valid = True
-        if not valid:
-            raise AirflowException(
-                f"Either specify task_arn or both source_location_uri and 
destination_location_uri. "
-                f"task_arn={task_arn!r}, 
source_location_uri={source_location_uri!r}, "
-                f"destination_location_uri={destination_location_uri!r}"
-            )
-
         # Candidates - these are found in AWS as possible things
         # for us to use
         self.candidate_source_location_arns: list[str] | None = None
@@ -201,7 +188,22 @@ class DataSyncOperator(AwsBaseOperator[DataSyncHook]):
     def _hook_parameters(self) -> dict[str, Any]:
         return {**super()._hook_parameters, "wait_interval_seconds": 
self.wait_interval_seconds}
 
+    def validate_inputs(self) -> None:
+        valid = False
+        if self.task_arn:
+            valid = True
+        if self.source_location_uri and self.destination_location_uri:
+            valid = True
+        if not valid:
+            raise AirflowException(
+                f"Either specify task_arn or both source_location_uri and 
destination_location_uri. "
+                f"task_arn={self.task_arn!r}, 
source_location_uri={self.source_location_uri!r}, "
+                f"destination_location_uri={self.destination_location_uri!r}"
+            )
+
     def execute(self, context: Context):
+        self.validate_inputs()
+
         # If task_arn was not specified then try to
         # find 0, 1 or many candidate DataSync Tasks to run
         if not self.task_arn:
diff --git a/providers/amazon/tests/unit/amazon/aws/operators/test_datasync.py 
b/providers/amazon/tests/unit/amazon/aws/operators/test_datasync.py
index 2addb0ce539..40a9f8788f9 100644
--- a/providers/amazon/tests/unit/amazon/aws/operators/test_datasync.py
+++ b/providers/amazon/tests/unit/amazon/aws/operators/test_datasync.py
@@ -206,17 +206,20 @@ class TestDataSyncOperatorCreate(DataSyncTestCaseBase):
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
-    def test_init_fails(self, mock_get_conn):
+    def test_execute_fails(self, mock_get_conn):
         # ### Set up mocks:
         mock_get_conn.return_value = self.client
         # ### Begin tests:
 
+        self.set_up_operator(task_id="task_1", source_location_uri=None)
         with pytest.raises(AirflowException):
-            self.set_up_operator(source_location_uri=None)
+            self.datasync.execute(None)
+        self.set_up_operator(task_id="task_2", destination_location_uri=None)
         with pytest.raises(AirflowException):
-            self.set_up_operator(destination_location_uri=None)
+            self.datasync.execute(None)
+        self.set_up_operator(task_id="task_3", source_location_uri=None, 
destination_location_uri=None)
         with pytest.raises(AirflowException):
-            self.set_up_operator(source_location_uri=None, 
destination_location_uri=None)
+            self.datasync.execute(None)
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
@@ -430,17 +433,20 @@ class TestDataSyncOperatorGetTasks(DataSyncTestCaseBase):
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
-    def test_init_fails(self, mock_get_conn):
+    def test_execute_fails(self, mock_get_conn):
         # ### Set up mocks:
         mock_get_conn.return_value = self.client
         # ### Begin tests:
 
+        self.set_up_operator(task_id="task_1", source_location_uri=None)
         with pytest.raises(AirflowException):
-            self.set_up_operator(source_location_uri=None)
+            self.datasync.execute(None)
+        self.set_up_operator(task_id="task_2", destination_location_uri=None)
         with pytest.raises(AirflowException):
-            self.set_up_operator(destination_location_uri=None)
+            self.datasync.execute(None)
+        self.set_up_operator(task_id="task_3", source_location_uri=None, 
destination_location_uri=None)
         with pytest.raises(AirflowException):
-            self.set_up_operator(source_location_uri=None, 
destination_location_uri=None)
+            self.datasync.execute(None)
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
@@ -640,13 +646,14 @@ class TestDataSyncOperatorUpdate(DataSyncTestCaseBase):
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
-    def test_init_fails(self, mock_get_conn):
+    def test_execute_fails(self, mock_get_conn):
         # ### Set up mocks:
         mock_get_conn.return_value = self.client
         # ### Begin tests:
 
+        self.set_up_operator(task_arn=None)
         with pytest.raises(AirflowException):
-            self.set_up_operator(task_arn=None)
+            self.datasync.execute(None)
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
@@ -761,13 +768,14 @@ class TestDataSyncOperator(DataSyncTestCaseBase):
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
-    def test_init_fails(self, mock_get_conn):
+    def test_execute_fails(self, mock_get_conn):
         # ### Set up mocks:
         mock_get_conn.return_value = self.client
         # ### Begin tests:
 
+        self.set_up_operator(task_arn=None)
         with pytest.raises(AirflowException):
-            self.set_up_operator(task_arn=None)
+            self.datasync.execute(None)
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
@@ -973,13 +981,14 @@ class TestDataSyncOperatorDelete(DataSyncTestCaseBase):
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
-    def test_init_fails(self, mock_get_conn):
+    def test_execute_fails(self, mock_get_conn):
         # ### Set up mocks:
         mock_get_conn.return_value = self.client
         # ### Begin tests:
 
+        self.set_up_operator(task_arn=None)
         with pytest.raises(AirflowException):
-            self.set_up_operator(task_arn=None)
+            self.datasync.execute(None)
         # ### Check mocks:
         mock_get_conn.assert_not_called()
 
diff --git a/scripts/ci/prek/validate_operators_init_exemptions.txt 
b/scripts/ci/prek/validate_operators_init_exemptions.txt
index 01fd5bc56db..22a82b96ff5 100644
--- a/scripts/ci/prek/validate_operators_init_exemptions.txt
+++ b/scripts/ci/prek/validate_operators_init_exemptions.txt
@@ -9,7 +9,6 @@
 
providers/amazon/src/airflow/providers/amazon/aws/operators/appflow.py::AppflowBaseOperator
 
providers/amazon/src/airflow/providers/amazon/aws/operators/bedrock.py::BedrockCreateKnowledgeBaseOperator
 
providers/amazon/src/airflow/providers/amazon/aws/operators/bedrock.py::BedrockRaGOperator
-providers/amazon/src/airflow/providers/amazon/aws/operators/datasync.py::DataSyncOperator
 
providers/amazon/src/airflow/providers/amazon/aws/operators/dms.py::DmsModifyTaskOperator
 
providers/amazon/src/airflow/providers/amazon/aws/operators/dms.py::DmsStartReplicationOperator
 
providers/amazon/src/airflow/providers/amazon/aws/operators/ecs.py::EcsRunTaskOperator

Reply via email to