mirror of
https://github.com/fastapi/fastapi.git
synced 2026-10-30 05:41:02 -04:00
🔥 Remove deprecated **extra from request parameters (#16545)
This commit is contained in:
1 parent
6f288521eb
commit
34b1783f88
5 files changed
+55
-166
No files matched your search
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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"],
|
||||
|
||||
Reference in new issue
Block a user