diff --git a/Pipfile b/Pipfile index 07e2a6a7c..4240e5dec 100644 --- a/Pipfile +++ b/Pipfile @@ -26,7 +26,7 @@ uvicorn = "*" [packages] starlette = "==0.12.7" -pydantic = "==0.30.0" +pydantic = "==0.32.2" databases = {extras = ["sqlite"],version = "*"} hypercorn = "*" diff --git a/fastapi/applications.py b/fastapi/applications.py index e5dce88d9..783680141 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -1,6 +1,7 @@ -from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Type, Union +from typing import Any, Callable, Dict, List, Optional, Sequence, Type, Union from fastapi import routing +from fastapi.encoders import DictIntStrAny, SetIntStr from fastapi.exception_handlers import ( http_exception_handler, request_validation_exception_handler, @@ -138,8 +139,8 @@ class FastAPI(Starlette): deprecated: bool = None, methods: List[str] = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -184,8 +185,8 @@ class FastAPI(Starlette): deprecated: bool = None, methods: List[str] = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -262,8 +263,8 @@ class FastAPI(Starlette): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -305,8 +306,8 @@ class FastAPI(Starlette): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -348,8 +349,8 @@ class FastAPI(Starlette): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -391,8 +392,8 @@ class FastAPI(Starlette): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -434,8 +435,8 @@ class FastAPI(Starlette): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -477,8 +478,8 @@ class FastAPI(Starlette): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -520,8 +521,8 @@ class FastAPI(Starlette): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -563,8 +564,8 @@ class FastAPI(Starlette): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, diff --git a/fastapi/encoders.py b/fastapi/encoders.py index f5ff57f61..0f4fd8346 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -1,15 +1,18 @@ from enum import Enum from types import GeneratorType -from typing import Any, List, Set +from typing import Any, Dict, List, Set, Union from pydantic import BaseModel from pydantic.json import ENCODERS_BY_TYPE +SetIntStr = Set[Union[int, str]] +DictIntStrAny = Dict[Union[int, str], Any] + def jsonable_encoder( obj: Any, - include: Set[str] = None, - exclude: Set[str] = set(), + include: Union[SetIntStr, DictIntStrAny] = None, + exclude: Union[SetIntStr, DictIntStrAny] = set(), by_alias: bool = True, skip_defaults: bool = False, include_none: bool = True, diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py index cbd82b44a..a85dfa82c 100644 --- a/fastapi/exceptions.py +++ b/fastapi/exceptions.py @@ -1,7 +1,10 @@ -from typing import Any +from typing import Any, Sequence from pydantic import ValidationError +from pydantic.error_wrappers import ErrorList +from requests import Request from starlette.exceptions import HTTPException as StarletteHTTPException +from starlette.websockets import WebSocket class HTTPException(StarletteHTTPException): @@ -13,8 +16,10 @@ class HTTPException(StarletteHTTPException): class RequestValidationError(ValidationError): - pass + def __init__(self, errors: Sequence[ErrorList]) -> None: + super().__init__(errors, Request) class WebSocketRequestValidationError(ValidationError): - pass + def __init__(self, errors: Sequence[ErrorList]) -> None: + super().__init__(errors, WebSocket) diff --git a/fastapi/routing.py b/fastapi/routing.py index 0e8ff9739..f7cec9e45 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -11,7 +11,7 @@ from fastapi.dependencies.utils import ( get_parameterless_sub_dependant, solve_dependencies, ) -from fastapi.encoders import jsonable_encoder +from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError from fastapi.utils import create_cloned_field, generate_operation_id_for_path from pydantic import BaseConfig, BaseModel, Schema @@ -38,8 +38,8 @@ def serialize_response( *, field: Field = None, response: Response, - include: Set[str] = None, - exclude: Set[str] = set(), + include: Union[SetIntStr, DictIntStrAny] = None, + exclude: Union[SetIntStr, DictIntStrAny] = set(), by_alias: bool = True, skip_defaults: bool = False, ) -> Any: @@ -53,7 +53,7 @@ def serialize_response( elif isinstance(errors_, list): errors.extend(errors_) if errors: - raise ValidationError(errors) + raise ValidationError(errors, field.type_) return jsonable_encoder( value, include=include, @@ -71,8 +71,8 @@ def get_app( status_code: int = 200, response_class: Type[Response] = JSONResponse, response_field: Field = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, dependency_overrides_provider: Any = None, @@ -195,8 +195,8 @@ class APIRoute(routing.Route): name: str = None, methods: Optional[Union[Set[str], List[str]]] = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -341,8 +341,8 @@ class APIRouter(routing.Router): deprecated: bool = None, methods: Optional[Union[Set[str], List[str]]] = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -389,8 +389,8 @@ class APIRouter(routing.Router): deprecated: bool = None, methods: List[str] = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -518,8 +518,8 @@ class APIRouter(routing.Router): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -563,8 +563,8 @@ class APIRouter(routing.Router): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -607,8 +607,8 @@ class APIRouter(routing.Router): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -651,8 +651,8 @@ class APIRouter(routing.Router): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -695,8 +695,8 @@ class APIRouter(routing.Router): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -739,8 +739,8 @@ class APIRouter(routing.Router): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -783,8 +783,8 @@ class APIRouter(routing.Router): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, @@ -827,8 +827,8 @@ class APIRouter(routing.Router): responses: Dict[Union[int, str], Dict[str, Any]] = None, deprecated: bool = None, operation_id: str = None, - response_model_include: Set[str] = None, - response_model_exclude: Set[str] = set(), + response_model_include: Union[SetIntStr, DictIntStrAny] = None, + response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(), response_model_by_alias: bool = True, response_model_skip_defaults: bool = False, include_in_schema: bool = True, diff --git a/pyproject.toml b/pyproject.toml index 1b239f5f6..0a202e1a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ classifiers = [ ] requires = [ "starlette >=0.11.1,<=0.12.7", - "pydantic >=0.30,<=0.30.0" + "pydantic >=0.32.2,<=0.32.2" ] description-file = "README.md" requires-python = ">=3.6" diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial004.py b/tests/test_tutorial/test_handling_errors/test_tutorial004.py index 09ccd463c..38a9c20b2 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial004.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial004.py @@ -81,7 +81,7 @@ def test_get_validation_error(): response = client.get("/items/foo") assert response.status_code == 400 validation_error_str_lines = [ - b"1 validation error", + b"1 validation error for Request", b"path -> item_id", b" value is not a valid integer (type=type_error.integer)", ] diff --git a/tests/test_tutorial/test_path_params/test_tutorial005.py b/tests/test_tutorial/test_path_params/test_tutorial005.py index 89f5863c5..4ff7e5e29 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial005.py +++ b/tests/test_tutorial/test_path_params/test_tutorial005.py @@ -106,8 +106,9 @@ def test_openapi(): { "detail": [ { + "ctx": {"enum_values": ["alexnet", "resnet", "lenet"]}, "loc": ["path", "model_name"], - "msg": "value is not a valid enumeration member", + "msg": "value is not a valid enumeration member; permitted: 'alexnet', 'resnet', 'lenet'", "type": "type_error.enum", } ]