Browse Source

Update now that pydantic has been released

pull/11634/head
Alex Couper 12 months ago
parent
commit
25716e308d
  1. 64
      fastapi/_compat.py
  2. 37
      fastapi/applications.py
  3. 52
      fastapi/routing.py
  4. 9
      tests/test_serialize_response_model.py

64
fastapi/_compat.py

@ -18,13 +18,14 @@ from typing import (
Union,
)
from fastapi.exceptions import RequestErrorModel
from fastapi.types import IncEx, ModelNameMap, UnionType
from pydantic import BaseModel, create_model
from pydantic.version import VERSION as P_VERSION
from starlette.datastructures import UploadFile
from typing_extensions import Annotated, Literal, get_args, get_origin
from fastapi.exceptions import RequestErrorModel
from fastapi.types import IncEx, ModelNameMap, UnionType
# Reassign variable to make it reexported for mypy
PYDANTIC_VERSION = P_VERSION
PYDANTIC_V2 = PYDANTIC_VERSION.startswith("2.")
@ -50,8 +51,8 @@ if PYDANTIC_V2:
from pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError
from pydantic import TypeAdapter
from pydantic import ValidationError as ValidationError
from pydantic._internal._schema_generation_shared import ( # type: ignore[attr-defined]
GetJsonSchemaHandler as GetJsonSchemaHandler,
from pydantic._internal._schema_generation_shared import (
GetJsonSchemaHandler as GetJsonSchemaHandler, # type: ignore[attr-defined]
)
from pydantic._internal._typing_extra import eval_type_lenient
from pydantic._internal._utils import lenient_issubclass as lenient_issubclass
@ -67,8 +68,8 @@ if PYDANTIC_V2:
with_info_plain_validator_function as with_info_plain_validator_function,
)
except ImportError: # pragma: no cover
from pydantic_core.core_schema import (
general_plain_validator_function as with_info_plain_validator_function, # noqa: F401
from pydantic_core.core_schema import ( # noqa: F401
general_plain_validator_function as with_info_plain_validator_function,
)
Required = PydanticUndefined
@ -149,8 +150,8 @@ if PYDANTIC_V2:
# What calls this code passes a value that already called
# self._type_adapter.validate_python(value)
#
# context argument was introduced in pydantic 2.7.3
kwargs = {"context": context} if PYDANTIC_VERSION >= "2.7.3" else {}
# context argument was introduced in pydantic 2.8
kwargs = {"context": context} if PYDANTIC_VERSION >= "2.8" else {}
return self._type_adapter.dump_python(
value,
@ -287,17 +288,16 @@ if PYDANTIC_V2:
return BodyModel
else:
from fastapi.openapi.constants import REF_PREFIX as REF_PREFIX
from pydantic import AnyUrl as Url # noqa: F401
from pydantic import ( # type: ignore[assignment]
BaseConfig as BaseConfig, # noqa: F401
from pydantic import ( # type: ignore[assignment]; noqa: F401
BaseConfig as BaseConfig,
)
from pydantic import ValidationError as ValidationError # noqa: F401
from pydantic.class_validators import ( # type: ignore[no-redef]
Validator as Validator, # noqa: F401
from pydantic.class_validators import ( # type: ignore[no-redef]; noqa: F401
Validator as Validator,
)
from pydantic.error_wrappers import ( # type: ignore[no-redef]
ErrorWrapper as ErrorWrapper, # noqa: F401
from pydantic.error_wrappers import ( # type: ignore[no-redef]; noqa: F401
ErrorWrapper as ErrorWrapper,
)
from pydantic.errors import MissingError
from pydantic.fields import ( # type: ignore[attr-defined]
@ -310,34 +310,36 @@ else:
SHAPE_TUPLE_ELLIPSIS,
)
from pydantic.fields import FieldInfo as FieldInfo
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
ModelField as ModelField, # noqa: F401
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]; noqa: F401
ModelField as ModelField,
)
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
Required as Required, # noqa: F401
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]; noqa: F401
Required as Required,
)
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
Undefined as Undefined,
from pydantic.fields import (
Undefined as Undefined, # type: ignore[no-redef,attr-defined]
)
from pydantic.fields import ( # type: ignore[no-redef, attr-defined]
UndefinedType as UndefinedType, # noqa: F401
from pydantic.fields import ( # type: ignore[no-redef, attr-defined]; noqa: F401
UndefinedType as UndefinedType,
)
from pydantic.schema import field_schema
from pydantic.schema import ( # type: ignore[no-redef] # noqa: F401
get_annotation_from_field_info as get_annotation_from_field_info,
)
from pydantic.schema import (
field_schema,
get_flat_models_from_fields,
get_model_name_map,
model_process_schema,
)
from pydantic.schema import ( # type: ignore[no-redef] # noqa: F401
get_annotation_from_field_info as get_annotation_from_field_info,
from pydantic.typing import ( # type: ignore[no-redef]; noqa: F401
evaluate_forwardref as evaluate_forwardref,
)
from pydantic.typing import ( # type: ignore[no-redef]
evaluate_forwardref as evaluate_forwardref, # noqa: F401
)
from pydantic.utils import ( # type: ignore[no-redef]
lenient_issubclass as lenient_issubclass, # noqa: F401
from pydantic.utils import ( # type: ignore[no-redef]; noqa: F401
lenient_issubclass as lenient_issubclass,
)
from fastapi.openapi.constants import REF_PREFIX as REF_PREFIX
GetJsonSchemaHandler = Any # type: ignore[assignment,misc]
JsonSchemaValue = Dict[str, Any] # type: ignore[misc]
CoreSchema = Any # type: ignore[assignment,misc]

37
fastapi/applications.py

@ -13,6 +13,17 @@ from typing import (
Union,
)
from starlette.applications import Starlette
from starlette.datastructures import State
from starlette.exceptions import HTTPException
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import HTMLResponse, JSONResponse, Response
from starlette.routing import BaseRoute
from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
from typing_extensions import Annotated, Doc, deprecated
from fastapi import routing
from fastapi.datastructures import Default, DefaultPlaceholder
from fastapi.exception_handlers import (
@ -31,16 +42,6 @@ from fastapi.openapi.utils import get_openapi
from fastapi.params import Depends
from fastapi.types import DecoratedCallable, IncEx
from fastapi.utils import generate_unique_id
from starlette.applications import Starlette
from starlette.datastructures import State
from starlette.exceptions import HTTPException
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import HTMLResponse, JSONResponse, Response
from starlette.routing import BaseRoute
from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
from typing_extensions import Annotated, Doc, deprecated
AppType = TypeVar("AppType", bound="FastAPI")
@ -1723,7 +1724,7 @@ class FastAPI(Starlette):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -2112,7 +2113,7 @@ class FastAPI(Starlette):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -2506,7 +2507,7 @@ class FastAPI(Starlette):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -2900,7 +2901,7 @@ class FastAPI(Starlette):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -3289,7 +3290,7 @@ class FastAPI(Starlette):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -3678,7 +3679,7 @@ class FastAPI(Starlette):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -4067,7 +4068,7 @@ class FastAPI(Starlette):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -4461,7 +4462,7 @@ class FastAPI(Starlette):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)

52
fastapi/routing.py

@ -19,6 +19,24 @@ from typing import (
Union,
)
from pydantic import BaseModel
from starlette import routing
from starlette.concurrency import run_in_threadpool
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
from starlette.routing import BaseRoute, Match
from starlette.routing import Mount as Mount # noqa
from starlette.routing import (
compile_path,
get_name,
request_response,
websocket_session,
)
from starlette.types import ASGIApp, Lifespan, Scope
from starlette.websockets import WebSocket
from typing_extensions import Annotated, Doc, deprecated
from fastapi import params
from fastapi._compat import (
ModelField,
@ -52,24 +70,6 @@ from fastapi.utils import (
get_value_or_default,
is_body_allowed_for_status_code,
)
from pydantic import BaseModel
from starlette import routing
from starlette.concurrency import run_in_threadpool
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
from starlette.routing import (
BaseRoute,
Match,
compile_path,
get_name,
request_response,
websocket_session,
)
from starlette.routing import Mount as Mount # noqa
from starlette.types import ASGIApp, Lifespan, Scope
from starlette.websockets import WebSocket
from typing_extensions import Annotated, Doc, deprecated
def _prepare_response_content(
@ -1583,7 +1583,7 @@ class APIRouter(routing.Router):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -1976,7 +1976,7 @@ class APIRouter(routing.Router):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -2374,7 +2374,7 @@ class APIRouter(routing.Router):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -2772,7 +2772,7 @@ class APIRouter(routing.Router):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -3165,7 +3165,7 @@ class APIRouter(routing.Router):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -3558,7 +3558,7 @@ class APIRouter(routing.Router):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -3956,7 +3956,7 @@ class APIRouter(routing.Router):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)
@ -4354,7 +4354,7 @@ class APIRouter(routing.Router):
This will be passed in as serialization context to the response model.
Note: This feature is a noop on pydantic < 2.7.2
Note: This feature is a noop on pydantic < 2.8
Read more about serialization context in the
[Pydantic documentation](https://docs.pydantic.dev/latest/concepts/serialization/#serialization-context)

9
tests/test_serialize_response_model.py

@ -1,11 +1,12 @@
from typing import Dict, List, Optional
import pytest
from fastapi import FastAPI
from fastapi._compat import PYDANTIC_V2, PYDANTIC_VERSION
from pydantic import BaseModel, Field
from starlette.testclient import TestClient
from fastapi import FastAPI
from fastapi._compat import PYDANTIC_V2, PYDANTIC_VERSION
app = FastAPI()
@ -188,7 +189,7 @@ if PYDANTIC_V2:
client_v2 = TestClient(app_v2)
@pytest.mark.skipif(PYDANTIC_VERSION < "2.7.3", reason="requires Pydantic v2.7.3+")
@pytest.mark.skipif(PYDANTIC_VERSION < "2.8", reason="requires Pydantic v2.8+")
def test_validdict_with_context__pydantic_supported():
response = client_v2.get("/items/validdict-with-context")
response.raise_for_status()
@ -202,7 +203,7 @@ if PYDANTIC_V2:
assert response.json() == expected_response
@pytest.mark.skipif(
PYDANTIC_VERSION >= "2.7.3",
PYDANTIC_VERSION >= "2.8",
reason="Pydantic supports the feature from this point on",
)
def test_validdict_with_context__pre_pydantic_support():

Loading…
Cancel
Save