From 577c5a84db307a13668f328857f8ea593d6048da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 5 Jan 2019 17:30:27 +0400 Subject: [PATCH] :bug: Fix constrained bytes, from defaults in Pydantic #2 --- fastapi/dependencies/utils.py | 16 +++++++++------- fastapi/routing.py | 5 +++-- fastapi/utils.py | 7 ++++++- .../test_request_files/test_tutorial001.py | 12 ++++++++++++ 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 7dddae3c2..2dce12bf1 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -9,8 +9,8 @@ from uuid import UUID from fastapi import params from fastapi.dependencies.models import Dependant, SecurityRequirement from fastapi.security.base import SecurityBase -from fastapi.utils import get_path_param_names -from pydantic import BaseConfig, Schema, create_model +from fastapi.utils import UnconstrainedConfig, get_path_param_names +from pydantic import Schema, create_model from pydantic.error_wrappers import ErrorWrapper from pydantic.errors import MissingError from pydantic.fields import Field, Required, Shape @@ -163,7 +163,7 @@ def add_param_to_fields( default=None if required else default_value, alias=alias, required=required, - model_config=BaseConfig(), + model_config=UnconstrainedConfig, class_validators=[], schema=schema, ) @@ -197,7 +197,7 @@ def add_param_to_body_fields(*, param: inspect.Parameter, dependant: Dependant) default=None if required else default_value, alias=schema.alias or param.name, required=required, - model_config=BaseConfig, + model_config=UnconstrainedConfig, class_validators=[], schema=schema, ) @@ -281,7 +281,7 @@ def request_params_to_args( ErrorWrapper( MissingError(), loc=(schema.in_.value, field.alias), - config=BaseConfig, + config=UnconstrainedConfig, ) ) else: @@ -315,7 +315,9 @@ async def request_body_to_args( if field.required: errors.append( ErrorWrapper( - MissingError(), loc=("body", field.alias), config=BaseConfig + MissingError(), + loc=("body", field.alias), + config=UnconstrainedConfig, ) ) else: @@ -356,7 +358,7 @@ def get_body_field(*, dependant: Dependant, name: str) -> Field: type_=BodyModel, default=None, required=required, - model_config=BaseConfig, + model_config=UnconstrainedConfig, class_validators=[], alias="body", schema=BodySchema(None), diff --git a/fastapi/routing.py b/fastapi/routing.py index 254f8f999..0c9334ba5 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -7,7 +7,8 @@ from fastapi import params from fastapi.dependencies.models import Dependant from fastapi.dependencies.utils import get_body_field, get_dependant, solve_dependencies from fastapi.encoders import jsonable_encoder -from pydantic import BaseConfig, BaseModel, Schema +from fastapi.utils import UnconstrainedConfig +from pydantic import BaseModel, Schema from pydantic.error_wrappers import ErrorWrapper, ValidationError from pydantic.fields import Field from pydantic.utils import lenient_issubclass @@ -130,7 +131,7 @@ class APIRoute(routing.Route): class_validators=[], default=None, required=False, - model_config=BaseConfig(), + model_config=UnconstrainedConfig, schema=Schema(None), ) else: diff --git a/fastapi/utils.py b/fastapi/utils.py index f3b4df82e..395ec9f5b 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -3,12 +3,17 @@ from typing import Any, Dict, List, Sequence, Set, Type from fastapi import routing from fastapi.openapi.constants import REF_PREFIX -from pydantic import BaseModel +from pydantic import BaseConfig, BaseModel from pydantic.fields import Field from pydantic.schema import get_flat_models_from_fields, model_process_schema from starlette.routing import BaseRoute +class UnconstrainedConfig(BaseConfig): + min_anystr_length = None + max_anystr_length = None + + def get_flat_models_from_routes( routes: Sequence[Type[BaseRoute]] ) -> Set[Type[BaseModel]]: diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py index d92d5a749..84de46e0a 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001.py @@ -119,3 +119,15 @@ def test_post_file(tmpdir): response = client.post("/files/", files={"file": open(path, "rb")}) assert response.status_code == 200 assert response.json() == {"file_size": 14} + + +def test_post_large_file(tmpdir): + default_pydantic_max_size = 2 ** 16 + path = os.path.join(tmpdir, "test.txt") + with open(path, "wb") as file: + file.write(b"x" * (default_pydantic_max_size + 1)) + + client = TestClient(app) + response = client.post("/files/", files={"file": open(path, "rb")}) + assert response.status_code == 200 + assert response.json() == {"file_size": default_pydantic_max_size + 1}