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 80e7e9b0381 Fix Neo4jOperator templated query validation (#70348)
80e7e9b0381 is described below

commit 80e7e9b03817c8487e183fef0f891351991040e8
Author: fat-catTW <[email protected]>
AuthorDate: Fri Jul 24 16:13:49 2026 +0800

    Fix Neo4jOperator templated query validation (#70348)
---
 .../src/airflow/providers/neo4j/operators/neo4j.py   | 18 +++++++++++-------
 .../neo4j/tests/unit/neo4j/operators/test_neo4j.py   | 20 ++++++++++++--------
 .../ci/prek/validate_operators_init_exemptions.txt   |  1 -
 3 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/providers/neo4j/src/airflow/providers/neo4j/operators/neo4j.py 
b/providers/neo4j/src/airflow/providers/neo4j/operators/neo4j.py
index 170204288a8..0c2a6538ad4 100644
--- a/providers/neo4j/src/airflow/providers/neo4j/operators/neo4j.py
+++ b/providers/neo4j/src/airflow/providers/neo4j/operators/neo4j.py
@@ -63,16 +63,20 @@ class Neo4jOperator(BaseOperator):
                 AirflowProviderDeprecationWarning,
                 stacklevel=2,
             )
-            if cypher is not None:
-                raise ValueError("Cannot provide both `sql` and `cypher`. Use 
`cypher` only.")
-            cypher = sql
-        if cypher is None:
-            raise ValueError("Parameter `cypher` is required.")
         self.neo4j_conn_id = neo4j_conn_id
         self.cypher = cypher
+        self.sql = sql
         self.parameters = parameters
 
     def execute(self, context: Context) -> None:
-        self.log.info("Executing: %s", self.cypher)
+        cypher = self.cypher
+        if self.sql is not None:
+            if cypher is not None:
+                raise ValueError("Cannot provide both `sql` and `cypher`. Use 
`cypher` only.")
+            cypher = self.render_template(self.sql, context)
+        if cypher is None:
+            raise ValueError("Parameter `cypher` is required.")
+
+        self.log.info("Executing: %s", cypher)
         hook = Neo4jHook(conn_id=self.neo4j_conn_id)
-        hook.run(self.cypher, self.parameters)
+        hook.run(cypher, self.parameters)
diff --git a/providers/neo4j/tests/unit/neo4j/operators/test_neo4j.py 
b/providers/neo4j/tests/unit/neo4j/operators/test_neo4j.py
index fb75adc3faa..3cebcfaffcb 100644
--- a/providers/neo4j/tests/unit/neo4j/operators/test_neo4j.py
+++ b/providers/neo4j/tests/unit/neo4j/operators/test_neo4j.py
@@ -61,16 +61,20 @@ class TestNeo4jOperator:
             AirflowProviderDeprecationWarning,
             match="`sql` parameter is deprecated, please use `cypher` 
instead.",
         ):
-            op = Neo4jOperator(task_id="basic_neo4j", sql=cypher)
-        assert op.cypher == cypher
-        op.execute(mock.MagicMock())
+            op = Neo4jOperator(task_id="basic_neo4j", sql="{{ cypher }}")
+        assert op.sql == "{{ cypher }}"
+        op.execute({"cypher": cypher})
         mock_hook.return_value.run.assert_called_once_with(cypher, None)
 
-    def test_neo4j_operator_both_sql_and_cypher_raises(self):
+    def test_neo4j_operator_both_sql_and_cypher_raises_on_execute(self):
         with pytest.warns(AirflowProviderDeprecationWarning):
-            with pytest.raises(ValueError, match="Cannot provide both `sql` 
and `cypher`"):
-                Neo4jOperator(task_id="basic_neo4j", sql="a", cypher="b")
+            op = Neo4jOperator(task_id="basic_neo4j", sql="a", cypher="b")
+
+        with pytest.raises(ValueError, match="Cannot provide both `sql` and 
`cypher`"):
+            op.execute(mock.MagicMock())
+
+    def test_neo4j_operator_missing_cypher_raises_on_execute(self):
+        op = Neo4jOperator(task_id="basic_neo4j")
 
-    def test_neo4j_operator_missing_cypher_raises(self):
         with pytest.raises(ValueError, match="Parameter `cypher` is 
required."):
-            Neo4jOperator(task_id="basic_neo4j")
+            op.execute(mock.MagicMock())
diff --git a/scripts/ci/prek/validate_operators_init_exemptions.txt 
b/scripts/ci/prek/validate_operators_init_exemptions.txt
index 2f3a91c6b04..db9e1ad7ce8 100644
--- a/scripts/ci/prek/validate_operators_init_exemptions.txt
+++ b/scripts/ci/prek/validate_operators_init_exemptions.txt
@@ -64,7 +64,6 @@ 
providers/google/src/airflow/providers/google/marketing_platform/operators/campa
 
providers/microsoft/azure/src/airflow/providers/microsoft/azure/transfers/gcs_to_wasb.py::GCSToAzureBlobStorageOperator
 
providers/microsoft/azure/src/airflow/providers/microsoft/azure/transfers/oracle_to_azure_data_lake.py::OracleToAzureDataLakeOperator
 
providers/microsoft/psrp/src/airflow/providers/microsoft/psrp/operators/psrp.py::PsrpOperator
-providers/neo4j/src/airflow/providers/neo4j/operators/neo4j.py::Neo4jOperator
 
providers/oracle/src/airflow/providers/oracle/transfers/oracle_to_oracle.py::OracleToOracleOperator
 
providers/papermill/src/airflow/providers/papermill/operators/papermill.py::PapermillOperator
 providers/ssh/src/airflow/providers/ssh/operators/ssh.py::SSHOperator

Reply via email to