33import json
44from collections .abc import Awaitable , Callable , Sequence
55from itertools import chain
6- from types import GenericAlias
6+ from types import GenericAlias , NoneType
77from typing import Annotated , Any , cast , get_args , get_origin , get_type_hints
88
99import anyio
@@ -148,7 +148,7 @@ def pre_parse_json(self, data: dict[str, Any]) -> dict[str, Any]:
148148 continue
149149
150150 field_info = key_to_field_info [data_key ]
151- if isinstance (data_value , str ) and field_info .annotation is not str :
151+ if isinstance (data_value , str ) and _should_pre_parse_json ( field_info .annotation ) :
152152 try :
153153 pre_parsed = json .loads (data_value )
154154 except json .JSONDecodeError :
@@ -167,6 +167,22 @@ def pre_parse_json(self, data: dict[str, Any]) -> dict[str, Any]:
167167 )
168168
169169
170+ def _is_simple_scalar_annotation (annotation : Any ) -> bool :
171+ return annotation in {str , int , float , bool , NoneType }
172+
173+
174+ def _should_pre_parse_json (annotation : Any ) -> bool :
175+ """Return whether string input for this annotation should be JSON-decoded."""
176+ if annotation is str :
177+ return False
178+
179+ origin = get_origin (annotation )
180+ if is_union_origin (origin ):
181+ return not all (_is_simple_scalar_annotation (arg ) for arg in get_args (annotation ))
182+
183+ return True
184+
185+
170186def func_metadata (
171187 func : Callable [..., Any ],
172188 skip_names : Sequence [str ] = (),
0 commit comments