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 dbb5c7ffff9 Fail Neo4jOperator argument mistakes at Dag parse time
(#70508)
dbb5c7ffff9 is described below
commit dbb5c7ffff9cd5a83a5b24191dd5027b67957d7a
Author: Jyun-An Chen <[email protected]>
AuthorDate: Thu Jul 30 14:22:05 2026 +0800
Fail Neo4jOperator argument mistakes at Dag parse time (#70508)
Whether `cypher` or `sql` was passed is a property of how the Dag was
written, not of the rendered value, and the constructor is the only place
that can read it: under render_template_as_native_obj a supplied field can
render to None, so the same check in execute reports an argument the author
did provide as missing. Checking at construction also surfaces the mistake
as a Dag import error instead of once per task instance.
The execute guard stays: a passed field can still render to None and the
hook needs a query string.
related: #70503
---
.../neo4j/src/airflow/providers/neo4j/operators/neo4j.py | 8 ++++++--
providers/neo4j/tests/unit/neo4j/operators/test_neo4j.py | 16 +++++++++-------
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/providers/neo4j/src/airflow/providers/neo4j/operators/neo4j.py
b/providers/neo4j/src/airflow/providers/neo4j/operators/neo4j.py
index e0d1e1b1538..7bc55df65c6 100644
--- a/providers/neo4j/src/airflow/providers/neo4j/operators/neo4j.py
+++ b/providers/neo4j/src/airflow/providers/neo4j/operators/neo4j.py
@@ -57,6 +57,10 @@ class Neo4jOperator(BaseOperator):
**kwargs,
) -> None:
super().__init__(**kwargs)
+ if sql is not None and cypher is not None:
+ raise ValueError("Cannot provide both `sql` and `cypher`. Use
`cypher` only.")
+ if cypher is None and sql is None:
+ raise ValueError("Parameter `cypher` is required.")
self.neo4j_conn_id = neo4j_conn_id
self.cypher = cypher
self.sql = sql
@@ -70,10 +74,10 @@ class Neo4jOperator(BaseOperator):
AirflowProviderDeprecationWarning,
stacklevel=2,
)
- if cypher is not None:
- raise ValueError("Cannot provide both `sql` and `cypher`. Use
`cypher` only.")
cypher = self.sql
if cypher is None:
+ # The constructor only sees whether the argument was passed; a
passed field can still
+ # render to None, and the hook needs a query string.
raise ValueError("Parameter `cypher` is required.")
self.log.info("Executing: %s", cypher)
diff --git a/providers/neo4j/tests/unit/neo4j/operators/test_neo4j.py
b/providers/neo4j/tests/unit/neo4j/operators/test_neo4j.py
index 3399cdb6cce..bd1c6e77509 100644
--- a/providers/neo4j/tests/unit/neo4j/operators/test_neo4j.py
+++ b/providers/neo4j/tests/unit/neo4j/operators/test_neo4j.py
@@ -66,15 +66,17 @@ class TestNeo4jOperator:
op.execute(mock.MagicMock())
mock_hook.return_value.run.assert_called_once_with(cypher, None)
- def test_neo4j_operator_both_sql_and_cypher_raises_on_execute(self):
- op = Neo4jOperator(task_id="basic_neo4j", sql="a", cypher="b")
+ def test_neo4j_operator_both_sql_and_cypher_raises(self):
+ with pytest.raises(ValueError, match="Cannot provide both `sql` and
`cypher`"):
+ Neo4jOperator(task_id="basic_neo4j", sql="a", cypher="b")
- with pytest.warns(AirflowProviderDeprecationWarning):
- with pytest.raises(ValueError, match="Cannot provide both `sql`
and `cypher`"):
- op.execute(mock.MagicMock())
+ def test_neo4j_operator_missing_cypher_raises(self):
+ with pytest.raises(ValueError, match="Parameter `cypher` is
required."):
+ Neo4jOperator(task_id="basic_neo4j")
- def test_neo4j_operator_missing_cypher_raises_on_execute(self):
- op = Neo4jOperator(task_id="basic_neo4j")
+ def test_neo4j_operator_cypher_rendering_to_none_raises_on_execute(self):
+ op = Neo4jOperator(task_id="basic_neo4j", cypher="{{ missing }}")
+ op.cypher = None
with pytest.raises(ValueError, match="Parameter `cypher` is
required."):
op.execute(mock.MagicMock())