Skip to content

Commit 8ae4603

Browse files
pachewisepre-commit-ci[bot]svlandeg
authored
🐛 Remove Required shadowing from fastapi using Pydantic v2 (fastapi#12197)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sofie Van Landeghem <[email protected]>
1 parent 529155e commit 8ae4603

File tree

5 files changed

+16
-16
lines changed

5 files changed

+16
-16
lines changed

docs_src/query_params_str_validations/tutorial006d.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
from fastapi import FastAPI, Query
2-
from pydantic import Required
32

43
app = FastAPI()
54

65

76
@app.get("/items/")
8-
async def read_items(q: str = Query(default=Required, min_length=3)):
7+
async def read_items(q: str = Query(default=..., min_length=3)):
98
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
109
if q:
1110
results.update({"q": q})

docs_src/query_params_str_validations/tutorial006d_an.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
from fastapi import FastAPI, Query
2-
from pydantic import Required
32
from typing_extensions import Annotated
43

54
app = FastAPI()
65

76

87
@app.get("/items/")
9-
async def read_items(q: Annotated[str, Query(min_length=3)] = Required):
8+
async def read_items(q: Annotated[str, Query(min_length=3)] = ...):
109
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
1110
if q:
1211
results.update({"q": q})

docs_src/query_params_str_validations/tutorial006d_an_py39.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
from typing import Annotated
22

33
from fastapi import FastAPI, Query
4-
from pydantic import Required
54

65
app = FastAPI()
76

87

98
@app.get("/items/")
10-
async def read_items(q: Annotated[str, Query(min_length=3)] = Required):
9+
async def read_items(q: Annotated[str, Query(min_length=3)] = ...):
1110
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
1211
if q:
1312
results.update({"q": q})

fastapi/_compat.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
general_plain_validator_function as with_info_plain_validator_function, # noqa: F401
7272
)
7373

74-
Required = PydanticUndefined
74+
RequiredParam = PydanticUndefined
7575
Undefined = PydanticUndefined
7676
UndefinedType = PydanticUndefinedType
7777
evaluate_forwardref = eval_type_lenient
@@ -313,9 +313,10 @@ def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
313313
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
314314
ModelField as ModelField, # noqa: F401
315315
)
316-
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
317-
Required as Required, # noqa: F401
318-
)
316+
317+
# Keeping old "Required" functionality from Pydantic V1, without
318+
# shadowing typing.Required.
319+
RequiredParam: Any = Ellipsis # type: ignore[no-redef]
319320
from pydantic.fields import ( # type: ignore[no-redef,attr-defined]
320321
Undefined as Undefined,
321322
)

fastapi/dependencies/utils.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
PYDANTIC_V2,
2525
ErrorWrapper,
2626
ModelField,
27-
Required,
27+
RequiredParam,
2828
Undefined,
2929
_regenerate_error_with_loc,
3030
copy_field_info,
@@ -377,15 +377,17 @@ def analyze_param(
377377
field_info = copy_field_info(
378378
field_info=fastapi_annotation, annotation=use_annotation
379379
)
380-
assert field_info.default is Undefined or field_info.default is Required, (
380+
assert (
381+
field_info.default is Undefined or field_info.default is RequiredParam
382+
), (
381383
f"`{field_info.__class__.__name__}` default value cannot be set in"
382384
f" `Annotated` for {param_name!r}. Set the default value with `=` instead."
383385
)
384386
if value is not inspect.Signature.empty:
385387
assert not is_path_param, "Path parameters cannot have default values"
386388
field_info.default = value
387389
else:
388-
field_info.default = Required
390+
field_info.default = RequiredParam
389391
# Get Annotated Depends
390392
elif isinstance(fastapi_annotation, params.Depends):
391393
depends = fastapi_annotation
@@ -434,9 +436,9 @@ def analyze_param(
434436
), f"Cannot specify FastAPI annotation for type {type_annotation!r}"
435437
# Handle default assignations, neither field_info nor depends was not found in Annotated nor default value
436438
elif field_info is None and depends is None:
437-
default_value = value if value is not inspect.Signature.empty else Required
439+
default_value = value if value is not inspect.Signature.empty else RequiredParam
438440
if is_path_param:
439-
# We might check here that `default_value is Required`, but the fact is that the same
441+
# We might check here that `default_value is RequiredParam`, but the fact is that the same
440442
# parameter might sometimes be a path parameter and sometimes not. See
441443
# `tests/test_infer_param_optionality.py` for an example.
442444
field_info = params.Path(annotation=use_annotation)
@@ -480,7 +482,7 @@ def analyze_param(
480482
type_=use_annotation_from_field_info,
481483
default=field_info.default,
482484
alias=alias,
483-
required=field_info.default in (Required, Undefined),
485+
required=field_info.default in (RequiredParam, Undefined),
484486
field_info=field_info,
485487
)
486488
if is_path_param:

0 commit comments

Comments
 (0)