fastapi 0.112.2__py3-none-any.whl → 0.112.3__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.2"
3
+ __version__ = "0.112.3"
4
4
 
5
5
  from starlette import status as status
6
6
 
@@ -1,58 +1,37 @@
1
- from typing import Any, Callable, List, Optional, Sequence
1
+ from dataclasses import dataclass, field
2
+ from typing import Any, Callable, List, Optional, Sequence, Tuple
2
3
 
3
4
  from fastapi._compat import ModelField
4
5
  from fastapi.security.base import SecurityBase
5
6
 
6
7
 
8
+ @dataclass
7
9
  class SecurityRequirement:
8
- def __init__(
9
- self, security_scheme: SecurityBase, scopes: Optional[Sequence[str]] = None
10
- ):
11
- self.security_scheme = security_scheme
12
- self.scopes = scopes
10
+ security_scheme: SecurityBase
11
+ scopes: Optional[Sequence[str]] = None
13
12
 
14
13
 
14
+ @dataclass
15
15
  class Dependant:
16
- def __init__(
17
- self,
18
- *,
19
- path_params: Optional[List[ModelField]] = None,
20
- query_params: Optional[List[ModelField]] = None,
21
- header_params: Optional[List[ModelField]] = None,
22
- cookie_params: Optional[List[ModelField]] = None,
23
- body_params: Optional[List[ModelField]] = None,
24
- dependencies: Optional[List["Dependant"]] = None,
25
- security_schemes: Optional[List[SecurityRequirement]] = None,
26
- name: Optional[str] = None,
27
- call: Optional[Callable[..., Any]] = None,
28
- request_param_name: Optional[str] = None,
29
- websocket_param_name: Optional[str] = None,
30
- http_connection_param_name: Optional[str] = None,
31
- response_param_name: Optional[str] = None,
32
- background_tasks_param_name: Optional[str] = None,
33
- security_scopes_param_name: Optional[str] = None,
34
- security_scopes: Optional[List[str]] = None,
35
- use_cache: bool = True,
36
- path: Optional[str] = None,
37
- ) -> None:
38
- self.path_params = path_params or []
39
- self.query_params = query_params or []
40
- self.header_params = header_params or []
41
- self.cookie_params = cookie_params or []
42
- self.body_params = body_params or []
43
- self.dependencies = dependencies or []
44
- self.security_requirements = security_schemes or []
45
- self.request_param_name = request_param_name
46
- self.websocket_param_name = websocket_param_name
47
- self.http_connection_param_name = http_connection_param_name
48
- self.response_param_name = response_param_name
49
- self.background_tasks_param_name = background_tasks_param_name
50
- self.security_scopes = security_scopes
51
- self.security_scopes_param_name = security_scopes_param_name
52
- self.name = name
53
- self.call = call
54
- self.use_cache = use_cache
55
- # Store the path to be able to re-generate a dependable from it in overrides
56
- self.path = path
57
- # Save the cache key at creation to optimize performance
16
+ path_params: List[ModelField] = field(default_factory=list)
17
+ query_params: List[ModelField] = field(default_factory=list)
18
+ header_params: List[ModelField] = field(default_factory=list)
19
+ cookie_params: List[ModelField] = field(default_factory=list)
20
+ body_params: List[ModelField] = field(default_factory=list)
21
+ dependencies: List["Dependant"] = field(default_factory=list)
22
+ security_requirements: List[SecurityRequirement] = field(default_factory=list)
23
+ name: Optional[str] = None
24
+ call: Optional[Callable[..., Any]] = None
25
+ request_param_name: Optional[str] = None
26
+ websocket_param_name: Optional[str] = None
27
+ http_connection_param_name: Optional[str] = None
28
+ response_param_name: Optional[str] = None
29
+ background_tasks_param_name: Optional[str] = None
30
+ security_scopes_param_name: Optional[str] = None
31
+ security_scopes: Optional[List[str]] = None
32
+ use_cache: bool = True
33
+ path: Optional[str] = None
34
+ cache_key: Tuple[Optional[Callable[..., Any]], Tuple[str, ...]] = field(init=False)
35
+
36
+ def __post_init__(self) -> None:
58
37
  self.cache_key = (self.call, tuple(sorted(set(self.security_scopes or []))))
@@ -1,6 +1,7 @@
1
1
  import inspect
2
2
  from contextlib import AsyncExitStack, contextmanager
3
3
  from copy import copy, deepcopy
4
+ from dataclasses import dataclass
4
5
  from typing import (
5
6
  Any,
6
7
  Callable,
@@ -54,7 +55,7 @@ from fastapi.logger import logger
54
55
  from fastapi.security.base import SecurityBase
55
56
  from fastapi.security.oauth2 import OAuth2, SecurityScopes
56
57
  from fastapi.security.open_id_connect_url import OpenIdConnect
57
- from fastapi.utils import create_response_field, get_path_param_names
58
+ from fastapi.utils import create_model_field, get_path_param_names
58
59
  from pydantic.fields import FieldInfo
59
60
  from starlette.background import BackgroundTasks as StarletteBackgroundTasks
60
61
  from starlette.concurrency import run_in_threadpool
@@ -79,25 +80,23 @@ multipart_incorrect_install_error = (
79
80
  )
80
81
 
81
82
 
82
- def check_file_field(field: ModelField) -> None:
83
- field_info = field.field_info
84
- if isinstance(field_info, params.Form):
83
+ def ensure_multipart_is_installed() -> None:
84
+ try:
85
+ # __version__ is available in both multiparts, and can be mocked
86
+ from multipart import __version__ # type: ignore
87
+
88
+ assert __version__
85
89
  try:
86
- # __version__ is available in both multiparts, and can be mocked
87
- from multipart import __version__ # type: ignore
88
-
89
- assert __version__
90
- try:
91
- # parse_options_header is only available in the right multipart
92
- from multipart.multipart import parse_options_header # type: ignore
93
-
94
- assert parse_options_header
95
- except ImportError:
96
- logger.error(multipart_incorrect_install_error)
97
- raise RuntimeError(multipart_incorrect_install_error) from None
90
+ # parse_options_header is only available in the right multipart
91
+ from multipart.multipart import parse_options_header # type: ignore
92
+
93
+ assert parse_options_header
98
94
  except ImportError:
99
- logger.error(multipart_not_installed_error)
100
- raise RuntimeError(multipart_not_installed_error) from None
95
+ logger.error(multipart_incorrect_install_error)
96
+ raise RuntimeError(multipart_incorrect_install_error) from None
97
+ except ImportError:
98
+ logger.error(multipart_not_installed_error)
99
+ raise RuntimeError(multipart_not_installed_error) from None
101
100
 
102
101
 
103
102
  def get_param_sub_dependant(
@@ -175,7 +174,7 @@ def get_flat_dependant(
175
174
  header_params=dependant.header_params.copy(),
176
175
  cookie_params=dependant.cookie_params.copy(),
177
176
  body_params=dependant.body_params.copy(),
178
- security_schemes=dependant.security_requirements.copy(),
177
+ security_requirements=dependant.security_requirements.copy(),
179
178
  use_cache=dependant.use_cache,
180
179
  path=dependant.path,
181
180
  )
@@ -258,16 +257,16 @@ def get_dependant(
258
257
  )
259
258
  for param_name, param in signature_params.items():
260
259
  is_path_param = param_name in path_param_names
261
- type_annotation, depends, param_field = analyze_param(
260
+ param_details = analyze_param(
262
261
  param_name=param_name,
263
262
  annotation=param.annotation,
264
263
  value=param.default,
265
264
  is_path_param=is_path_param,
266
265
  )
267
- if depends is not None:
266
+ if param_details.depends is not None:
268
267
  sub_dependant = get_param_sub_dependant(
269
268
  param_name=param_name,
270
- depends=depends,
269
+ depends=param_details.depends,
271
270
  path=path,
272
271
  security_scopes=security_scopes,
273
272
  )
@@ -275,18 +274,18 @@ def get_dependant(
275
274
  continue
276
275
  if add_non_field_param_to_dependency(
277
276
  param_name=param_name,
278
- type_annotation=type_annotation,
277
+ type_annotation=param_details.type_annotation,
279
278
  dependant=dependant,
280
279
  ):
281
280
  assert (
282
- param_field is None
281
+ param_details.field is None
283
282
  ), f"Cannot specify multiple FastAPI annotations for {param_name!r}"
284
283
  continue
285
- assert param_field is not None
286
- if is_body_param(param_field=param_field, is_path_param=is_path_param):
287
- dependant.body_params.append(param_field)
284
+ assert param_details.field is not None
285
+ if is_body_param(param_field=param_details.field, is_path_param=is_path_param):
286
+ dependant.body_params.append(param_details.field)
288
287
  else:
289
- add_param_to_fields(field=param_field, dependant=dependant)
288
+ add_param_to_fields(field=param_details.field, dependant=dependant)
290
289
  return dependant
291
290
 
292
291
 
@@ -314,13 +313,20 @@ def add_non_field_param_to_dependency(
314
313
  return None
315
314
 
316
315
 
316
+ @dataclass
317
+ class ParamDetails:
318
+ type_annotation: Any
319
+ depends: Optional[params.Depends]
320
+ field: Optional[ModelField]
321
+
322
+
317
323
  def analyze_param(
318
324
  *,
319
325
  param_name: str,
320
326
  annotation: Any,
321
327
  value: Any,
322
328
  is_path_param: bool,
323
- ) -> Tuple[Any, Optional[params.Depends], Optional[ModelField]]:
329
+ ) -> ParamDetails:
324
330
  field_info = None
325
331
  depends = None
326
332
  type_annotation: Any = Any
@@ -328,6 +334,7 @@ def analyze_param(
328
334
  if annotation is not inspect.Signature.empty:
329
335
  use_annotation = annotation
330
336
  type_annotation = annotation
337
+ # Extract Annotated info
331
338
  if get_origin(use_annotation) is Annotated:
332
339
  annotated_args = get_args(annotation)
333
340
  type_annotation = annotated_args[0]
@@ -347,6 +354,7 @@ def analyze_param(
347
354
  )
348
355
  else:
349
356
  fastapi_annotation = None
357
+ # Set default for Annotated FieldInfo
350
358
  if isinstance(fastapi_annotation, FieldInfo):
351
359
  # Copy `field_info` because we mutate `field_info.default` below.
352
360
  field_info = copy_field_info(
@@ -361,9 +369,10 @@ def analyze_param(
361
369
  field_info.default = value
362
370
  else:
363
371
  field_info.default = Required
372
+ # Get Annotated Depends
364
373
  elif isinstance(fastapi_annotation, params.Depends):
365
374
  depends = fastapi_annotation
366
-
375
+ # Get Depends from default value
367
376
  if isinstance(value, params.Depends):
368
377
  assert depends is None, (
369
378
  "Cannot specify `Depends` in `Annotated` and default value"
@@ -374,6 +383,7 @@ def analyze_param(
374
383
  f" default value together for {param_name!r}"
375
384
  )
376
385
  depends = value
386
+ # Get FieldInfo from default value
377
387
  elif isinstance(value, FieldInfo):
378
388
  assert field_info is None, (
379
389
  "Cannot specify FastAPI annotations in `Annotated` and default value"
@@ -383,11 +393,13 @@ def analyze_param(
383
393
  if PYDANTIC_V2:
384
394
  field_info.annotation = type_annotation
385
395
 
396
+ # Get Depends from type annotation
386
397
  if depends is not None and depends.dependency is None:
387
398
  # Copy `depends` before mutating it
388
399
  depends = copy(depends)
389
400
  depends.dependency = type_annotation
390
401
 
402
+ # Handle non-param type annotations like Request
391
403
  if lenient_issubclass(
392
404
  type_annotation,
393
405
  (
@@ -403,6 +415,7 @@ def analyze_param(
403
415
  assert (
404
416
  field_info is None
405
417
  ), f"Cannot specify FastAPI annotation for type {type_annotation!r}"
418
+ # Handle default assignations, neither field_info nor depends was not found in Annotated nor default value
406
419
  elif field_info is None and depends is None:
407
420
  default_value = value if value is not inspect.Signature.empty else Required
408
421
  if is_path_param:
@@ -420,7 +433,9 @@ def analyze_param(
420
433
  field_info = params.Query(annotation=use_annotation, default=default_value)
421
434
 
422
435
  field = None
436
+ # It's a field_info, not a dependency
423
437
  if field_info is not None:
438
+ # Handle field_info.in_
424
439
  if is_path_param:
425
440
  assert isinstance(field_info, params.Path), (
426
441
  f"Cannot use `{field_info.__class__.__name__}` for path param"
@@ -436,12 +451,14 @@ def analyze_param(
436
451
  field_info,
437
452
  param_name,
438
453
  )
454
+ if isinstance(field_info, params.Form):
455
+ ensure_multipart_is_installed()
439
456
  if not field_info.alias and getattr(field_info, "convert_underscores", None):
440
457
  alias = param_name.replace("_", "-")
441
458
  else:
442
459
  alias = field_info.alias or param_name
443
460
  field_info.alias = alias
444
- field = create_response_field(
461
+ field = create_model_field(
445
462
  name=param_name,
446
463
  type_=use_annotation_from_field_info,
447
464
  default=field_info.default,
@@ -450,7 +467,7 @@ def analyze_param(
450
467
  field_info=field_info,
451
468
  )
452
469
 
453
- return type_annotation, depends, field
470
+ return ParamDetails(type_annotation=type_annotation, depends=depends, field=field)
454
471
 
455
472
 
456
473
  def is_body_param(*, param_field: ModelField, is_path_param: bool) -> bool:
@@ -521,6 +538,15 @@ async def solve_generator(
521
538
  return await stack.enter_async_context(cm)
522
539
 
523
540
 
541
+ @dataclass
542
+ class SolvedDependency:
543
+ values: Dict[str, Any]
544
+ errors: List[Any]
545
+ background_tasks: Optional[StarletteBackgroundTasks]
546
+ response: Response
547
+ dependency_cache: Dict[Tuple[Callable[..., Any], Tuple[str]], Any]
548
+
549
+
524
550
  async def solve_dependencies(
525
551
  *,
526
552
  request: Union[Request, WebSocket],
@@ -531,13 +557,7 @@ async def solve_dependencies(
531
557
  dependency_overrides_provider: Optional[Any] = None,
532
558
  dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
533
559
  async_exit_stack: AsyncExitStack,
534
- ) -> Tuple[
535
- Dict[str, Any],
536
- List[Any],
537
- Optional[StarletteBackgroundTasks],
538
- Response,
539
- Dict[Tuple[Callable[..., Any], Tuple[str]], Any],
540
- ]:
560
+ ) -> SolvedDependency:
541
561
  values: Dict[str, Any] = {}
542
562
  errors: List[Any] = []
543
563
  if response is None:
@@ -579,27 +599,21 @@ async def solve_dependencies(
579
599
  dependency_cache=dependency_cache,
580
600
  async_exit_stack=async_exit_stack,
581
601
  )
582
- (
583
- sub_values,
584
- sub_errors,
585
- background_tasks,
586
- _, # the subdependency returns the same response we have
587
- sub_dependency_cache,
588
- ) = solved_result
589
- dependency_cache.update(sub_dependency_cache)
590
- if sub_errors:
591
- errors.extend(sub_errors)
602
+ background_tasks = solved_result.background_tasks
603
+ dependency_cache.update(solved_result.dependency_cache)
604
+ if solved_result.errors:
605
+ errors.extend(solved_result.errors)
592
606
  continue
593
607
  if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
594
608
  solved = dependency_cache[sub_dependant.cache_key]
595
609
  elif is_gen_callable(call) or is_async_gen_callable(call):
596
610
  solved = await solve_generator(
597
- call=call, stack=async_exit_stack, sub_values=sub_values
611
+ call=call, stack=async_exit_stack, sub_values=solved_result.values
598
612
  )
599
613
  elif is_coroutine_callable(call):
600
- solved = await call(**sub_values)
614
+ solved = await call(**solved_result.values)
601
615
  else:
602
- solved = await run_in_threadpool(call, **sub_values)
616
+ solved = await run_in_threadpool(call, **solved_result.values)
603
617
  if sub_dependant.name is not None:
604
618
  values[sub_dependant.name] = solved
605
619
  if sub_dependant.cache_key not in dependency_cache:
@@ -646,7 +660,13 @@ async def solve_dependencies(
646
660
  values[dependant.security_scopes_param_name] = SecurityScopes(
647
661
  scopes=dependant.security_scopes
648
662
  )
649
- return values, errors, background_tasks, response, dependency_cache
663
+ return SolvedDependency(
664
+ values=values,
665
+ errors=errors,
666
+ background_tasks=background_tasks,
667
+ response=response,
668
+ dependency_cache=dependency_cache,
669
+ )
650
670
 
651
671
 
652
672
  def request_params_to_args(
@@ -775,7 +795,6 @@ def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]:
775
795
  embed = getattr(field_info, "embed", None)
776
796
  body_param_names_set = {param.name for param in flat_dependant.body_params}
777
797
  if len(body_param_names_set) == 1 and not embed:
778
- check_file_field(first_param)
779
798
  return first_param
780
799
  # If one field requires to embed, all have to be embedded
781
800
  # in case a sub-dependency is evaluated with a single unique body field
@@ -807,12 +826,11 @@ def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]:
807
826
  ]
808
827
  if len(set(body_param_media_types)) == 1:
809
828
  BodyFieldInfo_kwargs["media_type"] = body_param_media_types[0]
810
- final_field = create_response_field(
829
+ final_field = create_model_field(
811
830
  name="body",
812
831
  type_=BodyModel,
813
832
  required=required,
814
833
  alias="body",
815
834
  field_info=BodyFieldInfo(**BodyFieldInfo_kwargs),
816
835
  )
817
- check_file_field(final_field)
818
836
  return final_field
fastapi/routing.py CHANGED
@@ -49,7 +49,7 @@ from fastapi.exceptions import (
49
49
  from fastapi.types import DecoratedCallable, IncEx
50
50
  from fastapi.utils import (
51
51
  create_cloned_field,
52
- create_response_field,
52
+ create_model_field,
53
53
  generate_unique_id,
54
54
  get_value_or_default,
55
55
  is_body_allowed_for_status_code,
@@ -292,26 +292,34 @@ def get_request_handler(
292
292
  dependency_overrides_provider=dependency_overrides_provider,
293
293
  async_exit_stack=async_exit_stack,
294
294
  )
295
- values, errors, background_tasks, sub_response, _ = solved_result
295
+ errors = solved_result.errors
296
296
  if not errors:
297
297
  raw_response = await run_endpoint_function(
298
- dependant=dependant, values=values, is_coroutine=is_coroutine
298
+ dependant=dependant,
299
+ values=solved_result.values,
300
+ is_coroutine=is_coroutine,
299
301
  )
300
302
  if isinstance(raw_response, Response):
301
303
  if raw_response.background is None:
302
- raw_response.background = background_tasks
304
+ raw_response.background = solved_result.background_tasks
303
305
  response = raw_response
304
306
  else:
305
- response_args: Dict[str, Any] = {"background": background_tasks}
307
+ response_args: Dict[str, Any] = {
308
+ "background": solved_result.background_tasks
309
+ }
306
310
  # If status_code was set, use it, otherwise use the default from the
307
311
  # response class, in the case of redirect it's 307
308
312
  current_status_code = (
309
- status_code if status_code else sub_response.status_code
313
+ status_code
314
+ if status_code
315
+ else solved_result.response.status_code
310
316
  )
311
317
  if current_status_code is not None:
312
318
  response_args["status_code"] = current_status_code
313
- if sub_response.status_code:
314
- response_args["status_code"] = sub_response.status_code
319
+ if solved_result.response.status_code:
320
+ response_args["status_code"] = (
321
+ solved_result.response.status_code
322
+ )
315
323
  content = await serialize_response(
316
324
  field=response_field,
317
325
  response_content=raw_response,
@@ -326,7 +334,7 @@ def get_request_handler(
326
334
  response = actual_response_class(content, **response_args)
327
335
  if not is_body_allowed_for_status_code(response.status_code):
328
336
  response.body = b""
329
- response.headers.raw.extend(sub_response.headers.raw)
337
+ response.headers.raw.extend(solved_result.response.headers.raw)
330
338
  if errors:
331
339
  validation_error = RequestValidationError(
332
340
  _normalize_errors(errors), body=body
@@ -360,11 +368,12 @@ def get_websocket_app(
360
368
  dependency_overrides_provider=dependency_overrides_provider,
361
369
  async_exit_stack=async_exit_stack,
362
370
  )
363
- values, errors, _, _2, _3 = solved_result
364
- if errors:
365
- raise WebSocketRequestValidationError(_normalize_errors(errors))
371
+ if solved_result.errors:
372
+ raise WebSocketRequestValidationError(
373
+ _normalize_errors(solved_result.errors)
374
+ )
366
375
  assert dependant.call is not None, "dependant.call must be a function"
367
- await dependant.call(**values)
376
+ await dependant.call(**solved_result.values)
368
377
 
369
378
  return app
370
379
 
@@ -488,7 +497,7 @@ class APIRoute(routing.Route):
488
497
  status_code
489
498
  ), f"Status code {status_code} must not have a response body"
490
499
  response_name = "Response_" + self.unique_id
491
- self.response_field = create_response_field(
500
+ self.response_field = create_model_field(
492
501
  name=response_name,
493
502
  type_=self.response_model,
494
503
  mode="serialization",
@@ -521,7 +530,7 @@ class APIRoute(routing.Route):
521
530
  additional_status_code
522
531
  ), f"Status code {additional_status_code} must not have a response body"
523
532
  response_name = f"Response_{additional_status_code}_{self.unique_id}"
524
- response_field = create_response_field(name=response_name, type_=model)
533
+ response_field = create_model_field(name=response_name, type_=model)
525
534
  response_fields[additional_status_code] = response_field
526
535
  if response_fields:
527
536
  self.response_fields: Dict[Union[int, str], ModelField] = response_fields
fastapi/utils.py CHANGED
@@ -60,9 +60,9 @@ def get_path_param_names(path: str) -> Set[str]:
60
60
  return set(re.findall("{(.*?)}", path))
61
61
 
62
62
 
63
- def create_response_field(
63
+ def create_model_field(
64
64
  name: str,
65
- type_: Type[Any],
65
+ type_: Any,
66
66
  class_validators: Optional[Dict[str, Validator]] = None,
67
67
  default: Optional[Any] = Undefined,
68
68
  required: Union[bool, UndefinedType] = Undefined,
@@ -71,9 +71,6 @@ def create_response_field(
71
71
  alias: Optional[str] = None,
72
72
  mode: Literal["validation", "serialization"] = "validation",
73
73
  ) -> ModelField:
74
- """
75
- Create a new response field. Raises if type_ is invalid.
76
- """
77
74
  class_validators = class_validators or {}
78
75
  if PYDANTIC_V2:
79
76
  field_info = field_info or FieldInfo(
@@ -135,7 +132,7 @@ def create_cloned_field(
135
132
  use_type.__fields__[f.name] = create_cloned_field(
136
133
  f, cloned_types=cloned_types
137
134
  )
138
- new_field = create_response_field(name=field.name, type_=use_type)
135
+ new_field = create_model_field(name=field.name, type_=use_type)
139
136
  new_field.has_alias = field.has_alias # type: ignore[attr-defined]
140
137
  new_field.alias = field.alias # type: ignore[misc]
141
138
  new_field.class_validators = field.class_validators # type: ignore[attr-defined]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastapi
3
- Version: 0.112.2
3
+ Version: 0.112.3
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,9 +115,8 @@ 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/configuration/frameworks/?utm_medium=advertising&utm_source=fastapi&utm_campaign=docs#fastapi-example" target="_blank" title="Coherence"><img src="https://fastapi.tiangolo.com/img/sponsors/coherence.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>
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
- <a href="https://konghq.com/products/kong-konnect?utm_medium=referral&utm_source=github&utm_campaign=platform&utm_content=fast-api" target="_blank" title="Kong Konnect - API management platform"><img src="https://fastapi.tiangolo.com/img/sponsors/kong.png"></a>
121
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>
122
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>
123
122
  <a href="https://liblab.com?utm_source=fastapi" target="_blank" title="liblab - Generate SDKs from FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/liblab.png"></a>
@@ -457,7 +456,7 @@ Coming back to the previous code example, **FastAPI** will:
457
456
  * Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.
458
457
  * As the `q` parameter is declared with `= None`, it is optional.
459
458
  * Without the `None` it would be required (as is the body in the case with `PUT`).
460
- * For `PUT` requests to `/items/{item_id}`, Read the body as JSON:
459
+ * For `PUT` requests to `/items/{item_id}`, read the body as JSON:
461
460
  * Check that it has a required attribute `name` that should be a `str`.
462
461
  * Check that it has a required attribute `price` that has to be a `float`.
463
462
  * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
@@ -1,8 +1,8 @@
1
- fastapi-0.112.2.dist-info/METADATA,sha256=bnN5StpCV0DjSg7dk8yiEBkSTr_hAjcMHoxYSv4LuIU,27528
2
- fastapi-0.112.2.dist-info/WHEEL,sha256=rSwsxJWe3vzyR5HCwjWXQruDgschpei4h_giTm0dJVE,90
3
- fastapi-0.112.2.dist-info/entry_points.txt,sha256=Nn2-rs4A5_lQZko2b9QqCKQx9Irx0agGbxq3QLgjBxQ,46
4
- fastapi-0.112.2.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
5
- fastapi/__init__.py,sha256=61dw7I6Jsj1RGSw6HG8Q3fNgxEuX7Y_QoG39NNJ81C8,1081
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
6
6
  fastapi/__main__.py,sha256=bKePXLdO4SsVSM6r9SVoLickJDcR2c0cTOxZRKq26YQ,37
7
7
  fastapi/_compat.py,sha256=OjE3FUZ0IPXqIJWKhoWKDNCHv4so-FQ-rfN8ngQZeFE,23134
8
8
  fastapi/applications.py,sha256=Ix-o9pQAWhEDf9J0Q1hZ0nBB1uP72c-Y3oiYzvrwqiM,176316
@@ -11,8 +11,8 @@ fastapi/cli.py,sha256=OYhZb0NR_deuT5ofyPF2NoNBzZDNOP8Salef2nk-HqA,418
11
11
  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
- fastapi/dependencies/models.py,sha256=-n-YCxzgVBkurQi49qOTooT71v_oeAhHJ-qQFonxh5o,2494
15
- fastapi/dependencies/utils.py,sha256=DBKj3z2oU1U3W89zTc3e6ej6V1Qy1tvx0V5ho_cYVIQ,30243
14
+ fastapi/dependencies/models.py,sha256=Pjl6vx-4nZ5Tta9kJa3-RfQKkXtCpS09-FhMgs9eWNs,1507
15
+ fastapi/dependencies/utils.py,sha256=2J36LBZMJTZ6jadjANaG-voTfzgs8JpROJCRtoLoSFA,30922
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
@@ -33,7 +33,7 @@ fastapi/params.py,sha256=CWumi-CkfxWSg4I2KpPxIvQyKdeW_Lnct9reHnrTwW8,28199
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=sUxTddjKa4IokZAOzv6fHTF0MbltBtJv_QRmh4-L_eA,175040
36
+ fastapi/routing.py,sha256=e_H0k8q4HQl88mgi-Jdf-9hBfn2gTvDjixXrufDN3U0,175326
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
@@ -45,6 +45,6 @@ fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69
45
45
  fastapi/templating.py,sha256=4zsuTWgcjcEainMJFAlW6-gnslm6AgOS1SiiDWfmQxk,76
46
46
  fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66
47
47
  fastapi/types.py,sha256=nFb36sK3DSoqoyo7Miwy3meKK5UdFBgkAgLSzQlUVyI,383
48
- fastapi/utils.py,sha256=T1OYlJBw80LMtKhvU18J6XeTX4_MMPzIGPYcJqI5QVM,8037
48
+ fastapi/utils.py,sha256=y8Bj5ttMaI9tS4D60OUgXqKnktBr99NdYUnHHV9LgoY,7948
49
49
  fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222
50
- fastapi-0.112.2.dist-info/RECORD,,
50
+ fastapi-0.112.3.dist-info/RECORD,,