fastapi 0.112.3__py3-none-any.whl → 0.112.4__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.112.4"
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
  )
@@ -59,7 +59,13 @@ from fastapi.utils import create_model_field, get_path_param_names
59
59
  from pydantic.fields import FieldInfo
60
60
  from starlette.background import BackgroundTasks as StarletteBackgroundTasks
61
61
  from starlette.concurrency import run_in_threadpool
62
- from starlette.datastructures import FormData, Headers, QueryParams, UploadFile
62
+ from starlette.datastructures import (
63
+ FormData,
64
+ Headers,
65
+ ImmutableMultiDict,
66
+ QueryParams,
67
+ UploadFile,
68
+ )
63
69
  from starlette.requests import HTTPConnection, Request
64
70
  from starlette.responses import Response
65
71
  from starlette.websockets import WebSocket
@@ -282,7 +288,7 @@ def get_dependant(
282
288
  ), f"Cannot specify multiple FastAPI annotations for {param_name!r}"
283
289
  continue
284
290
  assert param_details.field is not None
285
- if is_body_param(param_field=param_details.field, is_path_param=is_path_param):
291
+ if isinstance(param_details.field.field_info, params.Body):
286
292
  dependant.body_params.append(param_details.field)
287
293
  else:
288
294
  add_param_to_fields(field=param_details.field, dependant=dependant)
@@ -466,29 +472,16 @@ def analyze_param(
466
472
  required=field_info.default in (Required, Undefined),
467
473
  field_info=field_info,
468
474
  )
475
+ if is_path_param:
476
+ assert is_scalar_field(
477
+ field=field
478
+ ), "Path params must be of one of the supported types"
479
+ elif isinstance(field_info, params.Query):
480
+ assert is_scalar_field(field) or is_scalar_sequence_field(field)
469
481
 
470
482
  return ParamDetails(type_annotation=type_annotation, depends=depends, field=field)
471
483
 
472
484
 
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
485
  def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
493
486
  field_info = field.field_info
494
487
  field_info_in = getattr(field_info, "in_", None)
@@ -557,6 +550,7 @@ async def solve_dependencies(
557
550
  dependency_overrides_provider: Optional[Any] = None,
558
551
  dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
559
552
  async_exit_stack: AsyncExitStack,
553
+ embed_body_fields: bool,
560
554
  ) -> SolvedDependency:
561
555
  values: Dict[str, Any] = {}
562
556
  errors: List[Any] = []
@@ -598,6 +592,7 @@ async def solve_dependencies(
598
592
  dependency_overrides_provider=dependency_overrides_provider,
599
593
  dependency_cache=dependency_cache,
600
594
  async_exit_stack=async_exit_stack,
595
+ embed_body_fields=embed_body_fields,
601
596
  )
602
597
  background_tasks = solved_result.background_tasks
603
598
  dependency_cache.update(solved_result.dependency_cache)
@@ -640,7 +635,9 @@ async def solve_dependencies(
640
635
  body_values,
641
636
  body_errors,
642
637
  ) = await request_body_to_args( # body_params checked above
643
- required_params=dependant.body_params, received_body=body
638
+ body_fields=dependant.body_params,
639
+ received_body=body,
640
+ embed_body_fields=embed_body_fields,
644
641
  )
645
642
  values.update(body_values)
646
643
  errors.extend(body_errors)
@@ -669,138 +666,185 @@ async def solve_dependencies(
669
666
  )
670
667
 
671
668
 
669
+ def _validate_value_with_model_field(
670
+ *, field: ModelField, value: Any, values: Dict[str, Any], loc: Tuple[str, ...]
671
+ ) -> Tuple[Any, List[Any]]:
672
+ if value is None:
673
+ if field.required:
674
+ return None, [get_missing_field_error(loc=loc)]
675
+ else:
676
+ return deepcopy(field.default), []
677
+ v_, errors_ = field.validate(value, values, loc=loc)
678
+ if isinstance(errors_, ErrorWrapper):
679
+ return None, [errors_]
680
+ elif isinstance(errors_, list):
681
+ new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=())
682
+ return None, new_errors
683
+ else:
684
+ return v_, []
685
+
686
+
687
+ def _get_multidict_value(field: ModelField, values: Mapping[str, Any]) -> Any:
688
+ if is_sequence_field(field) and isinstance(values, (ImmutableMultiDict, Headers)):
689
+ value = values.getlist(field.alias)
690
+ else:
691
+ value = values.get(field.alias, None)
692
+ if (
693
+ value is None
694
+ or (
695
+ isinstance(field.field_info, params.Form)
696
+ and isinstance(value, str) # For type checks
697
+ and value == ""
698
+ )
699
+ or (is_sequence_field(field) and len(value) == 0)
700
+ ):
701
+ if field.required:
702
+ return
703
+ else:
704
+ return deepcopy(field.default)
705
+ return value
706
+
707
+
672
708
  def request_params_to_args(
673
- required_params: Sequence[ModelField],
709
+ fields: Sequence[ModelField],
674
710
  received_params: Union[Mapping[str, Any], QueryParams, Headers],
675
711
  ) -> Tuple[Dict[str, Any], List[Any]]:
676
- values = {}
712
+ values: Dict[str, Any] = {}
677
713
  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)
714
+ for field in fields:
715
+ value = _get_multidict_value(field, received_params)
685
716
  field_info = field.field_info
686
717
  assert isinstance(
687
718
  field_info, params.Param
688
719
  ), "Params must be subclasses of Param"
689
720
  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)
721
+ v_, errors_ = _validate_value_with_model_field(
722
+ field=field, value=value, values=values, loc=loc
723
+ )
724
+ if errors_:
725
+ errors.extend(errors_)
702
726
  else:
703
727
  values[field.name] = v_
704
728
  return values, errors
705
729
 
706
730
 
731
+ def _should_embed_body_fields(fields: List[ModelField]) -> bool:
732
+ if not fields:
733
+ return False
734
+ # More than one dependency could have the same field, it would show up as multiple
735
+ # fields but it's the same one, so count them by name
736
+ body_param_names_set = {field.name for field in fields}
737
+ # A top level field has to be a single field, not multiple
738
+ if len(body_param_names_set) > 1:
739
+ return True
740
+ first_field = fields[0]
741
+ # If it explicitly specifies it is embedded, it has to be embedded
742
+ if getattr(first_field.field_info, "embed", None):
743
+ return True
744
+ # If it's a Form (or File) field, it has to be a BaseModel to be top level
745
+ # otherwise it has to be embedded, so that the key value pair can be extracted
746
+ if isinstance(first_field.field_info, params.Form):
747
+ return True
748
+ return False
749
+
750
+
751
+ async def _extract_form_body(
752
+ body_fields: List[ModelField],
753
+ received_body: FormData,
754
+ ) -> Dict[str, Any]:
755
+ values = {}
756
+ first_field = body_fields[0]
757
+ first_field_info = first_field.field_info
758
+
759
+ for field in body_fields:
760
+ value = _get_multidict_value(field, received_body)
761
+ if (
762
+ isinstance(first_field_info, params.File)
763
+ and is_bytes_field(field)
764
+ and isinstance(value, UploadFile)
765
+ ):
766
+ value = await value.read()
767
+ elif (
768
+ is_bytes_sequence_field(field)
769
+ and isinstance(first_field_info, params.File)
770
+ and value_is_sequence(value)
771
+ ):
772
+ # For types
773
+ assert isinstance(value, sequence_types) # type: ignore[arg-type]
774
+ results: List[Union[bytes, str]] = []
775
+
776
+ async def process_fn(
777
+ fn: Callable[[], Coroutine[Any, Any, Any]],
778
+ ) -> None:
779
+ result = await fn()
780
+ results.append(result) # noqa: B023
781
+
782
+ async with anyio.create_task_group() as tg:
783
+ for sub_value in value:
784
+ tg.start_soon(process_fn, sub_value.read)
785
+ value = serialize_sequence_value(field=field, value=results)
786
+ values[field.name] = value
787
+ return values
788
+
789
+
707
790
  async def request_body_to_args(
708
- required_params: List[ModelField],
791
+ body_fields: List[ModelField],
709
792
  received_body: Optional[Union[Dict[str, Any], FormData]],
793
+ embed_body_fields: bool,
710
794
  ) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
711
- values = {}
795
+ values: Dict[str, Any] = {}
712
796
  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)
797
+ assert body_fields, "request_body_to_args() should be called with fields"
798
+ single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields
799
+ first_field = body_fields[0]
800
+ body_to_process = received_body
801
+ if isinstance(received_body, FormData):
802
+ body_to_process = await _extract_form_body(body_fields, received_body)
803
+
804
+ if single_not_embedded_field:
805
+ loc: Tuple[str, ...] = ("body",)
806
+ v_, errors_ = _validate_value_with_model_field(
807
+ field=first_field, value=body_to_process, values=values, loc=loc
808
+ )
809
+ return {first_field.name: v_}, errors_
810
+ for field in body_fields:
811
+ loc = ("body", field.alias)
812
+ value: Optional[Any] = None
813
+ if body_to_process is not None:
814
+ try:
815
+ value = body_to_process.get(field.alias)
816
+ # If the received body is a list, not a dict
817
+ except AttributeError:
818
+ errors.append(get_missing_field_error(loc))
751
819
  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_
820
+ v_, errors_ = _validate_value_with_model_field(
821
+ field=field, value=value, values=values, loc=loc
822
+ )
823
+ if errors_:
824
+ errors.extend(errors_)
825
+ else:
826
+ values[field.name] = v_
786
827
  return values, errors
787
828
 
788
829
 
789
- def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]:
790
- flat_dependant = get_flat_dependant(dependant)
830
+ def get_body_field(
831
+ *, flat_dependant: Dependant, name: str, embed_body_fields: bool
832
+ ) -> Optional[ModelField]:
833
+ """
834
+ Get a ModelField representing the request body for a path operation, combining
835
+ all body parameters into a single field if necessary.
836
+
837
+ Used to check if it's form data (with `isinstance(body_field, params.Form)`)
838
+ or JSON and to generate the JSON Schema for a request body.
839
+
840
+ This is **not** used to validate/parse the request body, that's done with each
841
+ individual body parameter.
842
+ """
791
843
  if not flat_dependant.body_params:
792
844
  return None
793
845
  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:
846
+ if not embed_body_fields:
798
847
  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
848
  model_name = "Body_" + name
805
849
  BodyModel = create_body_model(
806
850
  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.112.4
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
@@ -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.112.4.dist-info/METADATA,sha256=5HI7E6Ktp7E6DHqe-EAOrbdi9cOuiJqLfxqBCeJGmcQ,27273
2
+ fastapi-0.112.4.dist-info/WHEEL,sha256=rSwsxJWe3vzyR5HCwjWXQruDgschpei4h_giTm0dJVE,90
3
+ fastapi-0.112.4.dist-info/entry_points.txt,sha256=Nn2-rs4A5_lQZko2b9QqCKQx9Irx0agGbxq3QLgjBxQ,46
4
+ fastapi-0.112.4.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
5
+ fastapi/__init__.py,sha256=6SxOneGIhP_aHxYYRO2T6iyZXYjC_rjss7xd3XsWl7s,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=k3bs2iNotFYcwO_RihkdJjGrBAr2SNOxf6j5u7vu9gM,31980
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.112.4.dist-info/RECORD,,