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 805a37cc03c Clarify template field validator guidance (#71210)
805a37cc03c is described below

commit 805a37cc03c5e4063f3c4f07d097eeae272b700d
Author: Mihir Duvedi <[email protected]>
AuthorDate: Fri Aug 7 22:20:15 2026 +0530

    Clarify template field validator guidance (#71210)
    
    The existing diagnostic obscures the documented provision-check exception 
and has led contributors toward incorrect fixes. Surface the distinction at the 
point of failure.
    
    Co-authored-by: Mihir Duvedi 
<[email protected]>
---
 scripts/ci/prek/validate_operators_init.py            |  8 +++++---
 scripts/tests/ci/prek/test_validate_operators_init.py | 13 +++++++++++++
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/scripts/ci/prek/validate_operators_init.py 
b/scripts/ci/prek/validate_operators_init.py
index 664d3e4e471..86d25180508 100755
--- a/scripts/ci/prek/validate_operators_init.py
+++ b/scripts/ci/prek/validate_operators_init.py
@@ -403,9 +403,11 @@ def _check_constructor_field_logic(
     if findings:
         console.print(
             f"{class_node.name}'s constructor applies logic to template 
fields. Template fields "
-            f"are rendered after the constructor runs, so validation or 
transformation here acts "
-            f"on the un-rendered Jinja expression and should move to execute() 
"
-            f"(see contributing-docs/05_pull_requests.rst):"
+            f"are rendered after the constructor runs, so value-dependent 
validation or transformation "
+            f"here acts on the un-rendered Jinja expression and should run in 
execute() or another method "
+            f"called after rendering. Checks that only ask whether an argument 
was passed belong in "
+            f"__init__ and should use explicit is None / is not None 
comparisons rather than truthiness. "
+            f"See 
https://github.com/apache/airflow/issues/70296#false-positives";
         )
         for lineno in sorted(findings):
             source = source_lines[lineno - 1].strip() if lineno <= 
len(source_lines) else ""
diff --git a/scripts/tests/ci/prek/test_validate_operators_init.py 
b/scripts/tests/ci/prek/test_validate_operators_init.py
index 4546a173ca7..45302516bb1 100644
--- a/scripts/tests/ci/prek/test_validate_operators_init.py
+++ b/scripts/tests/ci/prek/test_validate_operators_init.py
@@ -23,6 +23,7 @@ from pathlib import Path
 
 import pytest
 import validate_operators_init
+from rich.text import Text
 from validate_operators_init import (
     _check_constructor_field_logic,
     _check_constructor_template_fields,
@@ -131,6 +132,18 @@ class TestConstructorFieldLogic:
     def test_flags_logic_but_not_sanctioned_patterns(self, ctor_body: str, 
expected: int):
         assert _logic_findings(_operator_code(ctor_body), ["foo"]) == expected
 
+    def test_failure_message_explains_provision_check_exception(self):
+        code = _operator_code("self._validate(foo)\nself.foo = foo")
+        with validate_operators_init.console.capture() as capture:
+            assert _logic_findings(code, ["foo"]) == 1
+
+        output = " ".join(Text.from_ansi(capture.get()).plain.split())
+        assert "value-dependent validation or transformation" in output
+        assert "whether an argument was passed" in output
+        assert "is None" in output
+        assert "is not None" in output
+        assert 
"https://github.com/apache/airflow/issues/70296#false-positives"; in output
+
     def test_name_in_parameter_default_is_not_the_field(self):
         # A field named like a module (e.g. "conf") used in a parameter 
default evaluates at
         # class-definition scope and must not be flagged.

Reply via email to