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

jedcunningham 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 c1fcbefd712 Fix nested non-Dag with-statement exiting the Dag context 
in version inflation checker (#68795)
c1fcbefd712 is described below

commit c1fcbefd71256cc47cafc2cb989a0ac58838035a
Author: Pradeep Kalluri <[email protected]>
AuthorDate: Fri Aug 21 16:44:26 2026 +0100

    Fix nested non-Dag with-statement exiting the Dag context in version 
inflation checker (#68795)
    
    AirflowRuntimeVaryingValueChecker.visit_With() called exit_dag_context()
    unconditionally at the end of every with-statement. When a non-DAG
    with-statement (e.g. `with open(...) as f`) was nested inside a DAG
    with-block, it would set is_in_dag_context=False, causing any tasks
    constructed AFTER the nested with — but still inside the DAG block —
    to be invisible to the checker. Those tasks were never flagged for
    runtime-varying values even when they used datetime.now(), random(), etc.
    
    Fix: guard the exit_dag_context() call with `if is_with_dag_context`
    so only the with-statement that actually entered the DAG context exits it.
    
    Regression tests added for:
    - nested non-DAG with followed by a task (primary case)
    - multiple successive nested non-DAG withs
    - task constructed inside a nested non-DAG with
    - task outside the DAG block not over-flagged after the fix
---
 .../airflow/utils/dag_version_inflation_checker.py |  6 +-
 .../utils/test_dag_version_inflation_checker.py    | 77 ++++++++++++++++++++++
 2 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/airflow-core/src/airflow/utils/dag_version_inflation_checker.py 
b/airflow-core/src/airflow/utils/dag_version_inflation_checker.py
index 2314b94a126..06fa96a7faa 100644
--- a/airflow-core/src/airflow/utils/dag_version_inflation_checker.py
+++ b/airflow-core/src/airflow/utils/dag_version_inflation_checker.py
@@ -513,8 +513,10 @@ class AirflowRuntimeVaryingValueChecker(ast.NodeVisitor):
         for body in node.body:
             self.visit(body)
 
-        # Exit Dag with block
-        self.dag_detector.exit_dag_context()
+        # Only exit Dag with block if we entered it; unconditional exit would 
prematurely
+        # reset the context when a non-DAG with-statement is nested inside a 
DAG with block.
+        if is_with_dag_context:
+            self.dag_detector.exit_dag_context()
 
     def visit_FunctionDef(self, node: ast.FunctionDef):
         for decorator in node.decorator_list:
diff --git 
a/airflow-core/tests/unit/utils/test_dag_version_inflation_checker.py 
b/airflow-core/tests/unit/utils/test_dag_version_inflation_checker.py
index 8d858523be4..035375c01f3 100644
--- a/airflow-core/tests/unit/utils/test_dag_version_inflation_checker.py
+++ b/airflow-core/tests/unit/utils/test_dag_version_inflation_checker.py
@@ -812,3 +812,80 @@ with DAG(
 """
         warnings = self._check_code(code)
         assert len(warnings) == 1
+
+    def test_nested_non_dag_with_does_not_exit_dag_context(self):
+        """Regression test: a non-DAG with-statement nested inside a DAG 
with-block must not
+        prematurely exit the DAG context.
+
+        Before the fix, visit_With() called exit_dag_context() unconditionally 
regardless of
+        whether a DAG context was entered. This meant any nested non-DAG 
with-statement (e.g.,
+        ``with open(...) as f``) would reset is_in_dag_context=False, causing 
tasks that appear
+        AFTER the nested with-statement (but still inside the DAG with-block) 
to be missed.
+        """
+        code = """
+from airflow import DAG
+from datetime import datetime
+from airflow.operators.bash import BashOperator
+
+with DAG('my_dag') as dag:
+    with open('some_file.txt') as f:   # non-DAG with — must not exit DAG 
context
+        data = f.read()
+    # This task is still inside the DAG block and uses datetime.now() — must 
be flagged
+    t1 = BashOperator(
+        task_id='test',
+        bash_command=str(datetime.now()),
+    )
+"""
+        warnings = self._check_code(code)
+        assert len(warnings) == 1, (
+            "BashOperator after a nested non-DAG with-statement must still be 
detected "
+            "as inside the DAG context and flagged for using datetime.now()"
+        )
+
+    def test_multiple_nested_non_dag_withs_do_not_exit_dag_context(self):
+        """Multiple successive non-DAG with-statements inside a DAG block must 
not exit the context."""
+        code = """
+from airflow import DAG
+from datetime import datetime
+from airflow.operators.bash import BashOperator
+
+with DAG('my_dag') as dag:
+    with open('a.txt') as f1:
+        pass
+    with open('b.txt') as f2:
+        pass
+    t1 = BashOperator(task_id='t', bash_command=str(datetime.now()))
+"""
+        warnings = self._check_code(code)
+        assert len(warnings) == 1
+
+    def test_task_inside_nested_non_dag_with_is_still_flagged(self):
+        """A task constructed inside a nested non-DAG with-block is still in 
DAG context."""
+        code = """
+from airflow import DAG
+from datetime import datetime
+from airflow.operators.bash import BashOperator
+
+with DAG('my_dag') as dag:
+    with open('a.txt') as f:
+        t1 = BashOperator(task_id='t', bash_command=str(datetime.now()))
+"""
+        warnings = self._check_code(code)
+        assert len(warnings) == 1
+
+    def test_task_outside_dag_with_not_flagged_after_nested_fix(self):
+        """Tasks genuinely outside any DAG block must not be flagged — the fix 
must not over-flag."""
+        code = """
+from airflow import DAG
+from datetime import datetime
+from airflow.operators.bash import BashOperator
+
+with DAG('my_dag') as dag:
+    with open('a.txt') as f:
+        pass
+
+# This task is outside the DAG with block — should NOT be flagged
+t_outside = BashOperator(task_id='outside', bash_command=str(datetime.now()))
+"""
+        warnings = self._check_code(code)
+        assert len(warnings) == 0, "A task constructed outside the DAG 
with-block must not be flagged"

Reply via email to