🔥 Remove deprecated **extra from request parameters (#16545)

This commit is contained in:
Sebastián Ramírez authored and GitHub committed 2026-10-20 18:34:47 +02:00
1 parent 6f288521eb
commit 34b1783f88
5 files changed
+55 -166

No files matched your search

+2
View File
@@ -7,6 +7,8 @@ hide:
## Latest Changes
The deprecated `**extra` keyword arguments have been removed from `Path`, `Query`, `Header`, `Cookie`, `Body`, `Form`, and `File`. Unknown keyword arguments now raise `TypeError`. For additional JSON Schema properties, replace, for example, `Query(custom="value")` with `Query(json_schema_extra={"custom": "value"})`.
## 0.154.0 (2026-10-20)
### Features
+3 -3
View File
@@ -43,13 +43,13 @@ Notice how each model's attribute with a type, default value and `Field` has the
## Add extra information { #add-extra-information }
You can declare extra information in `Field`, `Query`, `Body`, etc. And it will be included in the generated JSON Schema.
You can declare extra information with `json_schema_extra` in `Field`, `Query`, `Body`, etc. And it will be included in the generated JSON Schema.
You will learn more about adding extra information later in the docs, when learning to declare examples.
/// warning
Extra keys passed to `Field` will also be present in the resulting OpenAPI schema for your application.
Extra keys passed in `json_schema_extra` will also be present in the resulting OpenAPI schema for your application.
As these keys may not necessarily be part of the OpenAPI specification, some OpenAPI tools, for example [the OpenAPI validator](https://validator.swagger.io/), may not work with your generated schema.
///
@@ -58,4 +58,4 @@ As these keys may not necessarily be part of the OpenAPI specification, some Ope
You can use Pydantic's `Field` to declare extra validations and metadata for model attributes.
You can also use the extra keyword arguments to pass additional JSON Schema metadata.
You can also use `json_schema_extra` to pass additional JSON Schema metadata.
-98
View File
@@ -315,19 +315,6 @@ def Path( # noqa: N802
"""
),
] = None,
**extra: Annotated[
Any,
Doc(
"""
Include extra fields used by the JSON Schema.
"""
),
deprecated(
"""
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
"""
),
],
) -> Any:
"""
Declare a path parameter for a *path operation*.
@@ -382,7 +369,6 @@ def Path( # noqa: N802
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -709,19 +695,6 @@ def Query( # noqa: N802
"""
),
] = None,
**extra: Annotated[
Any,
Doc(
"""
Include extra fields used by the JSON Schema.
"""
),
deprecated(
"""
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
"""
),
],
) -> Any:
return params.Query(
default=default,
@@ -755,7 +728,6 @@ def Query( # noqa: N802
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -1054,19 +1026,6 @@ def Header( # noqa: N802
"""
),
] = None,
**extra: Annotated[
Any,
Doc(
"""
Include extra fields used by the JSON Schema.
"""
),
deprecated(
"""
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
"""
),
],
) -> Any:
return params.Header(
default=default,
@@ -1101,7 +1060,6 @@ def Header( # noqa: N802
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -1389,19 +1347,6 @@ def Cookie( # noqa: N802
"""
),
] = None,
**extra: Annotated[
Any,
Doc(
"""
Include extra fields used by the JSON Schema.
"""
),
deprecated(
"""
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
"""
),
],
) -> Any:
return params.Cookie(
default=default,
@@ -1435,7 +1380,6 @@ def Cookie( # noqa: N802
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -1746,19 +1690,6 @@ def Body( # noqa: N802
"""
),
] = None,
**extra: Annotated[
Any,
Doc(
"""
Include extra fields used by the JSON Schema.
"""
),
deprecated(
"""
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
"""
),
],
) -> Any:
return params.Body(
default=default,
@@ -1794,7 +1725,6 @@ def Body( # noqa: N802
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -2091,19 +2021,6 @@ def Form( # noqa: N802
"""
),
] = None,
**extra: Annotated[
Any,
Doc(
"""
Include extra fields used by the JSON Schema.
"""
),
deprecated(
"""
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
"""
),
],
) -> Any:
return params.Form(
default=default,
@@ -2138,7 +2055,6 @@ def Form( # noqa: N802
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -2435,19 +2351,6 @@ def File( # noqa: N802
"""
),
] = None,
**extra: Annotated[
Any,
Doc(
"""
Include extra fields used by the JSON Schema.
"""
),
deprecated(
"""
The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
"""
),
],
) -> Any:
return params.File(
default=default,
@@ -2482,7 +2385,6 @@ def File( # noqa: N802
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
+44 -62
View File
@@ -75,7 +75,6 @@ class Param(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-cl
json_schema_extra: dict[str, Any]
| Callable[[dict[str, Any]], None]
| None = None,
**extra: Any,
):
if example is not _Unset:
warnings.warn(
@@ -86,28 +85,27 @@ class Param(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-cl
self.example = example
self.include_in_schema = include_in_schema
self.openapi_examples = openapi_examples
kwargs = dict(
default=default,
default_factory=default_factory,
alias=alias,
title=title,
description=description,
gt=gt,
ge=ge,
lt=lt,
le=le,
min_length=min_length,
max_length=max_length,
discriminator=discriminator,
validate_default=validate_default,
union_mode=union_mode,
fail_fast=fail_fast,
multiple_of=multiple_of,
allow_inf_nan=allow_inf_nan,
max_digits=max_digits,
decimal_places=decimal_places,
**extra,
)
kwargs = {
"default": default,
"default_factory": default_factory,
"alias": alias,
"title": title,
"description": description,
"gt": gt,
"ge": ge,
"lt": lt,
"le": le,
"min_length": min_length,
"max_length": max_length,
"discriminator": discriminator,
"validate_default": validate_default,
"union_mode": union_mode,
"fail_fast": fail_fast,
"multiple_of": multiple_of,
"allow_inf_nan": allow_inf_nan,
"max_digits": max_digits,
"decimal_places": decimal_places,
}
if examples is not None:
kwargs["examples"] = examples
if regex is not None:
@@ -116,7 +114,6 @@ class Param(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-cl
category=FastAPIDeprecationWarning,
stacklevel=4,
)
current_json_schema_extra = json_schema_extra or extra
kwargs["deprecated"] = deprecated
if serialization_alias in (_Unset, None) and isinstance(alias, str):
@@ -130,7 +127,7 @@ class Param(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-cl
"validation_alias": validation_alias,
"serialization_alias": serialization_alias,
"strict": strict,
"json_schema_extra": current_json_schema_extra,
"json_schema_extra": json_schema_extra,
}
)
kwargs["pattern"] = pattern or regex
@@ -194,7 +191,6 @@ class Path(Param): # type: ignore[misc]
json_schema_extra: dict[str, Any]
| Callable[[dict[str, Any]], None]
| None = None,
**extra: Any,
):
assert default is ..., "Path parameters cannot have a default value"
self.in_ = self.in_
@@ -231,7 +227,6 @@ class Path(Param): # type: ignore[misc]
openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -286,7 +281,6 @@ class Query(Param): # type: ignore[misc]
json_schema_extra: dict[str, Any]
| Callable[[dict[str, Any]], None]
| None = None,
**extra: Any,
):
super().__init__(
default=default,
@@ -321,7 +315,6 @@ class Query(Param): # type: ignore[misc]
openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -377,7 +370,6 @@ class Header(Param): # type: ignore[misc]
json_schema_extra: dict[str, Any]
| Callable[[dict[str, Any]], None]
| None = None,
**extra: Any,
):
self.convert_underscores = convert_underscores
super().__init__(
@@ -413,7 +405,6 @@ class Header(Param): # type: ignore[misc]
openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -468,7 +459,6 @@ class Cookie(Param): # type: ignore[misc]
json_schema_extra: dict[str, Any]
| Callable[[dict[str, Any]], None]
| None = None,
**extra: Any,
):
super().__init__(
default=default,
@@ -503,7 +493,6 @@ class Cookie(Param): # type: ignore[misc]
openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -558,7 +547,6 @@ class Body(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-cla
json_schema_extra: dict[str, Any]
| Callable[[dict[str, Any]], None]
| None = None,
**extra: Any,
):
self.embed = embed
self.media_type = media_type
@@ -571,28 +559,27 @@ class Body(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-cla
self.example = example
self.include_in_schema = include_in_schema
self.openapi_examples = openapi_examples
kwargs = dict(
default=default,
default_factory=default_factory,
alias=alias,
title=title,
description=description,
gt=gt,
ge=ge,
lt=lt,
le=le,
min_length=min_length,
max_length=max_length,
discriminator=discriminator,
validate_default=validate_default,
union_mode=union_mode,
fail_fast=fail_fast,
multiple_of=multiple_of,
allow_inf_nan=allow_inf_nan,
max_digits=max_digits,
decimal_places=decimal_places,
**extra,
)
kwargs = {
"default": default,
"default_factory": default_factory,
"alias": alias,
"title": title,
"description": description,
"gt": gt,
"ge": ge,
"lt": lt,
"le": le,
"min_length": min_length,
"max_length": max_length,
"discriminator": discriminator,
"validate_default": validate_default,
"union_mode": union_mode,
"fail_fast": fail_fast,
"multiple_of": multiple_of,
"allow_inf_nan": allow_inf_nan,
"max_digits": max_digits,
"decimal_places": decimal_places,
}
if examples is not None:
kwargs["examples"] = examples
if regex is not None:
@@ -601,7 +588,6 @@ class Body(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-cla
category=FastAPIDeprecationWarning,
stacklevel=4,
)
current_json_schema_extra = json_schema_extra or extra
kwargs["deprecated"] = deprecated
if serialization_alias in (_Unset, None) and isinstance(alias, str):
serialization_alias = alias
@@ -614,7 +600,7 @@ class Body(FieldInfo): # type: ignore[misc] # ty: ignore[subclass-of-final-cla
"validation_alias": validation_alias,
"serialization_alias": serialization_alias,
"strict": strict,
"json_schema_extra": current_json_schema_extra,
"json_schema_extra": json_schema_extra,
}
)
kwargs["pattern"] = pattern or regex
@@ -677,7 +663,6 @@ class Form(Body): # type: ignore[misc]
json_schema_extra: dict[str, Any]
| Callable[[dict[str, Any]], None]
| None = None,
**extra: Any,
):
super().__init__(
default=default,
@@ -713,7 +698,6 @@ class Form(Body): # type: ignore[misc]
openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
@@ -767,7 +751,6 @@ class File(Form): # type: ignore[misc]
json_schema_extra: dict[str, Any]
| Callable[[dict[str, Any]], None]
| None = None,
**extra: Any,
):
super().__init__(
default=default,
@@ -803,7 +786,6 @@ class File(Form): # type: ignore[misc]
openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
)
+6 -3
View File
@@ -370,15 +370,18 @@ def test_model_validator_does_not_mutate_other_branches():
assert response.json() == {"value": ["", "hello"]}
def test_embedded_union_still_rejects_a_string():
def test_union_with_another_form_parameter_rejects_a_string():
app = FastAPI()
@app.post("/")
def read_form(data: Annotated[TextForm | ListForm, Form(embed=True)]):
def read_form(
data: Annotated[TextForm | ListForm, Form()],
token: Annotated[str, Form()],
):
pytest.fail("Invalid form data reached the endpoint") # pragma: no cover
client = TestClient(app)
response = client.post("/", data={"data": "hello"})
response = client.post("/", data={"data": "hello", "token": "example"})
assert response.status_code == 422
assert [error["loc"] for error in response.json()["detail"]] == [
["body", "data", "TextForm"],