@@ -174,6 +174,16 @@ def interpolate_component(
174174 # @DESIGN: Determine return signature from callable info (cached inspection) ?
175175 callable_info = get_callable_info (component_callable )
176176 kwargs = _prep_component_kwargs (callable_info , resolved_attrs , system = system_dict )
177+
178+ # @DESIGN: We can try to wrap this type resolution up but it is
179+ # hard to tell component authors what should be returned if we have this
180+ # union, and this is actually the simplified one without iterable, bool or
181+ # Node.
182+
183+ # Component() ->
184+ # None | Template | tuple[None | Template, dict[str, object]] |
185+ # Callable[[], None | Template | tuple[None | Template, dict[str, object]]]
186+
177187 res = component_callable (** kwargs )
178188
179189 # @DESIGN: callable or has_attr('__call__') for class components?
@@ -184,17 +194,34 @@ def interpolate_component(
184194
185195 # @DESIGN: Determine return signature via runtime inspection?
186196 if isinstance (res , tuple ):
187- result_template , comp_info = res
197+ if len (res ) != 2 :
198+ raise ValueError (
199+ f"Tuple form of component return value must be len() 2, not: { len (res )} "
200+ )
201+ else :
202+ result_template , comp_info = res
203+
204+ # @DESIGN: Use open-ended dict for opt-in second return argument?
188205 context_values = comp_info .get ("context_values" , ()) if comp_info else ()
206+ for entry in context_values :
207+ if not isinstance (entry , tuple ):
208+ raise ValueError (
209+ f"Entries for context_values must be 2-tuples but found type: { type (entry )} ."
210+ )
211+ elif len (entry ) != 2 :
212+ raise ValueError (
213+ f"Entries for context_values must be 2-tuples but found len(): { len (entry )} ."
214+ )
215+ elif not isinstance (entry [0 ], ContextVar ):
216+ raise ValueError (
217+ f"Invalid context variable in component return value: { type (entry [0 ])} "
218+ )
189219 else :
190220 result_template = res
191221 comp_info = None
192222 context_values = ()
193223
194- # @DESIGN: Use open-ended dict for opt-in second return argument?
195- context_values = comp_info .get ("context_values" , ()) if comp_info else ()
196-
197- if result_template :
224+ if isinstance (result_template , Template ):
198225 result_struct = render_api .transform_api .transform_template (result_template )
199226 if context_values :
200227 walker = render_api .walk_template_with_context (
@@ -203,6 +230,10 @@ def interpolate_component(
203230 else :
204231 walker = render_api .walk_template (bf , result_template , result_struct )
205232 return (container_tag , iter (walker ))
233+ elif result_template is None :
234+ pass
235+ else :
236+ raise ValueError (f"Unknown component return value: { type (result_template )} " )
206237
207238
208239type InterpolateRawTextInfo = tuple [str , Template ]
0 commit comments