@@ -27,6 +27,18 @@ class DummyOperator(BaseOperator):
2727 template_fields = ("name" ,)
2828
2929
30+ class OperatorWithExtraTemplateFields (BaseOperator ):
31+ """Operator whose template_fields do NOT all exist on the trigger."""
32+
33+ template_fields = ("bash_command" , "env" , "name" )
34+
35+ def __init__ (self , bash_command = "" , env = None , name = "" , ** kwargs ):
36+ super ().__init__ (** kwargs )
37+ self .bash_command = bash_command
38+ self .env = env
39+ self .name = name
40+
41+
3042class DummyTrigger (BaseTrigger ):
3143 def __init__ (self , name : str , ** kwargs ):
3244 super ().__init__ (** kwargs )
@@ -67,3 +79,62 @@ def test_render_template_fields(create_task_instance):
6779 trigger .render_template_fields (context = {"name" : "world" })
6880
6981 assert trigger .name == "Hello world"
82+
83+
84+ @pytest .mark .db_test
85+ def test_render_template_fields_filters_to_trigger_kwargs (create_task_instance ):
86+ """Only fields present in both trigger_kwargs and on the trigger should be rendered.
87+
88+ Operator template_fields like 'bash_command' and 'env' that don't exist on the
89+ trigger must be excluded to avoid AttributeError.
90+ """
91+ op = OperatorWithExtraTemplateFields (
92+ task_id = "extra_fields_task" ,
93+ bash_command = "echo hello" ,
94+ env = {"KEY" : "val" },
95+ name = "static" ,
96+ )
97+ ti = create_task_instance (
98+ task = op ,
99+ start_from_trigger = True ,
100+ start_trigger_args = StartTriggerArgs (
101+ trigger_cls = f"{ DummyTrigger .__module__ } .{ DummyTrigger .__qualname__ } " ,
102+ next_method = "resume_method" ,
103+ trigger_kwargs = {"name" : "Hello {{ name }}" },
104+ ),
105+ )
106+
107+ trigger = DummyTrigger (name = "Hello {{ name }}" )
108+ trigger .task_instance = ti
109+
110+ # Only 'name' should be in template_fields; 'bash_command' and 'env' are excluded
111+ # because they aren't keys in trigger_kwargs or don't exist on the trigger.
112+ assert trigger .template_fields == ("name" ,)
113+
114+ # Rendering must not raise AttributeError for missing operator fields
115+ trigger .render_template_fields (context = {"name" : "world" })
116+ assert trigger .name == "Hello world"
117+
118+
119+ @pytest .mark .db_test
120+ def test_render_template_fields_empty_when_no_trigger_kwargs (create_task_instance ):
121+ """When start_trigger_args has no trigger_kwargs, template_fields should be empty."""
122+ op = DummyOperator (task_id = "no_kwargs_task" )
123+ ti = create_task_instance (
124+ task = op ,
125+ start_from_trigger = True ,
126+ start_trigger_args = StartTriggerArgs (
127+ trigger_cls = f"{ DummyTrigger .__module__ } .{ DummyTrigger .__qualname__ } " ,
128+ next_method = "resume_method" ,
129+ trigger_kwargs = None ,
130+ ),
131+ )
132+
133+ trigger = DummyTrigger (name = "Hello {{ name }}" )
134+ trigger .task_instance = ti
135+
136+ assert trigger .template_fields == ()
137+
138+ # Rendering with empty template_fields is a no-op
139+ trigger .render_template_fields (context = {"name" : "world" })
140+ assert trigger .name == "Hello {{ name }}"
0 commit comments