@@ -325,25 +325,33 @@ def analyze_param(
325
325
field_info = None
326
326
depends = None
327
327
type_annotation : Any = Any
328
- if (
329
- annotation is not inspect .Signature .empty
330
- and get_origin (annotation ) is Annotated
331
- ):
328
+ use_annotation : Any = Any
329
+ if annotation is not inspect .Signature .empty :
330
+ use_annotation = annotation
331
+ type_annotation = annotation
332
+ if get_origin (use_annotation ) is Annotated :
332
333
annotated_args = get_args (annotation )
333
334
type_annotation = annotated_args [0 ]
334
335
fastapi_annotations = [
335
336
arg
336
337
for arg in annotated_args [1 :]
337
338
if isinstance (arg , (FieldInfo , params .Depends ))
338
339
]
339
- assert (
340
- len (fastapi_annotations ) <= 1
341
- ), f"Cannot specify multiple `Annotated` FastAPI arguments for { param_name !r} "
342
- fastapi_annotation = next (iter (fastapi_annotations ), None )
340
+ fastapi_specific_annotations = [
341
+ arg
342
+ for arg in fastapi_annotations
343
+ if isinstance (arg , (params .Param , params .Body , params .Depends ))
344
+ ]
345
+ if fastapi_specific_annotations :
346
+ fastapi_annotation : Union [
347
+ FieldInfo , params .Depends , None
348
+ ] = fastapi_specific_annotations [- 1 ]
349
+ else :
350
+ fastapi_annotation = None
343
351
if isinstance (fastapi_annotation , FieldInfo ):
344
352
# Copy `field_info` because we mutate `field_info.default` below.
345
353
field_info = copy_field_info (
346
- field_info = fastapi_annotation , annotation = annotation
354
+ field_info = fastapi_annotation , annotation = use_annotation
347
355
)
348
356
assert field_info .default is Undefined or field_info .default is Required , (
349
357
f"`{ field_info .__class__ .__name__ } ` default value cannot be set in"
@@ -356,8 +364,6 @@ def analyze_param(
356
364
field_info .default = Required
357
365
elif isinstance (fastapi_annotation , params .Depends ):
358
366
depends = fastapi_annotation
359
- elif annotation is not inspect .Signature .empty :
360
- type_annotation = annotation
361
367
362
368
if isinstance (value , params .Depends ):
363
369
assert depends is None , (
@@ -402,15 +408,15 @@ def analyze_param(
402
408
# We might check here that `default_value is Required`, but the fact is that the same
403
409
# parameter might sometimes be a path parameter and sometimes not. See
404
410
# `tests/test_infer_param_optionality.py` for an example.
405
- field_info = params .Path (annotation = type_annotation )
411
+ field_info = params .Path (annotation = use_annotation )
406
412
elif is_uploadfile_or_nonable_uploadfile_annotation (
407
413
type_annotation
408
414
) or is_uploadfile_sequence_annotation (type_annotation ):
409
- field_info = params .File (annotation = type_annotation , default = default_value )
415
+ field_info = params .File (annotation = use_annotation , default = default_value )
410
416
elif not field_annotation_is_scalar (annotation = type_annotation ):
411
- field_info = params .Body (annotation = type_annotation , default = default_value )
417
+ field_info = params .Body (annotation = use_annotation , default = default_value )
412
418
else :
413
- field_info = params .Query (annotation = type_annotation , default = default_value )
419
+ field_info = params .Query (annotation = use_annotation , default = default_value )
414
420
415
421
field = None
416
422
if field_info is not None :
@@ -424,8 +430,8 @@ def analyze_param(
424
430
and getattr (field_info , "in_" , None ) is None
425
431
):
426
432
field_info .in_ = params .ParamTypes .query
427
- use_annotation = get_annotation_from_field_info (
428
- type_annotation ,
433
+ use_annotation_from_field_info = get_annotation_from_field_info (
434
+ use_annotation ,
429
435
field_info ,
430
436
param_name ,
431
437
)
@@ -436,7 +442,7 @@ def analyze_param(
436
442
field_info .alias = alias
437
443
field = create_response_field (
438
444
name = param_name ,
439
- type_ = use_annotation ,
445
+ type_ = use_annotation_from_field_info ,
440
446
default = field_info .default ,
441
447
alias = alias ,
442
448
required = field_info .default in (Required , Undefined ),
@@ -466,16 +472,17 @@ def is_body_param(*, param_field: ModelField, is_path_param: bool) -> bool:
466
472
467
473
468
474
def add_param_to_fields (* , field : ModelField , dependant : Dependant ) -> None :
469
- field_info = cast (params .Param , field .field_info )
470
- if field_info .in_ == params .ParamTypes .path :
475
+ field_info = field .field_info
476
+ field_info_in = getattr (field_info , "in_" , None )
477
+ if field_info_in == params .ParamTypes .path :
471
478
dependant .path_params .append (field )
472
- elif field_info . in_ == params .ParamTypes .query :
479
+ elif field_info_in == params .ParamTypes .query :
473
480
dependant .query_params .append (field )
474
- elif field_info . in_ == params .ParamTypes .header :
481
+ elif field_info_in == params .ParamTypes .header :
475
482
dependant .header_params .append (field )
476
483
else :
477
484
assert (
478
- field_info . in_ == params .ParamTypes .cookie
485
+ field_info_in == params .ParamTypes .cookie
479
486
), f"non-body parameters must be in path, query, header or cookie: { field .name } "
480
487
dependant .cookie_params .append (field )
481
488
0 commit comments