diff --git a/fastapi/_compat/v2.py b/fastapi/_compat/v2.py index 54a9cfacde..c913874612 100644 --- a/fastapi/_compat/v2.py +++ b/fastapi/_compat/v2.py @@ -570,6 +570,7 @@ def get_flat_models_from_fields( get_flat_models_from_field(field, known_models=known_models) return known_models + def _regenerate_error_with_loc( *, errors: Sequence[Any], loc_prefix: tuple[Union[str, int], ...] ) -> list[dict[str, Any]]: @@ -579,6 +580,7 @@ def _regenerate_error_with_loc( return updated_loc_errors + if shared.PYDANTIC_VERSION_MINOR_TUPLE >= (2, 6): # Omit by default for scalar mapping and scalar sequence mapping annotations # added in Pydantic v2.6 https://github.com/pydantic/pydantic/releases/tag/v2.6.0 diff --git a/tests/test_request_params/test_query/test_free_form.py b/tests/test_request_params/test_query/test_free_form.py index 36a10b1393..d2f28bd952 100644 --- a/tests/test_request_params/test_query/test_free_form.py +++ b/tests/test_request_params/test_query/test_free_form.py @@ -75,11 +75,15 @@ def test_required_dict_str(path: str): assert response.status_code == 200 assert response.json() == {"p": {"foo": "bar", "baz": "qux"}} + # ===================================================================================== # With union types + @app.get("/required-dict-union") -async def read_required_dict_union(p: Annotated[dict[str, str] | dict[str, int], Query()]): +async def read_required_dict_union( + p: Annotated[dict[str, str] | dict[str, int], Query()], +): return {"p": p} @@ -91,6 +95,7 @@ class QueryModelRequiredDictUnion(BaseModel): def read_model_required_dict_union(p: Annotated[QueryModelRequiredDictUnion, Query()]): return {"p": p.p} + @pytest.mark.parametrize( "path", ["/required-dict-union", "/model-required-dict-union"], @@ -117,6 +122,7 @@ def test_required_dict_union_schema(path: str): } ] + @pytest.mark.parametrize( "path", ["/required-dict-union", "/model-required-dict-union"], @@ -136,6 +142,7 @@ def test_required_dict_union_missing(path: str): ] } + @pytest.mark.parametrize( "path", ["/required-dict-union", "/model-required-dict-union"], @@ -146,6 +153,7 @@ def test_required_dict_union(path: str): assert response.status_code == 200 assert response.json() == {"p": {"foo": "bar", "baz": "42"}} + @app.get("/required-dict-of-union") async def read_required_dict_of_union(p: Annotated[dict[str, int | bool], Query()]): return {"p": p} @@ -161,6 +169,7 @@ def read_model_required_dict_of_union( ): return {"p": p.p} + @pytest.mark.parametrize( "path", ["/required-dict-of-union", "/model-required-dict-of-union"], @@ -184,6 +193,7 @@ def test_required_dict_of_union_schema(path: str): } ] + @pytest.mark.parametrize( "path", ["/required-dict-of-union", "/model-required-dict-of-union"], @@ -215,19 +225,23 @@ def test_required_dict_of_union(path: str): assert response.status_code == 200 assert response.json() == {"p": {"foo": True, "baz": 42}} + @app.get("/required-dict-of-list") async def read_required_dict_of_list(p: Annotated[dict[str, list[int]], Query()]): return {"p": p} + class QueryModelRequiredDictOfList(BaseModel): p: dict[str, list[int]] + @app.get("/model-required-dict-of-list") def read_model_required_dict_of_list( p: Annotated[QueryModelRequiredDictOfList, Query()], ): return {"p": p.p} + @pytest.mark.parametrize( "path", ["/required-dict-of-list", "/model-required-dict-of-list"], @@ -249,6 +263,7 @@ def test_required_dict_of_list_schema(path: str): } ] + @pytest.mark.parametrize( "path", ["/required-dict-of-list", "/model-required-dict-of-list"], @@ -268,6 +283,7 @@ def test_required_dict_of_list_missing(path: str): ] } + @pytest.mark.parametrize( "path", ["/required-dict-of-list", "/model-required-dict-of-list"],