fastapi 0.112.3__py3-none-any.whl → 0.113.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fastapi might be problematic. Click here for more details.

fastapi/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
2
2
 
3
- __version__ = "0.112.3"
3
+ __version__ = "0.113.0"
4
4
 
5
5
  from starlette import status as status
6
6
 
fastapi/_compat.py CHANGED
@@ -279,6 +279,12 @@ if PYDANTIC_V2:
279
279
  BodyModel: Type[BaseModel] = create_model(model_name, **field_params) # type: ignore[call-overload]
280
280
  return BodyModel
281
281
 
282
+ def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
283
+ return [
284
+ ModelField(field_info=field_info, name=name)
285
+ for name, field_info in model.model_fields.items()
286
+ ]
287
+
282
288
  else:
283
289
  from fastapi.openapi.constants import REF_PREFIX as REF_PREFIX
284
290
  from pydantic import AnyUrl as Url # noqa: F401
@@ -513,6 +519,9 @@ else:
513
519
  BodyModel.__fields__[f.name] = f # type: ignore[index]
514
520
  return BodyModel
515
521
 
522
+ def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
523
+ return list(model.__fields__.values()) # type: ignore[attr-defined]
524
+
516
525
 
517
526
  def _regenerate_error_with_loc(
518
527
  *, errors: Sequence[Any], loc_prefix: Tuple[Union[str, int], ...]
@@ -532,6 +541,12 @@ def _annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
532
541
 
533
542
 
534
543
  def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
544
+ origin = get_origin(annotation)
545
+ if origin is Union or origin is UnionType:
546
+ for arg in get_args(annotation):
547
+ if field_annotation_is_sequence(arg):
548
+ return True
549
+ return False
535
550
  return _annotation_is_sequence(annotation) or _annotation_is_sequence(
536
551
  get_origin(annotation)
537
552
  )
@@ -33,6 +33,7 @@ from fastapi._compat import (
33
33
  field_annotation_is_scalar,
34
34
  get_annotation_from_field_info,
35
35
  get_missing_field_error,
36
+ get_model_fields,
36
37
  is_bytes_field,
37
38
  is_bytes_sequence_field,
38
39
  is_scalar_field,
@@ -56,10 +57,17 @@ from fastapi.security.base import SecurityBase
56
57
  from fastapi.security.oauth2 import OAuth2, SecurityScopes
57
58
  from fastapi.security.open_id_connect_url import OpenIdConnect
58
59
  from fastapi.utils import create_model_field, get_path_param_names
60
+ from pydantic import BaseModel
59
61
  from pydantic.fields import FieldInfo
60
62
  from starlette.background import BackgroundTasks as StarletteBackgroundTasks
61
63
  from starlette.concurrency import run_in_threadpool
62
- from starlette.datastructures import FormData, Headers, QueryParams, UploadFile
64
+ from starlette.datastructures import (
65
+ FormData,
66
+ Headers,
67
+ ImmutableMultiDict,
68
+ QueryParams,
69
+ UploadFile,
70
+ )
63
71
  from starlette.requests import HTTPConnection, Request
64
72
  from starlette.responses import Response
65
73
  from starlette.websockets import WebSocket
@@ -282,7 +290,7 @@ def get_dependant(
282
290
  ), f"Cannot specify multiple FastAPI annotations for {param_name!r}"
283
291
  continue
284
292
  assert param_details.field is not None
285
- if is_body_param(param_field=param_details.field, is_path_param=is_path_param):
293
+ if isinstance(param_details.field.field_info, params.Body):
286
294
  dependant.body_params.append(param_details.field)
287
295
  else:
288
296
  add_param_to_fields(field=param_details.field, dependant=dependant)
@@ -466,29 +474,16 @@ def analyze_param(
466
474
  required=field_info.default in (Required, Undefined),
467
475
  field_info=field_info,
468
476
  )
477
+ if is_path_param:
478
+ assert is_scalar_field(
479
+ field=field
480
+ ), "Path params must be of one of the supported types"
481
+ elif isinstance(field_info, params.Query):
482
+ assert is_scalar_field(field) or is_scalar_sequence_field(field)
469
483
 
470
484
  return ParamDetails(type_annotation=type_annotation, depends=depends, field=field)
471
485
 
472
486
 
473
- def is_body_param(*, param_field: ModelField, is_path_param: bool) -> bool:
474
- if is_path_param:
475
- assert is_scalar_field(
476
- field=param_field
477
- ), "Path params must be of one of the supported types"
478
- return False
479
- elif is_scalar_field(field=param_field):
480
- return False
481
- elif isinstance(
482
- param_field.field_info, (params.Query, params.Header)
483
- ) and is_scalar_sequence_field(param_field):
484
- return False
485
- else:
486
- assert isinstance(
487
- param_field.field_info, params.Body
488
- ), f"Param: {param_field.name} can only be a request body, using Body()"
489
- return True
490
-
491
-
492
487
  def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
493
488
  field_info = field.field_info
494
489
  field_info_in = getattr(field_info, "in_", None)
@@ -557,6 +552,7 @@ async def solve_dependencies(
557
552
  dependency_overrides_provider: Optional[Any] = None,
558
553
  dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
559
554
  async_exit_stack: AsyncExitStack,
555
+ embed_body_fields: bool,
560
556
  ) -> SolvedDependency:
561
557
  values: Dict[str, Any] = {}
562
558
  errors: List[Any] = []
@@ -598,6 +594,7 @@ async def solve_dependencies(
598
594
  dependency_overrides_provider=dependency_overrides_provider,
599
595
  dependency_cache=dependency_cache,
600
596
  async_exit_stack=async_exit_stack,
597
+ embed_body_fields=embed_body_fields,
601
598
  )
602
599
  background_tasks = solved_result.background_tasks
603
600
  dependency_cache.update(solved_result.dependency_cache)
@@ -640,7 +637,9 @@ async def solve_dependencies(
640
637
  body_values,
641
638
  body_errors,
642
639
  ) = await request_body_to_args( # body_params checked above
643
- required_params=dependant.body_params, received_body=body
640
+ body_fields=dependant.body_params,
641
+ received_body=body,
642
+ embed_body_fields=embed_body_fields,
644
643
  )
645
644
  values.update(body_values)
646
645
  errors.extend(body_errors)
@@ -669,138 +668,194 @@ async def solve_dependencies(
669
668
  )
670
669
 
671
670
 
671
+ def _validate_value_with_model_field(
672
+ *, field: ModelField, value: Any, values: Dict[str, Any], loc: Tuple[str, ...]
673
+ ) -> Tuple[Any, List[Any]]:
674
+ if value is None:
675
+ if field.required:
676
+ return None, [get_missing_field_error(loc=loc)]
677
+ else:
678
+ return deepcopy(field.default), []
679
+ v_, errors_ = field.validate(value, values, loc=loc)
680
+ if isinstance(errors_, ErrorWrapper):
681
+ return None, [errors_]
682
+ elif isinstance(errors_, list):
683
+ new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=())
684
+ return None, new_errors
685
+ else:
686
+ return v_, []
687
+
688
+
689
+ def _get_multidict_value(field: ModelField, values: Mapping[str, Any]) -> Any:
690
+ if is_sequence_field(field) and isinstance(values, (ImmutableMultiDict, Headers)):
691
+ value = values.getlist(field.alias)
692
+ else:
693
+ value = values.get(field.alias, None)
694
+ if (
695
+ value is None
696
+ or (
697
+ isinstance(field.field_info, params.Form)
698
+ and isinstance(value, str) # For type checks
699
+ and value == ""
700
+ )
701
+ or (is_sequence_field(field) and len(value) == 0)
702
+ ):
703
+ if field.required:
704
+ return
705
+ else:
706
+ return deepcopy(field.default)
707
+ return value
708
+
709
+
672
710
  def request_params_to_args(
673
- required_params: Sequence[ModelField],
711
+ fields: Sequence[ModelField],
674
712
  received_params: Union[Mapping[str, Any], QueryParams, Headers],
675
713
  ) -> Tuple[Dict[str, Any], List[Any]]:
676
- values = {}
714
+ values: Dict[str, Any] = {}
677
715
  errors = []
678
- for field in required_params:
679
- if is_scalar_sequence_field(field) and isinstance(
680
- received_params, (QueryParams, Headers)
681
- ):
682
- value = received_params.getlist(field.alias) or field.default
683
- else:
684
- value = received_params.get(field.alias)
716
+ for field in fields:
717
+ value = _get_multidict_value(field, received_params)
685
718
  field_info = field.field_info
686
719
  assert isinstance(
687
720
  field_info, params.Param
688
721
  ), "Params must be subclasses of Param"
689
722
  loc = (field_info.in_.value, field.alias)
690
- if value is None:
691
- if field.required:
692
- errors.append(get_missing_field_error(loc=loc))
693
- else:
694
- values[field.name] = deepcopy(field.default)
695
- continue
696
- v_, errors_ = field.validate(value, values, loc=loc)
697
- if isinstance(errors_, ErrorWrapper):
698
- errors.append(errors_)
699
- elif isinstance(errors_, list):
700
- new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=())
701
- errors.extend(new_errors)
723
+ v_, errors_ = _validate_value_with_model_field(
724
+ field=field, value=value, values=values, loc=loc
725
+ )
726
+ if errors_:
727
+ errors.extend(errors_)
702
728
  else:
703
729
  values[field.name] = v_
704
730
  return values, errors
705
731
 
706
732
 
733
+ def _should_embed_body_fields(fields: List[ModelField]) -> bool:
734
+ if not fields:
735
+ return False
736
+ # More than one dependency could have the same field, it would show up as multiple
737
+ # fields but it's the same one, so count them by name
738
+ body_param_names_set = {field.name for field in fields}
739
+ # A top level field has to be a single field, not multiple
740
+ if len(body_param_names_set) > 1:
741
+ return True
742
+ first_field = fields[0]
743
+ # If it explicitly specifies it is embedded, it has to be embedded
744
+ if getattr(first_field.field_info, "embed", None):
745
+ return True
746
+ # If it's a Form (or File) field, it has to be a BaseModel to be top level
747
+ # otherwise it has to be embedded, so that the key value pair can be extracted
748
+ if isinstance(first_field.field_info, params.Form) and not lenient_issubclass(
749
+ first_field.type_, BaseModel
750
+ ):
751
+ return True
752
+ return False
753
+
754
+
755
+ async def _extract_form_body(
756
+ body_fields: List[ModelField],
757
+ received_body: FormData,
758
+ ) -> Dict[str, Any]:
759
+ values = {}
760
+ first_field = body_fields[0]
761
+ first_field_info = first_field.field_info
762
+
763
+ for field in body_fields:
764
+ value = _get_multidict_value(field, received_body)
765
+ if (
766
+ isinstance(first_field_info, params.File)
767
+ and is_bytes_field(field)
768
+ and isinstance(value, UploadFile)
769
+ ):
770
+ value = await value.read()
771
+ elif (
772
+ is_bytes_sequence_field(field)
773
+ and isinstance(first_field_info, params.File)
774
+ and value_is_sequence(value)
775
+ ):
776
+ # For types
777
+ assert isinstance(value, sequence_types) # type: ignore[arg-type]
778
+ results: List[Union[bytes, str]] = []
779
+
780
+ async def process_fn(
781
+ fn: Callable[[], Coroutine[Any, Any, Any]],
782
+ ) -> None:
783
+ result = await fn()
784
+ results.append(result) # noqa: B023
785
+
786
+ async with anyio.create_task_group() as tg:
787
+ for sub_value in value:
788
+ tg.start_soon(process_fn, sub_value.read)
789
+ value = serialize_sequence_value(field=field, value=results)
790
+ if value is not None:
791
+ values[field.name] = value
792
+ return values
793
+
794
+
707
795
  async def request_body_to_args(
708
- required_params: List[ModelField],
796
+ body_fields: List[ModelField],
709
797
  received_body: Optional[Union[Dict[str, Any], FormData]],
798
+ embed_body_fields: bool,
710
799
  ) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
711
- values = {}
800
+ values: Dict[str, Any] = {}
712
801
  errors: List[Dict[str, Any]] = []
713
- if required_params:
714
- field = required_params[0]
715
- field_info = field.field_info
716
- embed = getattr(field_info, "embed", None)
717
- field_alias_omitted = len(required_params) == 1 and not embed
718
- if field_alias_omitted:
719
- received_body = {field.alias: received_body}
720
-
721
- for field in required_params:
722
- loc: Tuple[str, ...]
723
- if field_alias_omitted:
724
- loc = ("body",)
725
- else:
726
- loc = ("body", field.alias)
727
-
728
- value: Optional[Any] = None
729
- if received_body is not None:
730
- if (is_sequence_field(field)) and isinstance(received_body, FormData):
731
- value = received_body.getlist(field.alias)
732
- else:
733
- try:
734
- value = received_body.get(field.alias)
735
- except AttributeError:
736
- errors.append(get_missing_field_error(loc))
737
- continue
738
- if (
739
- value is None
740
- or (isinstance(field_info, params.Form) and value == "")
741
- or (
742
- isinstance(field_info, params.Form)
743
- and is_sequence_field(field)
744
- and len(value) == 0
745
- )
746
- ):
747
- if field.required:
748
- errors.append(get_missing_field_error(loc))
749
- else:
750
- values[field.name] = deepcopy(field.default)
802
+ assert body_fields, "request_body_to_args() should be called with fields"
803
+ single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields
804
+ first_field = body_fields[0]
805
+ body_to_process = received_body
806
+
807
+ fields_to_extract: List[ModelField] = body_fields
808
+
809
+ if single_not_embedded_field and lenient_issubclass(first_field.type_, BaseModel):
810
+ fields_to_extract = get_model_fields(first_field.type_)
811
+
812
+ if isinstance(received_body, FormData):
813
+ body_to_process = await _extract_form_body(fields_to_extract, received_body)
814
+
815
+ if single_not_embedded_field:
816
+ loc: Tuple[str, ...] = ("body",)
817
+ v_, errors_ = _validate_value_with_model_field(
818
+ field=first_field, value=body_to_process, values=values, loc=loc
819
+ )
820
+ return {first_field.name: v_}, errors_
821
+ for field in body_fields:
822
+ loc = ("body", field.alias)
823
+ value: Optional[Any] = None
824
+ if body_to_process is not None:
825
+ try:
826
+ value = body_to_process.get(field.alias)
827
+ # If the received body is a list, not a dict
828
+ except AttributeError:
829
+ errors.append(get_missing_field_error(loc))
751
830
  continue
752
- if (
753
- isinstance(field_info, params.File)
754
- and is_bytes_field(field)
755
- and isinstance(value, UploadFile)
756
- ):
757
- value = await value.read()
758
- elif (
759
- is_bytes_sequence_field(field)
760
- and isinstance(field_info, params.File)
761
- and value_is_sequence(value)
762
- ):
763
- # For types
764
- assert isinstance(value, sequence_types) # type: ignore[arg-type]
765
- results: List[Union[bytes, str]] = []
766
-
767
- async def process_fn(
768
- fn: Callable[[], Coroutine[Any, Any, Any]],
769
- ) -> None:
770
- result = await fn()
771
- results.append(result) # noqa: B023
772
-
773
- async with anyio.create_task_group() as tg:
774
- for sub_value in value:
775
- tg.start_soon(process_fn, sub_value.read)
776
- value = serialize_sequence_value(field=field, value=results)
777
-
778
- v_, errors_ = field.validate(value, values, loc=loc)
779
-
780
- if isinstance(errors_, list):
781
- errors.extend(errors_)
782
- elif errors_:
783
- errors.append(errors_)
784
- else:
785
- values[field.name] = v_
831
+ v_, errors_ = _validate_value_with_model_field(
832
+ field=field, value=value, values=values, loc=loc
833
+ )
834
+ if errors_:
835
+ errors.extend(errors_)
836
+ else:
837
+ values[field.name] = v_
786
838
  return values, errors
787
839
 
788
840
 
789
- def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]:
790
- flat_dependant = get_flat_dependant(dependant)
841
+ def get_body_field(
842
+ *, flat_dependant: Dependant, name: str, embed_body_fields: bool
843
+ ) -> Optional[ModelField]:
844
+ """
845
+ Get a ModelField representing the request body for a path operation, combining
846
+ all body parameters into a single field if necessary.
847
+
848
+ Used to check if it's form data (with `isinstance(body_field, params.Form)`)
849
+ or JSON and to generate the JSON Schema for a request body.
850
+
851
+ This is **not** used to validate/parse the request body, that's done with each
852
+ individual body parameter.
853
+ """
791
854
  if not flat_dependant.body_params:
792
855
  return None
793
856
  first_param = flat_dependant.body_params[0]
794
- field_info = first_param.field_info
795
- embed = getattr(field_info, "embed", None)
796
- body_param_names_set = {param.name for param in flat_dependant.body_params}
797
- if len(body_param_names_set) == 1 and not embed:
857
+ if not embed_body_fields:
798
858
  return first_param
799
- # If one field requires to embed, all have to be embedded
800
- # in case a sub-dependency is evaluated with a single unique body field
801
- # That is combined (embedded) with other body fields
802
- for param in flat_dependant.body_params:
803
- setattr(param.field_info, "embed", True) # noqa: B010
804
859
  model_name = "Body_" + name
805
860
  BodyModel = create_body_model(
806
861
  fields=flat_dependant.body_params, model_name=model_name
@@ -1282,7 +1282,7 @@ def Body( # noqa: N802
1282
1282
  ),
1283
1283
  ] = _Unset,
1284
1284
  embed: Annotated[
1285
- bool,
1285
+ Union[bool, None],
1286
1286
  Doc(
1287
1287
  """
1288
1288
  When `embed` is `True`, the parameter will be expected in a JSON body as a
@@ -1294,7 +1294,7 @@ def Body( # noqa: N802
1294
1294
  [FastAPI docs for Body - Multiple Parameters](https://fastapi.tiangolo.com/tutorial/body-multiple-params/#embed-a-single-body-parameter).
1295
1295
  """
1296
1296
  ),
1297
- ] = False,
1297
+ ] = None,
1298
1298
  media_type: Annotated[
1299
1299
  str,
1300
1300
  Doc(
fastapi/params.py CHANGED
@@ -479,7 +479,7 @@ class Body(FieldInfo):
479
479
  *,
480
480
  default_factory: Union[Callable[[], Any], None] = _Unset,
481
481
  annotation: Optional[Any] = None,
482
- embed: bool = False,
482
+ embed: Union[bool, None] = None,
483
483
  media_type: str = "application/json",
484
484
  alias: Optional[str] = None,
485
485
  alias_priority: Union[int, None] = _Unset,
@@ -642,7 +642,6 @@ class Form(Body):
642
642
  default=default,
643
643
  default_factory=default_factory,
644
644
  annotation=annotation,
645
- embed=True,
646
645
  media_type=media_type,
647
646
  alias=alias,
648
647
  alias_priority=alias_priority,
fastapi/routing.py CHANGED
@@ -33,8 +33,10 @@ from fastapi._compat import (
33
33
  from fastapi.datastructures import Default, DefaultPlaceholder
34
34
  from fastapi.dependencies.models import Dependant
35
35
  from fastapi.dependencies.utils import (
36
+ _should_embed_body_fields,
36
37
  get_body_field,
37
38
  get_dependant,
39
+ get_flat_dependant,
38
40
  get_parameterless_sub_dependant,
39
41
  get_typed_return_annotation,
40
42
  solve_dependencies,
@@ -225,6 +227,7 @@ def get_request_handler(
225
227
  response_model_exclude_defaults: bool = False,
226
228
  response_model_exclude_none: bool = False,
227
229
  dependency_overrides_provider: Optional[Any] = None,
230
+ embed_body_fields: bool = False,
228
231
  ) -> Callable[[Request], Coroutine[Any, Any, Response]]:
229
232
  assert dependant.call is not None, "dependant.call must be a function"
230
233
  is_coroutine = asyncio.iscoroutinefunction(dependant.call)
@@ -291,6 +294,7 @@ def get_request_handler(
291
294
  body=body,
292
295
  dependency_overrides_provider=dependency_overrides_provider,
293
296
  async_exit_stack=async_exit_stack,
297
+ embed_body_fields=embed_body_fields,
294
298
  )
295
299
  errors = solved_result.errors
296
300
  if not errors:
@@ -354,7 +358,9 @@ def get_request_handler(
354
358
 
355
359
 
356
360
  def get_websocket_app(
357
- dependant: Dependant, dependency_overrides_provider: Optional[Any] = None
361
+ dependant: Dependant,
362
+ dependency_overrides_provider: Optional[Any] = None,
363
+ embed_body_fields: bool = False,
358
364
  ) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]:
359
365
  async def app(websocket: WebSocket) -> None:
360
366
  async with AsyncExitStack() as async_exit_stack:
@@ -367,6 +373,7 @@ def get_websocket_app(
367
373
  dependant=dependant,
368
374
  dependency_overrides_provider=dependency_overrides_provider,
369
375
  async_exit_stack=async_exit_stack,
376
+ embed_body_fields=embed_body_fields,
370
377
  )
371
378
  if solved_result.errors:
372
379
  raise WebSocketRequestValidationError(
@@ -399,11 +406,15 @@ class APIWebSocketRoute(routing.WebSocketRoute):
399
406
  0,
400
407
  get_parameterless_sub_dependant(depends=depends, path=self.path_format),
401
408
  )
402
-
409
+ self._flat_dependant = get_flat_dependant(self.dependant)
410
+ self._embed_body_fields = _should_embed_body_fields(
411
+ self._flat_dependant.body_params
412
+ )
403
413
  self.app = websocket_session(
404
414
  get_websocket_app(
405
415
  dependant=self.dependant,
406
416
  dependency_overrides_provider=dependency_overrides_provider,
417
+ embed_body_fields=self._embed_body_fields,
407
418
  )
408
419
  )
409
420
 
@@ -544,7 +555,15 @@ class APIRoute(routing.Route):
544
555
  0,
545
556
  get_parameterless_sub_dependant(depends=depends, path=self.path_format),
546
557
  )
547
- self.body_field = get_body_field(dependant=self.dependant, name=self.unique_id)
558
+ self._flat_dependant = get_flat_dependant(self.dependant)
559
+ self._embed_body_fields = _should_embed_body_fields(
560
+ self._flat_dependant.body_params
561
+ )
562
+ self.body_field = get_body_field(
563
+ flat_dependant=self._flat_dependant,
564
+ name=self.unique_id,
565
+ embed_body_fields=self._embed_body_fields,
566
+ )
548
567
  self.app = request_response(self.get_route_handler())
549
568
 
550
569
  def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]:
@@ -561,6 +580,7 @@ class APIRoute(routing.Route):
561
580
  response_model_exclude_defaults=self.response_model_exclude_defaults,
562
581
  response_model_exclude_none=self.response_model_exclude_none,
563
582
  dependency_overrides_provider=self.dependency_overrides_provider,
583
+ embed_body_fields=self._embed_body_fields,
564
584
  )
565
585
 
566
586
  def matches(self, scope: Scope) -> Tuple[Match, Scope]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastapi
3
- Version: 0.112.3
3
+ Version: 0.113.0
4
4
  Summary: FastAPI framework, high performance, easy to learn, fast to code, ready for production
5
5
  Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiangolo@gmail.com>
6
6
  Classifier: Intended Audience :: Information Technology
@@ -115,7 +115,7 @@ The key features are:
115
115
  <a href="https://bump.sh/fastapi?utm_source=fastapi&utm_medium=referral&utm_campaign=sponsor" target="_blank" title="Automate FastAPI documentation generation with Bump.sh"><img src="https://fastapi.tiangolo.com/img/sponsors/bump-sh.svg"></a>
116
116
  <a href="https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=main-badge" target="_blank" title="Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files"><img src="https://fastapi.tiangolo.com/img/sponsors/scalar.svg"></a>
117
117
  <a href="https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=mainbadge" target="_blank" title="Auth, user management and more for your B2B product"><img src="https://fastapi.tiangolo.com/img/sponsors/propelauth.png"></a>
118
- <a href="https://docs.withcoherence.com/coherence-templates/full-stack-template/#fastapi?utm_medium=advertising&utm_source=fastapi&utm_campaign=docs" target="_blank" title="Coherence"><img src="https://fastapi.tiangolo.com/img/sponsors/coherence.png"></a>
118
+ <a href="https://www.withcoherence.com/?utm_medium=advertising&utm_source=fastapi&utm_campaign=website" target="_blank" title="Coherence"><img src="https://fastapi.tiangolo.com/img/sponsors/coherence.png"></a>
119
119
  <a href="https://www.mongodb.com/developer/languages/python/python-quickstart-fastapi/?utm_campaign=fastapi_framework&utm_source=fastapi_sponsorship&utm_medium=web_referral" target="_blank" title="Simplify Full Stack Development with FastAPI & MongoDB"><img src="https://fastapi.tiangolo.com/img/sponsors/mongodb.png"></a>
120
120
  <a href="https://zuplo.link/fastapi-gh" target="_blank" title="Zuplo: Scale, Protect, Document, and Monetize your FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/zuplo.png"></a>
121
121
  <a href="https://fine.dev?ref=fastapibadge" target="_blank" title="Fine's AI FastAPI Workflow: Effortlessly Deploy and Integrate FastAPI into Your Project"><img src="https://fastapi.tiangolo.com/img/sponsors/fine.png"></a>
@@ -1,10 +1,10 @@
1
- fastapi-0.112.3.dist-info/METADATA,sha256=w1QfelBarqYSCtz6ly70TBP_VdihTpwEujW_K2sRg9E,27273
2
- fastapi-0.112.3.dist-info/WHEEL,sha256=rSwsxJWe3vzyR5HCwjWXQruDgschpei4h_giTm0dJVE,90
3
- fastapi-0.112.3.dist-info/entry_points.txt,sha256=Nn2-rs4A5_lQZko2b9QqCKQx9Irx0agGbxq3QLgjBxQ,46
4
- fastapi-0.112.3.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
5
- fastapi/__init__.py,sha256=o7tP2gKcsHMiiJNCKrN-GA3wqWjGR54B379fYdZ3_TA,1081
1
+ fastapi-0.113.0.dist-info/METADATA,sha256=ii9Gxjj0MqtirULJzkuNcZ6ur3w-NRAvUA1Z0dv_EOY,27227
2
+ fastapi-0.113.0.dist-info/WHEEL,sha256=rSwsxJWe3vzyR5HCwjWXQruDgschpei4h_giTm0dJVE,90
3
+ fastapi-0.113.0.dist-info/entry_points.txt,sha256=Nn2-rs4A5_lQZko2b9QqCKQx9Irx0agGbxq3QLgjBxQ,46
4
+ fastapi-0.113.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
5
+ fastapi/__init__.py,sha256=d4A3W-W3uWnnSbn4daxNgwAvbz-XdCxNGIoAU2Xh68w,1081
6
6
  fastapi/__main__.py,sha256=bKePXLdO4SsVSM6r9SVoLickJDcR2c0cTOxZRKq26YQ,37
7
- fastapi/_compat.py,sha256=OjE3FUZ0IPXqIJWKhoWKDNCHv4so-FQ-rfN8ngQZeFE,23134
7
+ fastapi/_compat.py,sha256=9AipVKxefipp4ymECk3VhrryBi-Hbh8A7zsljaWdGAk,23723
8
8
  fastapi/applications.py,sha256=Ix-o9pQAWhEDf9J0Q1hZ0nBB1uP72c-Y3oiYzvrwqiM,176316
9
9
  fastapi/background.py,sha256=rouLirxUANrcYC824MSMypXL_Qb2HYg2YZqaiEqbEKI,1768
10
10
  fastapi/cli.py,sha256=OYhZb0NR_deuT5ofyPF2NoNBzZDNOP8Salef2nk-HqA,418
@@ -12,7 +12,7 @@ fastapi/concurrency.py,sha256=AYLnS4judDUmXsNRICtoKSP0prfYDcS8ehBtYW9JhQQ,1403
12
12
  fastapi/datastructures.py,sha256=b2PEz77XGq-u3Ur1Inwk0AGjOsQZO49yF9C7IPJ15cY,5766
13
13
  fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  fastapi/dependencies/models.py,sha256=Pjl6vx-4nZ5Tta9kJa3-RfQKkXtCpS09-FhMgs9eWNs,1507
15
- fastapi/dependencies/utils.py,sha256=2J36LBZMJTZ6jadjANaG-voTfzgs8JpROJCRtoLoSFA,30922
15
+ fastapi/dependencies/utils.py,sha256=EGlTiaoExyqTVLYEuQnHa8NDfuf37YNRs-gU2hiwlxo,32352
16
16
  fastapi/encoders.py,sha256=LvwYmFeOz4tVwvgBoC5rvZnbr7hZr73KGrU8O7zSptU,11068
17
17
  fastapi/exception_handlers.py,sha256=MBrIOA-ugjJDivIi4rSsUJBdTsjuzN76q4yh0q1COKw,1332
18
18
  fastapi/exceptions.py,sha256=taNixuFEXb67lI1bnX1ubq8y8TseJ4yoPlWjyP0fTzk,4969
@@ -28,12 +28,12 @@ fastapi/openapi/constants.py,sha256=adGzmis1L1HJRTE3kJ5fmHS_Noq6tIY6pWv_SFzoFDU,
28
28
  fastapi/openapi/docs.py,sha256=XcQq-ZbQdC5sI0gIGu5MoHK1q-OFaqws7-ORTo6sjY4,10348
29
29
  fastapi/openapi/models.py,sha256=PqkxQiqcEgjKuhfUIWPZPQcyTcubtUCB3vcObLsB7VE,15397
30
30
  fastapi/openapi/utils.py,sha256=asSbOKDuagDfpByNQvPy7OM0sqOBdUmqh64BH-n-5f0,22286
31
- fastapi/param_functions.py,sha256=Xp1h5RBdb-zlatMJ8_USkut2G9HJAgkMx7HBky9wHbM,64006
32
- fastapi/params.py,sha256=CWumi-CkfxWSg4I2KpPxIvQyKdeW_Lnct9reHnrTwW8,28199
31
+ fastapi/param_functions.py,sha256=uQzNlihlhM80u4Xbstz__D3L3yxpTqLmsC-Hra1WfqE,64018
32
+ fastapi/params.py,sha256=e_ZHoUohqWWbquiBL5AHqdsKJmTMLZzAPii6eCYR3tk,28187
33
33
  fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  fastapi/requests.py,sha256=zayepKFcienBllv3snmWI20Gk0oHNVLU4DDhqXBb4LU,142
35
35
  fastapi/responses.py,sha256=QNQQlwpKhQoIPZTTWkpc9d_QGeGZ_aVQPaDV3nQ8m7c,1761
36
- fastapi/routing.py,sha256=e_H0k8q4HQl88mgi-Jdf-9hBfn2gTvDjixXrufDN3U0,175326
36
+ fastapi/routing.py,sha256=LnYhRsafzHporfz4aDUmEk8qDU2tarLZNjHaKy3RB7w,176148
37
37
  fastapi/security/__init__.py,sha256=bO8pNmxqVRXUjfl2mOKiVZLn0FpBQ61VUYVjmppnbJw,881
38
38
  fastapi/security/api_key.py,sha256=_OqUUjEHG5_MT1IPAhXIGJRCPldTBdSww_DegFy_W8Y,9368
39
39
  fastapi/security/base.py,sha256=dl4pvbC-RxjfbWgPtCWd8MVU-7CB2SZ22rJDXVCXO6c,141
@@ -47,4 +47,4 @@ fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66
47
47
  fastapi/types.py,sha256=nFb36sK3DSoqoyo7Miwy3meKK5UdFBgkAgLSzQlUVyI,383
48
48
  fastapi/utils.py,sha256=y8Bj5ttMaI9tS4D60OUgXqKnktBr99NdYUnHHV9LgoY,7948
49
49
  fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222
50
- fastapi-0.112.3.dist-info/RECORD,,
50
+ fastapi-0.113.0.dist-info/RECORD,,