fastapi 0.99.1__py3-none-any.whl → 0.100.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/openapi/utils.py CHANGED
@@ -1,35 +1,37 @@
1
1
  import http.client
2
2
  import inspect
3
3
  import warnings
4
- from enum import Enum
5
4
  from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast
6
5
 
7
6
  from fastapi import routing
7
+ from fastapi._compat import (
8
+ GenerateJsonSchema,
9
+ JsonSchemaValue,
10
+ ModelField,
11
+ Undefined,
12
+ get_compat_model_name_map,
13
+ get_definitions,
14
+ get_schema_from_model_field,
15
+ lenient_issubclass,
16
+ )
8
17
  from fastapi.datastructures import DefaultPlaceholder
9
18
  from fastapi.dependencies.models import Dependant
10
19
  from fastapi.dependencies.utils import get_flat_dependant, get_flat_params
11
20
  from fastapi.encoders import jsonable_encoder
12
- from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX
21
+ from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX, REF_TEMPLATE
13
22
  from fastapi.openapi.models import OpenAPI
14
23
  from fastapi.params import Body, Param
15
24
  from fastapi.responses import Response
25
+ from fastapi.types import ModelNameMap
16
26
  from fastapi.utils import (
17
27
  deep_dict_update,
18
28
  generate_operation_id_for_path,
19
- get_model_definitions,
20
29
  is_body_allowed_for_status_code,
21
30
  )
22
- from pydantic import BaseModel
23
- from pydantic.fields import ModelField, Undefined
24
- from pydantic.schema import (
25
- field_schema,
26
- get_flat_models_from_fields,
27
- get_model_name_map,
28
- )
29
- from pydantic.utils import lenient_issubclass
30
31
  from starlette.responses import JSONResponse
31
32
  from starlette.routing import BaseRoute
32
33
  from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
34
+ from typing_extensions import Literal
33
35
 
34
36
  validation_error_definition = {
35
37
  "title": "ValidationError",
@@ -88,7 +90,11 @@ def get_openapi_security_definitions(
88
90
  def get_openapi_operation_parameters(
89
91
  *,
90
92
  all_route_params: Sequence[ModelField],
91
- model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
93
+ schema_generator: GenerateJsonSchema,
94
+ model_name_map: ModelNameMap,
95
+ field_mapping: Dict[
96
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
97
+ ],
92
98
  ) -> List[Dict[str, Any]]:
93
99
  parameters = []
94
100
  for param in all_route_params:
@@ -96,13 +102,17 @@ def get_openapi_operation_parameters(
96
102
  field_info = cast(Param, field_info)
97
103
  if not field_info.include_in_schema:
98
104
  continue
105
+ param_schema = get_schema_from_model_field(
106
+ field=param,
107
+ schema_generator=schema_generator,
108
+ model_name_map=model_name_map,
109
+ field_mapping=field_mapping,
110
+ )
99
111
  parameter = {
100
112
  "name": param.alias,
101
113
  "in": field_info.in_.value,
102
114
  "required": param.required,
103
- "schema": field_schema(
104
- param, model_name_map=model_name_map, ref_prefix=REF_PREFIX
105
- )[0],
115
+ "schema": param_schema,
106
116
  }
107
117
  if field_info.description:
108
118
  parameter["description"] = field_info.description
@@ -117,13 +127,20 @@ def get_openapi_operation_parameters(
117
127
  def get_openapi_operation_request_body(
118
128
  *,
119
129
  body_field: Optional[ModelField],
120
- model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
130
+ schema_generator: GenerateJsonSchema,
131
+ model_name_map: ModelNameMap,
132
+ field_mapping: Dict[
133
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
134
+ ],
121
135
  ) -> Optional[Dict[str, Any]]:
122
136
  if not body_field:
123
137
  return None
124
138
  assert isinstance(body_field, ModelField)
125
- body_schema, _, _ = field_schema(
126
- body_field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
139
+ body_schema = get_schema_from_model_field(
140
+ field=body_field,
141
+ schema_generator=schema_generator,
142
+ model_name_map=model_name_map,
143
+ field_mapping=field_mapping,
127
144
  )
128
145
  field_info = cast(Body, body_field.field_info)
129
146
  request_media_type = field_info.media_type
@@ -186,7 +203,14 @@ def get_openapi_operation_metadata(
186
203
 
187
204
 
188
205
  def get_openapi_path(
189
- *, route: routing.APIRoute, model_name_map: Dict[type, str], operation_ids: Set[str]
206
+ *,
207
+ route: routing.APIRoute,
208
+ operation_ids: Set[str],
209
+ schema_generator: GenerateJsonSchema,
210
+ model_name_map: ModelNameMap,
211
+ field_mapping: Dict[
212
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
213
+ ],
190
214
  ) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
191
215
  path = {}
192
216
  security_schemes: Dict[str, Any] = {}
@@ -214,7 +238,10 @@ def get_openapi_path(
214
238
  security_schemes.update(security_definitions)
215
239
  all_route_params = get_flat_params(route.dependant)
216
240
  operation_parameters = get_openapi_operation_parameters(
217
- all_route_params=all_route_params, model_name_map=model_name_map
241
+ all_route_params=all_route_params,
242
+ schema_generator=schema_generator,
243
+ model_name_map=model_name_map,
244
+ field_mapping=field_mapping,
218
245
  )
219
246
  parameters.extend(operation_parameters)
220
247
  if parameters:
@@ -232,7 +259,10 @@ def get_openapi_path(
232
259
  operation["parameters"] = list(all_parameters.values())
233
260
  if method in METHODS_WITH_BODY:
234
261
  request_body_oai = get_openapi_operation_request_body(
235
- body_field=route.body_field, model_name_map=model_name_map
262
+ body_field=route.body_field,
263
+ schema_generator=schema_generator,
264
+ model_name_map=model_name_map,
265
+ field_mapping=field_mapping,
236
266
  )
237
267
  if request_body_oai:
238
268
  operation["requestBody"] = request_body_oai
@@ -246,8 +276,10 @@ def get_openapi_path(
246
276
  cb_definitions,
247
277
  ) = get_openapi_path(
248
278
  route=callback,
249
- model_name_map=model_name_map,
250
279
  operation_ids=operation_ids,
280
+ schema_generator=schema_generator,
281
+ model_name_map=model_name_map,
282
+ field_mapping=field_mapping,
251
283
  )
252
284
  callbacks[callback.name] = {callback.path: cb_path}
253
285
  operation["callbacks"] = callbacks
@@ -273,10 +305,11 @@ def get_openapi_path(
273
305
  response_schema = {"type": "string"}
274
306
  if lenient_issubclass(current_response_class, JSONResponse):
275
307
  if route.response_field:
276
- response_schema, _, _ = field_schema(
277
- route.response_field,
308
+ response_schema = get_schema_from_model_field(
309
+ field=route.response_field,
310
+ schema_generator=schema_generator,
278
311
  model_name_map=model_name_map,
279
- ref_prefix=REF_PREFIX,
312
+ field_mapping=field_mapping,
280
313
  )
281
314
  else:
282
315
  response_schema = {}
@@ -305,8 +338,11 @@ def get_openapi_path(
305
338
  field = route.response_fields.get(additional_status_code)
306
339
  additional_field_schema: Optional[Dict[str, Any]] = None
307
340
  if field:
308
- additional_field_schema, _, _ = field_schema(
309
- field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
341
+ additional_field_schema = get_schema_from_model_field(
342
+ field=field,
343
+ schema_generator=schema_generator,
344
+ model_name_map=model_name_map,
345
+ field_mapping=field_mapping,
310
346
  )
311
347
  media_type = route_response_media_type or "application/json"
312
348
  additional_schema = (
@@ -352,13 +388,13 @@ def get_openapi_path(
352
388
  return path, security_schemes, definitions
353
389
 
354
390
 
355
- def get_flat_models_from_routes(
391
+ def get_fields_from_routes(
356
392
  routes: Sequence[BaseRoute],
357
- ) -> Set[Union[Type[BaseModel], Type[Enum]]]:
393
+ ) -> List[ModelField]:
358
394
  body_fields_from_routes: List[ModelField] = []
359
395
  responses_from_routes: List[ModelField] = []
360
396
  request_fields_from_routes: List[ModelField] = []
361
- callback_flat_models: Set[Union[Type[BaseModel], Type[Enum]]] = set()
397
+ callback_flat_models: List[ModelField] = []
362
398
  for route in routes:
363
399
  if getattr(route, "include_in_schema", None) and isinstance(
364
400
  route, routing.APIRoute
@@ -373,13 +409,12 @@ def get_flat_models_from_routes(
373
409
  if route.response_fields:
374
410
  responses_from_routes.extend(route.response_fields.values())
375
411
  if route.callbacks:
376
- callback_flat_models |= get_flat_models_from_routes(route.callbacks)
412
+ callback_flat_models.extend(get_fields_from_routes(route.callbacks))
377
413
  params = get_flat_params(route.dependant)
378
414
  request_fields_from_routes.extend(params)
379
415
 
380
- flat_models = callback_flat_models | get_flat_models_from_fields(
381
- body_fields_from_routes + responses_from_routes + request_fields_from_routes,
382
- known_models=set(),
416
+ flat_models = callback_flat_models + list(
417
+ body_fields_from_routes + responses_from_routes + request_fields_from_routes
383
418
  )
384
419
  return flat_models
385
420
 
@@ -417,15 +452,22 @@ def get_openapi(
417
452
  paths: Dict[str, Dict[str, Any]] = {}
418
453
  webhook_paths: Dict[str, Dict[str, Any]] = {}
419
454
  operation_ids: Set[str] = set()
420
- flat_models = get_flat_models_from_routes(list(routes or []) + list(webhooks or []))
421
- model_name_map = get_model_name_map(flat_models)
422
- definitions = get_model_definitions(
423
- flat_models=flat_models, model_name_map=model_name_map
455
+ all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or []))
456
+ model_name_map = get_compat_model_name_map(all_fields)
457
+ schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)
458
+ field_mapping, definitions = get_definitions(
459
+ fields=all_fields,
460
+ schema_generator=schema_generator,
461
+ model_name_map=model_name_map,
424
462
  )
425
463
  for route in routes or []:
426
464
  if isinstance(route, routing.APIRoute):
427
465
  result = get_openapi_path(
428
- route=route, model_name_map=model_name_map, operation_ids=operation_ids
466
+ route=route,
467
+ operation_ids=operation_ids,
468
+ schema_generator=schema_generator,
469
+ model_name_map=model_name_map,
470
+ field_mapping=field_mapping,
429
471
  )
430
472
  if result:
431
473
  path, security_schemes, path_definitions = result
@@ -441,8 +483,10 @@ def get_openapi(
441
483
  if isinstance(webhook, routing.APIRoute):
442
484
  result = get_openapi_path(
443
485
  route=webhook,
444
- model_name_map=model_name_map,
445
486
  operation_ids=operation_ids,
487
+ schema_generator=schema_generator,
488
+ model_name_map=model_name_map,
489
+ field_mapping=field_mapping,
446
490
  )
447
491
  if result:
448
492
  path, security_schemes, path_definitions = result