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

weilee pushed a commit to branch v3-0-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-0-test by this push:
     new 4c43bb98fe4 [v3-0-test] Fix Jinja2 Template deep copy error with 
``dag.test`` (#51670) (#51673)
4c43bb98fe4 is described below

commit 4c43bb98fe4b8bdafce126c0989fc0c8b73da4c8
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Jun 13 08:58:13 2025 +0800

    [v3-0-test] Fix Jinja2 Template deep copy error with ``dag.test`` (#51670) 
(#51673)
    
    The `dag.test` method currently (in 3.0.2) clears dag runs before running ( 
[code](https://github.com/apache/airflow/blob/3.0.2/task-sdk/src/airflow/sdk/definitions/dag.py#L1092-L1097)
 ) the dag. For that it uses `SchedulerDAG.clear_dags`, which create 
`SchedulerDAG` from Task SDK DAG -- to do that it uses 
[`deepcopy.copy`](https://github.com/apache/airflow/blob/3.0.2/airflow-core/src/airflow/models/dag.py#L1797).
    
    Now that works for most cases, but not where `jinja2.Template` class is 
passed as a Task/Operator argument because of [this 
issue](https://github.com/pallets/jinja/issues/758).
    
    ```python
    In [1]: from copy import deepcopy
       ...:
       ...: from jinja2 import Template
       ...:
       ...: deepcopy(Template(''))
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    Cell In[1], line 5
          1 from copy import deepcopy
          3 from jinja2 import Template
    ----> 5 deepcopy(Template(''))
    
    File 
~/.local/share/uv/python/cpython-3.12.8-macos-aarch64-none/lib/python3.12/copy.py:162,
 in deepcopy(x, memo, _nil)
        160                 y = x
        161             else:
    --> 162                 y = _reconstruct(x, memo, *rv)
        164 # If is its own copy, don't memoize.
        165 if y is not x:
    
    File 
~/.local/share/uv/python/cpython-3.12.8-macos-aarch64-none/lib/python3.12/copy.py:253,
 in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
        251 if deep and args:
        252     args = (deepcopy(arg, memo) for arg in args)
    --> 253 y = func(*args)
        254 if deep:
        255     memo[id(x)] = y
    
    File 
~/.local/share/uv/python/cpython-3.12.8-macos-aarch64-none/lib/python3.12/copyreg.py:99,
 in __newobj__(cls, *args)
         98 def __newobj__(cls, *args):
    ---> 99     return cls.__new__(cls, *args)
    
    TypeError: Template.__new__() missing 1 required positional argument: 
'source'
    ```
    
    This is a general issue that can affect any DAG using custom arguments that 
store or cache Jinja2 Template objects or similar.
    Clearly, the longer term solution for dag.test is to not use SchedulerDAG 
like that and instead call some task Execution endpoint to clear dagruns -- but 
this works for 3.0.x.
    (cherry picked from commit 75f8aa9)
    
    Co-authored-by: Kaxil Naik <kaxiln...@gmail.com>
---
 airflow-core/src/airflow/models/dag.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/airflow-core/src/airflow/models/dag.py 
b/airflow-core/src/airflow/models/dag.py
index 57c1050e3ce..77f96d590cc 100644
--- a/airflow-core/src/airflow/models/dag.py
+++ b/airflow-core/src/airflow/models/dag.py
@@ -1794,7 +1794,7 @@ class DAG(TaskSDKDag, LoggingMixin):
             if isinstance(task, TaskGroup):
                 return task_group_map[task.group_id]
 
-            new_task = copy.deepcopy(task)
+            new_task = copy.copy(task)
 
             # Only overwrite the specific attributes we want to change
             new_task.task_id = task.task_id

Reply via email to