Browse Source

⬆ Require Pydantic > 1.0 (#1862)

* 🔥 Remove support for Pydantic < 1.0

* 🔥 Remove deprecated skip_defaults from jsonable_encoder and set default for exclude to None, as in Pydantic

* ♻️ Set default of response_model_exclude=None as in Pydantic

* ⬆️ Require Pydantic >=1.0.0 in requirements
pull/1864/head
Sebastián Ramírez 5 years ago
committed by GitHub
parent
commit
e1758d107e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 92
      fastapi/applications.py
  2. 5
      fastapi/dependencies/models.py
  3. 92
      fastapi/dependencies/utils.py
  4. 25
      fastapi/encoders.py
  5. 9
      fastapi/exceptions.py
  6. 13
      fastapi/openapi/models.py
  7. 12
      fastapi/openapi/utils.py
  8. 4
      fastapi/params.py
  9. 3
      fastapi/requests.py
  10. 115
      fastapi/routing.py
  11. 52
      fastapi/utils.py
  12. 2
      pyproject.toml
  13. 8
      tests/test_jsonable_encoder.py
  14. 9
      tests/test_tutorial/test_body_fields/test_tutorial001.py

92
fastapi/applications.py

@ -16,7 +16,6 @@ from fastapi.openapi.docs import (
) )
from fastapi.openapi.utils import get_openapi from fastapi.openapi.utils import get_openapi
from fastapi.params import Depends from fastapi.params import Depends
from fastapi.utils import warning_response_model_skip_defaults_deprecated
from starlette.applications import Starlette from starlette.applications import Starlette
from starlette.datastructures import State from starlette.datastructures import State
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
@ -198,9 +197,8 @@ class FastAPI(Starlette):
methods: Optional[List[str]] = None, methods: Optional[List[str]] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -208,8 +206,6 @@ class FastAPI(Starlette):
response_class: Optional[Type[Response]] = None, response_class: Optional[Type[Response]] = None,
name: Optional[str] = None, name: Optional[str] = None,
) -> None: ) -> None:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
self.router.add_api_route( self.router.add_api_route(
path, path,
endpoint=endpoint, endpoint=endpoint,
@ -227,9 +223,7 @@ class FastAPI(Starlette):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -253,9 +247,8 @@ class FastAPI(Starlette):
methods: Optional[List[str]] = None, methods: Optional[List[str]] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -263,9 +256,6 @@ class FastAPI(Starlette):
response_class: Optional[Type[Response]] = None, response_class: Optional[Type[Response]] = None,
name: Optional[str] = None, name: Optional[str] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
def decorator(func: Callable) -> Callable: def decorator(func: Callable) -> Callable:
self.router.add_api_route( self.router.add_api_route(
path, path,
@ -284,9 +274,7 @@ class FastAPI(Starlette):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -344,9 +332,8 @@ class FastAPI(Starlette):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -355,8 +342,6 @@ class FastAPI(Starlette):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[routing.APIRoute]] = None, callbacks: Optional[List[routing.APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.router.get( return self.router.get(
path, path,
response_model=response_model, response_model=response_model,
@ -372,9 +357,7 @@ class FastAPI(Starlette):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -398,9 +381,8 @@ class FastAPI(Starlette):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -409,8 +391,6 @@ class FastAPI(Starlette):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[routing.APIRoute]] = None, callbacks: Optional[List[routing.APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.router.put( return self.router.put(
path, path,
response_model=response_model, response_model=response_model,
@ -426,9 +406,7 @@ class FastAPI(Starlette):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -452,9 +430,8 @@ class FastAPI(Starlette):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -463,8 +440,6 @@ class FastAPI(Starlette):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[routing.APIRoute]] = None, callbacks: Optional[List[routing.APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.router.post( return self.router.post(
path, path,
response_model=response_model, response_model=response_model,
@ -480,9 +455,7 @@ class FastAPI(Starlette):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -506,9 +479,8 @@ class FastAPI(Starlette):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -517,8 +489,6 @@ class FastAPI(Starlette):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[routing.APIRoute]] = None, callbacks: Optional[List[routing.APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.router.delete( return self.router.delete(
path, path,
response_model=response_model, response_model=response_model,
@ -534,9 +504,7 @@ class FastAPI(Starlette):
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
operation_id=operation_id, operation_id=operation_id,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -560,9 +528,8 @@ class FastAPI(Starlette):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -571,8 +538,6 @@ class FastAPI(Starlette):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[routing.APIRoute]] = None, callbacks: Optional[List[routing.APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.router.options( return self.router.options(
path, path,
response_model=response_model, response_model=response_model,
@ -588,9 +553,7 @@ class FastAPI(Starlette):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -614,9 +577,8 @@ class FastAPI(Starlette):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -625,8 +587,6 @@ class FastAPI(Starlette):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[routing.APIRoute]] = None, callbacks: Optional[List[routing.APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.router.head( return self.router.head(
path, path,
response_model=response_model, response_model=response_model,
@ -642,9 +602,7 @@ class FastAPI(Starlette):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -668,9 +626,8 @@ class FastAPI(Starlette):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -679,8 +636,6 @@ class FastAPI(Starlette):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[routing.APIRoute]] = None, callbacks: Optional[List[routing.APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.router.patch( return self.router.patch(
path, path,
response_model=response_model, response_model=response_model,
@ -696,9 +651,7 @@ class FastAPI(Starlette):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -722,9 +675,8 @@ class FastAPI(Starlette):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -733,8 +685,6 @@ class FastAPI(Starlette):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[routing.APIRoute]] = None, callbacks: Optional[List[routing.APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.router.trace( return self.router.trace(
path, path,
response_model=response_model, response_model=response_model,
@ -750,9 +700,7 @@ class FastAPI(Starlette):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,

5
fastapi/dependencies/models.py

@ -1,12 +1,7 @@
from typing import Callable, List, Optional, Sequence from typing import Callable, List, Optional, Sequence
from fastapi.security.base import SecurityBase from fastapi.security.base import SecurityBase
try:
from pydantic.fields import ModelField from pydantic.fields import ModelField
except ImportError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic.fields import Field as ModelField # type: ignore
param_supported_types = (str, int, float, bool) param_supported_types = (str, int, float, bool)

92
fastapi/dependencies/utils.py

@ -28,24 +28,10 @@ from fastapi.logger import logger
from fastapi.security.base import SecurityBase from fastapi.security.base import SecurityBase
from fastapi.security.oauth2 import OAuth2, SecurityScopes from fastapi.security.oauth2 import OAuth2, SecurityScopes
from fastapi.security.open_id_connect_url import OpenIdConnect from fastapi.security.open_id_connect_url import OpenIdConnect
from fastapi.utils import ( from fastapi.utils import create_response_field, get_path_param_names
PYDANTIC_1, from pydantic import BaseModel, create_model
create_response_field,
get_field_info,
get_path_param_names,
)
from pydantic import BaseConfig, BaseModel, create_model
from pydantic.error_wrappers import ErrorWrapper from pydantic.error_wrappers import ErrorWrapper
from pydantic.errors import MissingError from pydantic.errors import MissingError
from pydantic.utils import lenient_issubclass
from starlette.background import BackgroundTasks
from starlette.concurrency import run_in_threadpool
from starlette.datastructures import FormData, Headers, QueryParams, UploadFile
from starlette.requests import HTTPConnection, Request
from starlette.responses import Response
from starlette.websockets import WebSocket
try:
from pydantic.fields import ( from pydantic.fields import (
SHAPE_LIST, SHAPE_LIST,
SHAPE_SEQUENCE, SHAPE_SEQUENCE,
@ -59,26 +45,13 @@ try:
) )
from pydantic.schema import get_annotation_from_field_info from pydantic.schema import get_annotation_from_field_info
from pydantic.typing import ForwardRef, evaluate_forwardref from pydantic.typing import ForwardRef, evaluate_forwardref
except ImportError: # pragma: nocover from pydantic.utils import lenient_issubclass
# TODO: remove when removing support for Pydantic < 1.0.0 from starlette.background import BackgroundTasks
from pydantic import Schema as FieldInfo # type: ignore from starlette.concurrency import run_in_threadpool
from pydantic.fields import Field as ModelField # type: ignore from starlette.datastructures import FormData, Headers, QueryParams, UploadFile
from pydantic.fields import Required, Shape # type: ignore from starlette.requests import HTTPConnection, Request
from pydantic.schema import get_annotation_from_schema # type: ignore from starlette.responses import Response
from pydantic.utils import ForwardRef, evaluate_forwardref # type: ignore from starlette.websockets import WebSocket
SHAPE_LIST = Shape.LIST
SHAPE_SEQUENCE = Shape.SEQUENCE
SHAPE_SET = Shape.SET
SHAPE_SINGLETON = Shape.SINGLETON
SHAPE_TUPLE = Shape.TUPLE
SHAPE_TUPLE_ELLIPSIS = Shape.TUPLE_ELLIPS
def get_annotation_from_field_info(
annotation: Any, field_info: FieldInfo, field_name: str
) -> Type[Any]:
return get_annotation_from_schema(annotation, field_info)
sequence_shapes = { sequence_shapes = {
SHAPE_LIST, SHAPE_LIST,
@ -113,7 +86,7 @@ multipart_incorrect_install_error = (
def check_file_field(field: ModelField) -> None: def check_file_field(field: ModelField) -> None:
field_info = get_field_info(field) field_info = field.field_info
if isinstance(field_info, params.Form): if isinstance(field_info, params.Form):
try: try:
# __version__ is available in both multiparts, and can be mocked # __version__ is available in both multiparts, and can be mocked
@ -239,7 +212,7 @@ def get_flat_params(dependant: Dependant) -> List[ModelField]:
def is_scalar_field(field: ModelField) -> bool: def is_scalar_field(field: ModelField) -> bool:
field_info = get_field_info(field) field_info = field.field_info
if not ( if not (
field.shape == SHAPE_SINGLETON field.shape == SHAPE_SINGLETON
and not lenient_issubclass(field.type_, BaseModel) and not lenient_issubclass(field.type_, BaseModel)
@ -354,7 +327,7 @@ def get_dependant(
) and is_scalar_sequence_field(param_field): ) and is_scalar_sequence_field(param_field):
add_param_to_fields(field=param_field, dependant=dependant) add_param_to_fields(field=param_field, dependant=dependant)
else: else:
field_info = get_field_info(param_field) field_info = param_field.field_info
assert isinstance( assert isinstance(
field_info, params.Body field_info, params.Body
), f"Param: {param_field.name} can only be a request body, using Body(...)" ), f"Param: {param_field.name} can only be a request body, using Body(...)"
@ -430,16 +403,13 @@ def get_param_field(
) )
field.required = required field.required = required
if not had_schema and not is_scalar_field(field=field): if not had_schema and not is_scalar_field(field=field):
if PYDANTIC_1:
field.field_info = params.Body(field_info.default) field.field_info = params.Body(field_info.default)
else:
field.schema = params.Body(field_info.default) # type: ignore # pragma: nocover
return field return field
def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None: def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
field_info = cast(params.Param, get_field_info(field)) field_info = cast(params.Param, field.field_info)
if field_info.in_ == params.ParamTypes.path: if field_info.in_ == params.ParamTypes.path:
dependant.path_params.append(field) dependant.path_params.append(field)
elif field_info.in_ == params.ParamTypes.query: elif field_info.in_ == params.ParamTypes.query:
@ -642,26 +612,17 @@ def request_params_to_args(
value = received_params.getlist(field.alias) or field.default value = received_params.getlist(field.alias) or field.default
else: else:
value = received_params.get(field.alias) value = received_params.get(field.alias)
field_info = get_field_info(field) field_info = field.field_info
assert isinstance( assert isinstance(
field_info, params.Param field_info, params.Param
), "Params must be subclasses of Param" ), "Params must be subclasses of Param"
if value is None: if value is None:
if field.required: if field.required:
if PYDANTIC_1:
errors.append( errors.append(
ErrorWrapper( ErrorWrapper(
MissingError(), loc=(field_info.in_.value, field.alias) MissingError(), loc=(field_info.in_.value, field.alias)
) )
) )
else: # pragma: nocover
errors.append(
ErrorWrapper( # type: ignore
MissingError(),
loc=(field_info.in_.value, field.alias),
config=BaseConfig,
)
)
else: else:
values[field.name] = deepcopy(field.default) values[field.name] = deepcopy(field.default)
continue continue
@ -685,7 +646,7 @@ async def request_body_to_args(
errors = [] errors = []
if required_params: if required_params:
field = required_params[0] field = required_params[0]
field_info = get_field_info(field) field_info = field.field_info
embed = getattr(field_info, "embed", None) embed = getattr(field_info, "embed", None)
field_alias_omitted = len(required_params) == 1 and not embed field_alias_omitted = len(required_params) == 1 and not embed
if field_alias_omitted: if field_alias_omitted:
@ -752,12 +713,7 @@ async def request_body_to_args(
def get_missing_field_error(loc: Tuple[str, ...]) -> ErrorWrapper: def get_missing_field_error(loc: Tuple[str, ...]) -> ErrorWrapper:
if PYDANTIC_1:
missing_field_error = ErrorWrapper(MissingError(), loc=loc) missing_field_error = ErrorWrapper(MissingError(), loc=loc)
else: # pragma: no cover
missing_field_error = ErrorWrapper( # type: ignore
MissingError(), loc=loc, config=BaseConfig,
)
return missing_field_error return missing_field_error
@ -775,7 +731,7 @@ def get_schema_compatible_field(*, field: ModelField) -> ModelField:
default=field.default, default=field.default,
required=field.required, required=field.required,
alias=field.alias, alias=field.alias,
field_info=get_field_info(field), field_info=field.field_info,
) )
return out_field return out_field
@ -785,7 +741,7 @@ def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]:
if not flat_dependant.body_params: if not flat_dependant.body_params:
return None return None
first_param = flat_dependant.body_params[0] first_param = flat_dependant.body_params[0]
field_info = get_field_info(first_param) field_info = first_param.field_info
embed = getattr(field_info, "embed", None) embed = getattr(field_info, "embed", None)
body_param_names_set = {param.name for param in flat_dependant.body_params} body_param_names_set = {param.name for param in flat_dependant.body_params}
if len(body_param_names_set) == 1 and not embed: if len(body_param_names_set) == 1 and not embed:
@ -796,7 +752,7 @@ def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]:
# in case a sub-dependency is evaluated with a single unique body field # in case a sub-dependency is evaluated with a single unique body field
# That is combined (embedded) with other body fields # That is combined (embedded) with other body fields
for param in flat_dependant.body_params: for param in flat_dependant.body_params:
setattr(get_field_info(param), "embed", True) setattr(param.field_info, "embed", True)
model_name = "Body_" + name model_name = "Body_" + name
BodyModel = create_model(model_name) BodyModel = create_model(model_name)
for f in flat_dependant.body_params: for f in flat_dependant.body_params:
@ -804,21 +760,17 @@ def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]:
required = any(True for f in flat_dependant.body_params if f.required) required = any(True for f in flat_dependant.body_params if f.required)
BodyFieldInfo_kwargs: Dict[str, Any] = dict(default=None) BodyFieldInfo_kwargs: Dict[str, Any] = dict(default=None)
if any( if any(isinstance(f.field_info, params.File) for f in flat_dependant.body_params):
isinstance(get_field_info(f), params.File) for f in flat_dependant.body_params
):
BodyFieldInfo: Type[params.Body] = params.File BodyFieldInfo: Type[params.Body] = params.File
elif any( elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params):
isinstance(get_field_info(f), params.Form) for f in flat_dependant.body_params
):
BodyFieldInfo = params.Form BodyFieldInfo = params.Form
else: else:
BodyFieldInfo = params.Body BodyFieldInfo = params.Body
body_param_media_types = [ body_param_media_types = [
getattr(get_field_info(f), "media_type") getattr(f.field_info, "media_type")
for f in flat_dependant.body_params for f in flat_dependant.body_params
if isinstance(get_field_info(f), params.Body) if isinstance(f.field_info, params.Body)
] ]
if len(set(body_param_media_types)) == 1: if len(set(body_param_media_types)) == 1:
BodyFieldInfo_kwargs["media_type"] = body_param_media_types[0] BodyFieldInfo_kwargs["media_type"] = body_param_media_types[0]

25
fastapi/encoders.py

@ -4,8 +4,6 @@ from pathlib import PurePath
from types import GeneratorType from types import GeneratorType
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
from fastapi.logger import logger
from fastapi.utils import PYDANTIC_1
from pydantic import BaseModel from pydantic import BaseModel
from pydantic.json import ENCODERS_BY_TYPE from pydantic.json import ENCODERS_BY_TYPE
@ -28,21 +26,14 @@ encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE)
def jsonable_encoder( def jsonable_encoder(
obj: Any, obj: Any,
include: Optional[Union[SetIntStr, DictIntStrAny]] = None, include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
exclude: Union[SetIntStr, DictIntStrAny] = set(), exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
by_alias: bool = True, by_alias: bool = True,
skip_defaults: Optional[bool] = None,
exclude_unset: bool = False, exclude_unset: bool = False,
exclude_defaults: bool = False, exclude_defaults: bool = False,
exclude_none: bool = False, exclude_none: bool = False,
custom_encoder: dict = {}, custom_encoder: dict = {},
sqlalchemy_safe: bool = True, sqlalchemy_safe: bool = True,
) -> Any: ) -> Any:
if skip_defaults is not None:
logger.warning( # pragma: nocover
"skip_defaults in jsonable_encoder has been deprecated in favor of "
"exclude_unset to keep in line with Pydantic v1, support for it will be "
"removed soon."
)
if include is not None and not isinstance(include, set): if include is not None and not isinstance(include, set):
include = set(include) include = set(include)
if exclude is not None and not isinstance(exclude, set): if exclude is not None and not isinstance(exclude, set):
@ -51,24 +42,14 @@ def jsonable_encoder(
encoder = getattr(obj.__config__, "json_encoders", {}) encoder = getattr(obj.__config__, "json_encoders", {})
if custom_encoder: if custom_encoder:
encoder.update(custom_encoder) encoder.update(custom_encoder)
if PYDANTIC_1:
obj_dict = obj.dict( obj_dict = obj.dict(
include=include, include=include,
exclude=exclude, exclude=exclude,
by_alias=by_alias, by_alias=by_alias,
exclude_unset=bool(exclude_unset or skip_defaults), exclude_unset=exclude_unset,
exclude_none=exclude_none, exclude_none=exclude_none,
exclude_defaults=exclude_defaults, exclude_defaults=exclude_defaults,
) )
else: # pragma: nocover
if exclude_defaults:
raise ValueError("Cannot use exclude_defaults")
obj_dict = obj.dict(
include=include,
exclude=exclude,
by_alias=by_alias,
skip_defaults=bool(exclude_unset or skip_defaults),
)
if "__root__" in obj_dict: if "__root__" in obj_dict:
obj_dict = obj_dict["__root__"] obj_dict = obj_dict["__root__"]
return jsonable_encoder( return jsonable_encoder(
@ -94,7 +75,7 @@ def jsonable_encoder(
or (not key.startswith("_sa")) or (not key.startswith("_sa"))
) )
and (value is not None or not exclude_none) and (value is not None or not exclude_none)
and ((include and key in include) or key not in exclude) and ((include and key in include) or not exclude or key not in exclude)
): ):
encoded_key = jsonable_encoder( encoded_key = jsonable_encoder(
key, key,

9
fastapi/exceptions.py

@ -1,11 +1,8 @@
from typing import Any, Dict, Optional, Sequence from typing import Any, Dict, Optional, Sequence
from fastapi.utils import PYDANTIC_1
from pydantic import ValidationError, create_model from pydantic import ValidationError, create_model
from pydantic.error_wrappers import ErrorList from pydantic.error_wrappers import ErrorList
from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.requests import Request
from starlette.websockets import WebSocket
class HTTPException(StarletteHTTPException): class HTTPException(StarletteHTTPException):
@ -32,15 +29,9 @@ class FastAPIError(RuntimeError):
class RequestValidationError(ValidationError): class RequestValidationError(ValidationError):
def __init__(self, errors: Sequence[ErrorList], *, body: Any = None) -> None: def __init__(self, errors: Sequence[ErrorList], *, body: Any = None) -> None:
self.body = body self.body = body
if PYDANTIC_1:
super().__init__(errors, RequestErrorModel) super().__init__(errors, RequestErrorModel)
else:
super().__init__(errors, Request) # type: ignore # pragma: nocover
class WebSocketRequestValidationError(ValidationError): class WebSocketRequestValidationError(ValidationError):
def __init__(self, errors: Sequence[ErrorList]) -> None: def __init__(self, errors: Sequence[ErrorList]) -> None:
if PYDANTIC_1:
super().__init__(errors, WebSocketErrorModel) super().__init__(errors, WebSocketErrorModel)
else:
super().__init__(errors, WebSocket) # type: ignore # pragma: nocover

13
fastapi/openapi/models.py

@ -2,25 +2,14 @@ from enum import Enum
from typing import Any, Callable, Dict, Iterable, List, Optional, Union from typing import Any, Callable, Dict, Iterable, List, Optional, Union
from fastapi.logger import logger from fastapi.logger import logger
from pydantic import BaseModel from pydantic import AnyUrl, BaseModel, Field
try:
from pydantic import AnyUrl, Field
except ImportError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic import Schema as Field # type: ignore
from pydantic import UrlStr as AnyUrl # type: ignore
try: try:
import email_validator import email_validator
assert email_validator # make autoflake ignore the unused import assert email_validator # make autoflake ignore the unused import
try:
from pydantic import EmailStr from pydantic import EmailStr
except ImportError: # pragma: no cover except ImportError: # pragma: no cover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic.types import EmailStr # type: ignore
except ImportError: # pragma: no cover
class EmailStr(str): # type: ignore class EmailStr(str): # type: ignore
@classmethod @classmethod

12
fastapi/openapi/utils.py

@ -16,10 +16,10 @@ from fastapi.params import Body, Param
from fastapi.utils import ( from fastapi.utils import (
deep_dict_update, deep_dict_update,
generate_operation_id_for_path, generate_operation_id_for_path,
get_field_info,
get_model_definitions, get_model_definitions,
) )
from pydantic import BaseModel from pydantic import BaseModel
from pydantic.fields import ModelField
from pydantic.schema import ( from pydantic.schema import (
field_schema, field_schema,
get_flat_models_from_fields, get_flat_models_from_fields,
@ -30,12 +30,6 @@ from starlette.responses import JSONResponse
from starlette.routing import BaseRoute from starlette.routing import BaseRoute
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
try:
from pydantic.fields import ModelField
except ImportError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic.fields import Field as ModelField # type: ignore
validation_error_definition = { validation_error_definition = {
"title": "ValidationError", "title": "ValidationError",
"type": "object", "type": "object",
@ -91,7 +85,7 @@ def get_openapi_operation_parameters(
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
parameters = [] parameters = []
for param in all_route_params: for param in all_route_params:
field_info = get_field_info(param) field_info = param.field_info
field_info = cast(Param, field_info) field_info = cast(Param, field_info)
# ignore mypy error until enum schemas are released # ignore mypy error until enum schemas are released
parameter = { parameter = {
@ -122,7 +116,7 @@ def get_openapi_operation_request_body(
body_schema, _, _ = field_schema( body_schema, _, _ = field_schema(
body_field, model_name_map=model_name_map, ref_prefix=REF_PREFIX # type: ignore body_field, model_name_map=model_name_map, ref_prefix=REF_PREFIX # type: ignore
) )
field_info = cast(Body, get_field_info(body_field)) field_info = cast(Body, body_field.field_info)
request_media_type = field_info.media_type request_media_type = field_info.media_type
required = body_field.required required = body_field.required
request_body_oai: Dict[str, Any] = {} request_body_oai: Dict[str, Any] = {}

4
fastapi/params.py

@ -1,11 +1,7 @@
from enum import Enum from enum import Enum
from typing import Any, Callable, Optional, Sequence from typing import Any, Callable, Optional, Sequence
try:
from pydantic.fields import FieldInfo from pydantic.fields import FieldInfo
except ImportError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic import Schema as FieldInfo # type: ignore
class ParamTypes(Enum): class ParamTypes(Enum):

3
fastapi/requests.py

@ -1 +1,2 @@
from starlette.requests import HTTPConnection, Request # noqa from starlette.requests import HTTPConnection as HTTPConnection # noqa: F401
from starlette.requests import Request as Request # noqa: F401

115
fastapi/routing.py

@ -16,15 +16,13 @@ from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
from fastapi.openapi.constants import STATUS_CODES_WITH_NO_BODY from fastapi.openapi.constants import STATUS_CODES_WITH_NO_BODY
from fastapi.utils import ( from fastapi.utils import (
PYDANTIC_1,
create_cloned_field, create_cloned_field,
create_response_field, create_response_field,
generate_operation_id_for_path, generate_operation_id_for_path,
get_field_info,
warning_response_model_skip_defaults_deprecated,
) )
from pydantic import BaseModel from pydantic import BaseModel
from pydantic.error_wrappers import ErrorWrapper, ValidationError from pydantic.error_wrappers import ErrorWrapper, ValidationError
from pydantic.fields import ModelField
from starlette import routing from starlette import routing
from starlette.concurrency import run_in_threadpool from starlette.concurrency import run_in_threadpool
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
@ -41,12 +39,6 @@ from starlette.status import WS_1008_POLICY_VIOLATION
from starlette.types import ASGIApp from starlette.types import ASGIApp
from starlette.websockets import WebSocket from starlette.websockets import WebSocket
try:
from pydantic.fields import ModelField
except ImportError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic.fields import Field as ModelField # type: ignore
def _prepare_response_content( def _prepare_response_content(
res: Any, res: Any,
@ -56,17 +48,12 @@ def _prepare_response_content(
exclude_none: bool = False, exclude_none: bool = False,
) -> Any: ) -> Any:
if isinstance(res, BaseModel): if isinstance(res, BaseModel):
if PYDANTIC_1:
return res.dict( return res.dict(
by_alias=True, by_alias=True,
exclude_unset=exclude_unset, exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults, exclude_defaults=exclude_defaults,
exclude_none=exclude_none, exclude_none=exclude_none,
) )
else:
return res.dict(
by_alias=True, skip_defaults=exclude_unset,
) # pragma: nocover
elif isinstance(res, list): elif isinstance(res, list):
return [ return [
_prepare_response_content( _prepare_response_content(
@ -95,7 +82,7 @@ async def serialize_response(
field: Optional[ModelField] = None, field: Optional[ModelField] = None,
response_content: Any, response_content: Any,
include: Optional[Union[SetIntStr, DictIntStrAny]] = None, include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
exclude: Union[SetIntStr, DictIntStrAny] = set(), exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
by_alias: bool = True, by_alias: bool = True,
exclude_unset: bool = False, exclude_unset: bool = False,
exclude_defaults: bool = False, exclude_defaults: bool = False,
@ -155,7 +142,7 @@ def get_request_handler(
response_class: Type[Response] = JSONResponse, response_class: Type[Response] = JSONResponse,
response_field: Optional[ModelField] = None, response_field: Optional[ModelField] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
@ -164,7 +151,7 @@ def get_request_handler(
) -> Callable: ) -> Callable:
assert dependant.call is not None, "dependant.call must be a function" assert dependant.call is not None, "dependant.call must be a function"
is_coroutine = asyncio.iscoroutinefunction(dependant.call) is_coroutine = asyncio.iscoroutinefunction(dependant.call)
is_body_form = body_field and isinstance(get_field_info(body_field), params.Form) is_body_form = body_field and isinstance(body_field.field_info, params.Form)
async def app(request: Request) -> Response: async def app(request: Request) -> Response:
try: try:
@ -284,7 +271,7 @@ class APIRoute(routing.Route):
methods: Optional[Union[Set[str], List[str]]] = None, methods: Optional[Union[Set[str], List[str]]] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
@ -437,9 +424,8 @@ class APIRouter(routing.Router):
methods: Optional[Union[Set[str], List[str]]] = None, methods: Optional[Union[Set[str], List[str]]] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -449,8 +435,6 @@ class APIRouter(routing.Router):
route_class_override: Optional[Type[APIRoute]] = None, route_class_override: Optional[Type[APIRoute]] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> None: ) -> None:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
route_class = route_class_override or self.route_class route_class = route_class_override or self.route_class
route = route_class( route = route_class(
path, path,
@ -469,9 +453,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -498,9 +480,8 @@ class APIRouter(routing.Router):
methods: Optional[List[str]] = None, methods: Optional[List[str]] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -509,9 +490,6 @@ class APIRouter(routing.Router):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
def decorator(func: Callable) -> Callable: def decorator(func: Callable) -> Callable:
self.add_api_route( self.add_api_route(
path, path,
@ -530,9 +508,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -653,9 +629,8 @@ class APIRouter(routing.Router):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -664,8 +639,6 @@ class APIRouter(routing.Router):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.api_route( return self.api_route(
path=path, path=path,
response_model=response_model, response_model=response_model,
@ -682,9 +655,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -708,9 +679,8 @@ class APIRouter(routing.Router):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -719,8 +689,6 @@ class APIRouter(routing.Router):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.api_route( return self.api_route(
path=path, path=path,
response_model=response_model, response_model=response_model,
@ -737,9 +705,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -763,9 +729,8 @@ class APIRouter(routing.Router):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -774,8 +739,6 @@ class APIRouter(routing.Router):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.api_route( return self.api_route(
path=path, path=path,
response_model=response_model, response_model=response_model,
@ -792,9 +755,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -818,9 +779,8 @@ class APIRouter(routing.Router):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -829,8 +789,6 @@ class APIRouter(routing.Router):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.api_route( return self.api_route(
path=path, path=path,
response_model=response_model, response_model=response_model,
@ -847,9 +805,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -873,9 +829,8 @@ class APIRouter(routing.Router):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -884,8 +839,6 @@ class APIRouter(routing.Router):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.api_route( return self.api_route(
path=path, path=path,
response_model=response_model, response_model=response_model,
@ -902,9 +855,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -928,9 +879,8 @@ class APIRouter(routing.Router):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -939,8 +889,6 @@ class APIRouter(routing.Router):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.api_route( return self.api_route(
path=path, path=path,
response_model=response_model, response_model=response_model,
@ -957,9 +905,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -983,9 +929,8 @@ class APIRouter(routing.Router):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -994,8 +939,6 @@ class APIRouter(routing.Router):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.api_route( return self.api_route(
path=path, path=path,
response_model=response_model, response_model=response_model,
@ -1012,9 +955,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,
@ -1038,9 +979,8 @@ class APIRouter(routing.Router):
deprecated: Optional[bool] = None, deprecated: Optional[bool] = None,
operation_id: Optional[str] = None, operation_id: Optional[str] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
response_model_by_alias: bool = True, response_model_by_alias: bool = True,
response_model_skip_defaults: Optional[bool] = None,
response_model_exclude_unset: bool = False, response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False, response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False, response_model_exclude_none: bool = False,
@ -1049,8 +989,7 @@ class APIRouter(routing.Router):
name: Optional[str] = None, name: Optional[str] = None,
callbacks: Optional[List[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None,
) -> Callable: ) -> Callable:
if response_model_skip_defaults is not None:
warning_response_model_skip_defaults_deprecated() # pragma: nocover
return self.api_route( return self.api_route(
path=path, path=path,
response_model=response_model, response_model=response_model,
@ -1067,9 +1006,7 @@ class APIRouter(routing.Router):
response_model_include=response_model_include, response_model_include=response_model_include,
response_model_exclude=response_model_exclude, response_model_exclude=response_model_exclude,
response_model_by_alias=response_model_by_alias, response_model_by_alias=response_model_by_alias,
response_model_exclude_unset=bool( response_model_exclude_unset=response_model_exclude_unset,
response_model_exclude_unset or response_model_skip_defaults
),
response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_defaults=response_model_exclude_defaults,
response_model_exclude_none=response_model_exclude_none, response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema, include_in_schema=include_in_schema,

52
fastapi/utils.py

@ -5,49 +5,13 @@ from enum import Enum
from typing import Any, Dict, Optional, Set, Type, Union, cast from typing import Any, Dict, Optional, Set, Type, Union, cast
import fastapi import fastapi
from fastapi.logger import logger
from fastapi.openapi.constants import REF_PREFIX from fastapi.openapi.constants import REF_PREFIX
from pydantic import BaseConfig, BaseModel, create_model from pydantic import BaseConfig, BaseModel, create_model
from pydantic.class_validators import Validator from pydantic.class_validators import Validator
from pydantic.fields import FieldInfo, ModelField, UndefinedType
from pydantic.schema import model_process_schema from pydantic.schema import model_process_schema
from pydantic.utils import lenient_issubclass from pydantic.utils import lenient_issubclass
try:
from pydantic.fields import FieldInfo, ModelField, UndefinedType
PYDANTIC_1 = True
except ImportError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic import Schema as FieldInfo # type: ignore
from pydantic.fields import Field as ModelField # type: ignore
class UndefinedType: # type: ignore
def __repr__(self) -> str:
return "PydanticUndefined"
logger.warning(
"Pydantic versions < 1.0.0 are deprecated in FastAPI and support will be "
"removed soon."
)
PYDANTIC_1 = False
# TODO: remove when removing support for Pydantic < 1.0.0
def get_field_info(field: ModelField) -> FieldInfo:
if PYDANTIC_1:
return field.field_info # type: ignore
else:
return field.schema # type: ignore # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
def warning_response_model_skip_defaults_deprecated() -> None:
logger.warning( # pragma: nocover
"response_model_skip_defaults has been deprecated in favor of "
"response_model_exclude_unset to keep in line with Pydantic v1, support for "
"it will be removed soon."
)
def get_model_definitions( def get_model_definitions(
*, *,
@ -98,10 +62,7 @@ def create_response_field(
) )
try: try:
if PYDANTIC_1:
return response_field(field_info=field_info) return response_field(field_info=field_info)
else: # pragma: nocover
return response_field(schema=field_info)
except RuntimeError: except RuntimeError:
raise fastapi.exceptions.FastAPIError( raise fastapi.exceptions.FastAPIError(
f"Invalid args for response field! Hint: check that {type_} is a valid pydantic field type" f"Invalid args for response field! Hint: check that {type_} is a valid pydantic field type"
@ -137,10 +98,7 @@ def create_cloned_field(
new_field.default = field.default new_field.default = field.default
new_field.required = field.required new_field.required = field.required
new_field.model_config = field.model_config new_field.model_config = field.model_config
if PYDANTIC_1:
new_field.field_info = field.field_info new_field.field_info = field.field_info
else: # pragma: nocover
new_field.schema = field.schema # type: ignore
new_field.allow_none = field.allow_none new_field.allow_none = field.allow_none
new_field.validate_always = field.validate_always new_field.validate_always = field.validate_always
if field.sub_fields: if field.sub_fields:
@ -153,19 +111,11 @@ def create_cloned_field(
field.key_field, cloned_types=cloned_types field.key_field, cloned_types=cloned_types
) )
new_field.validators = field.validators new_field.validators = field.validators
if PYDANTIC_1:
new_field.pre_validators = field.pre_validators new_field.pre_validators = field.pre_validators
new_field.post_validators = field.post_validators new_field.post_validators = field.post_validators
else: # pragma: nocover
new_field.whole_pre_validators = field.whole_pre_validators # type: ignore
new_field.whole_post_validators = field.whole_post_validators # type: ignore
new_field.parse_json = field.parse_json new_field.parse_json = field.parse_json
new_field.shape = field.shape new_field.shape = field.shape
try:
new_field.populate_validators() new_field.populate_validators()
except AttributeError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
new_field._populate_validators() # type: ignore
return new_field return new_field

2
pyproject.toml

@ -33,7 +33,7 @@ classifiers = [
] ]
requires = [ requires = [
"starlette ==0.13.6", "starlette ==0.13.6",
"pydantic >=0.32.2,<2.0.0" "pydantic >=1.0.0,<2.0.0"
] ]
description-file = "README.md" description-file = "README.md"
requires-python = ">=3.6" requires-python = ">=3.6"

8
tests/test_jsonable_encoder.py

@ -5,13 +5,7 @@ from typing import Optional
import pytest import pytest
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel, ValidationError, create_model from pydantic import BaseModel, Field, ValidationError, create_model
try:
from pydantic import Field
except ImportError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic import Schema as Field
class Person: class Person:

9
tests/test_tutorial/test_body_fields/test_tutorial001.py

@ -3,15 +3,6 @@ from fastapi.testclient import TestClient
from docs_src.body_fields.tutorial001 import app from docs_src.body_fields.tutorial001 import app
# TODO: remove when removing support for Pydantic < 1.0.0
try:
from pydantic import Field # noqa
except ImportError: # pragma: nocover
import pydantic
pydantic.Field = pydantic.Schema
client = TestClient(app) client = TestClient(app)

Loading…
Cancel
Save