mirror of https://github.com/tiangolo/fastapi.git
🎨 Upgrade typing syntax for Python 3.10 (#14932)
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: tiangolo <1326112+tiangolo@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
6e5680c7ea
commit
faee822574
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
|
@ -30,6 +28,6 @@ items = {
|
|||
}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
|
||||
@app.get("/items/{item_id}", response_model=PlaneItem | CarItem)
|
||||
async def read_item(item_id: str):
|
||||
return items[item_id]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import re
|
||||
from typing import TypedDict, Union
|
||||
from typing import TypedDict
|
||||
|
||||
CODE_INCLUDE_RE = re.compile(r"^\{\*\s*(\S+)\s*(.*)\*\}$")
|
||||
CODE_INCLUDE_PLACEHOLDER = "<CODE_INCLUDE>"
|
||||
|
|
@ -50,8 +50,8 @@ class MarkdownLinkInfo(TypedDict):
|
|||
line_no: int
|
||||
url: str
|
||||
text: str
|
||||
title: Union[str, None]
|
||||
attributes: Union[str, None]
|
||||
title: str | None
|
||||
attributes: str | None
|
||||
full_match: str
|
||||
|
||||
|
||||
|
|
@ -287,8 +287,8 @@ def _add_lang_code_to_url(url: str, lang_code: str) -> str:
|
|||
def _construct_markdown_link(
|
||||
url: str,
|
||||
text: str,
|
||||
title: Union[str, None],
|
||||
attributes: Union[str, None],
|
||||
title: str | None,
|
||||
attributes: str | None,
|
||||
lang_code: str,
|
||||
) -> str:
|
||||
"""
|
||||
|
|
@ -549,7 +549,7 @@ def extract_multiline_code_blocks(text: list[str]) -> list[MultilineCodeBlockInf
|
|||
return blocks
|
||||
|
||||
|
||||
def _split_hash_comment(line: str) -> tuple[str, Union[str, None]]:
|
||||
def _split_hash_comment(line: str) -> tuple[str, str | None]:
|
||||
match = HASH_COMMENT_RE.match(line)
|
||||
if match:
|
||||
code = match.group("code").rstrip()
|
||||
|
|
@ -558,7 +558,7 @@ def _split_hash_comment(line: str) -> tuple[str, Union[str, None]]:
|
|||
return line.rstrip(), None
|
||||
|
||||
|
||||
def _split_slashes_comment(line: str) -> tuple[str, Union[str, None]]:
|
||||
def _split_slashes_comment(line: str) -> tuple[str, str | None]:
|
||||
match = SLASHES_COMMENT_RE.match(line)
|
||||
if match:
|
||||
code = match.group("code").rstrip()
|
||||
|
|
@ -603,9 +603,9 @@ def replace_multiline_code_block(
|
|||
return block_a["content"].copy() # We don't handle mermaid code blocks for now
|
||||
|
||||
code_block: list[str] = []
|
||||
for line_a, line_b in zip(block_a["content"], block_b["content"]):
|
||||
line_a_comment: Union[str, None] = None
|
||||
line_b_comment: Union[str, None] = None
|
||||
for line_a, line_b in zip(block_a["content"], block_b["content"], strict=False):
|
||||
line_a_comment: str | None = None
|
||||
line_b_comment: str | None = None
|
||||
|
||||
# Handle comments based on language
|
||||
if block_language in {
|
||||
|
|
@ -659,7 +659,7 @@ def replace_multiline_code_blocks_in_text(
|
|||
)
|
||||
|
||||
modified_text = text.copy()
|
||||
for block, original_block in zip(code_blocks, original_code_blocks):
|
||||
for block, original_block in zip(code_blocks, original_code_blocks, strict=True):
|
||||
updated_content = replace_multiline_code_block(block, original_block)
|
||||
|
||||
start_line_index = block["start_line_no"] - 1
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any, Union
|
||||
from typing import Any
|
||||
|
||||
import material
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
|
|
@ -105,9 +105,9 @@ def on_files(files: Files, *, config: MkDocsConfig) -> Files:
|
|||
|
||||
|
||||
def generate_renamed_section_items(
|
||||
items: list[Union[Page, Section, Link]], *, config: MkDocsConfig
|
||||
) -> list[Union[Page, Section, Link]]:
|
||||
new_items: list[Union[Page, Section, Link]] = []
|
||||
items: list[Page | Section | Link], *, config: MkDocsConfig
|
||||
) -> list[Page | Section | Link]:
|
||||
new_items: list[Page | Section | Link] = []
|
||||
for item in items:
|
||||
if isinstance(item, Section):
|
||||
new_title = item.title
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import random
|
|||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Any, Union, cast
|
||||
from typing import Any, cast
|
||||
|
||||
import httpx
|
||||
from github import Github
|
||||
|
|
@ -181,9 +181,9 @@ class Settings(BaseSettings):
|
|||
github_repository: str
|
||||
github_token: SecretStr
|
||||
github_event_path: Path
|
||||
github_event_name: Union[str, None] = None
|
||||
github_event_name: str | None = None
|
||||
httpx_timeout: int = 30
|
||||
debug: Union[bool, None] = False
|
||||
debug: bool | None = False
|
||||
number: int | None = None
|
||||
|
||||
|
||||
|
|
@ -199,12 +199,12 @@ def get_graphql_response(
|
|||
*,
|
||||
settings: Settings,
|
||||
query: str,
|
||||
after: Union[str, None] = None,
|
||||
category_id: Union[str, None] = None,
|
||||
discussion_number: Union[int, None] = None,
|
||||
discussion_id: Union[str, None] = None,
|
||||
comment_id: Union[str, None] = None,
|
||||
body: Union[str, None] = None,
|
||||
after: str | None = None,
|
||||
category_id: str | None = None,
|
||||
discussion_number: int | None = None,
|
||||
discussion_id: str | None = None,
|
||||
comment_id: str | None = None,
|
||||
body: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
headers = {"Authorization": f"token {settings.github_token.get_secret_value()}"}
|
||||
variables = {
|
||||
|
|
@ -249,7 +249,7 @@ def get_graphql_translation_discussions(
|
|||
|
||||
|
||||
def get_graphql_translation_discussion_comments_edges(
|
||||
*, settings: Settings, discussion_number: int, after: Union[str, None] = None
|
||||
*, settings: Settings, discussion_number: int, after: str | None = None
|
||||
) -> list[CommentsEdge]:
|
||||
data = get_graphql_response(
|
||||
settings=settings,
|
||||
|
|
@ -372,8 +372,8 @@ def main() -> None:
|
|||
f"Found a translation discussion for language: {lang} in discussion: #{discussion.number}"
|
||||
)
|
||||
|
||||
already_notified_comment: Union[Comment, None] = None
|
||||
already_done_comment: Union[Comment, None] = None
|
||||
already_notified_comment: Comment | None = None
|
||||
already_done_comment: Comment | None = None
|
||||
|
||||
logging.info(
|
||||
f"Checking current comments in discussion: #{discussion.number} to see if already notified about this PR: #{pr.number}"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from collections import Counter
|
|||
from collections.abc import Container
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any, Union
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
import yaml
|
||||
|
|
@ -70,7 +70,7 @@ class Author(BaseModel):
|
|||
|
||||
class CommentsNode(BaseModel):
|
||||
createdAt: datetime
|
||||
author: Union[Author, None] = None
|
||||
author: Author | None = None
|
||||
|
||||
|
||||
class Replies(BaseModel):
|
||||
|
|
@ -89,7 +89,7 @@ class DiscussionsComments(BaseModel):
|
|||
|
||||
class DiscussionsNode(BaseModel):
|
||||
number: int
|
||||
author: Union[Author, None] = None
|
||||
author: Author | None = None
|
||||
title: str | None = None
|
||||
createdAt: datetime
|
||||
comments: DiscussionsComments
|
||||
|
|
@ -127,8 +127,8 @@ def get_graphql_response(
|
|||
*,
|
||||
settings: Settings,
|
||||
query: str,
|
||||
after: Union[str, None] = None,
|
||||
category_id: Union[str, None] = None,
|
||||
after: str | None = None,
|
||||
category_id: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
headers = {"Authorization": f"token {settings.github_token.get_secret_value()}"}
|
||||
variables = {"after": after, "category_id": category_id}
|
||||
|
|
@ -156,7 +156,7 @@ def get_graphql_response(
|
|||
def get_graphql_question_discussion_edges(
|
||||
*,
|
||||
settings: Settings,
|
||||
after: Union[str, None] = None,
|
||||
after: str | None = None,
|
||||
) -> list[DiscussionsEdge]:
|
||||
data = get_graphql_response(
|
||||
settings=settings,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import http
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Path, Query
|
||||
|
||||
|
|
@ -54,7 +53,7 @@ def get_bool_id(item_id: bool):
|
|||
|
||||
|
||||
@app.get("/path/param/{item_id}")
|
||||
def get_path_param_id(item_id: Optional[str] = Path()):
|
||||
def get_path_param_id(item_id: str | None = Path()):
|
||||
return item_id
|
||||
|
||||
|
||||
|
|
@ -161,7 +160,7 @@ def get_query_type(query: int):
|
|||
|
||||
|
||||
@app.get("/query/int/optional")
|
||||
def get_query_type_optional(query: Optional[int] = None):
|
||||
def get_query_type_optional(query: int | None = None):
|
||||
if query is None:
|
||||
return "foo bar"
|
||||
return f"foo bar {query}"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -19,7 +17,7 @@ app = FastAPI()
|
|||
|
||||
@app.post("/")
|
||||
async def post(
|
||||
foo: Union[Foo, None] = None,
|
||||
foo: Foo | None = None,
|
||||
):
|
||||
return foo
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ don't accumulate duplicate $ref entries in anyOf arrays.
|
|||
See https://github.com/fastapi/fastapi/pull/14463
|
||||
"""
|
||||
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -23,7 +21,7 @@ class ModelB(BaseModel):
|
|||
app = FastAPI(
|
||||
responses={
|
||||
500: {
|
||||
"model": Union[ModelA, ModelB],
|
||||
"model": ModelA | ModelB,
|
||||
"content": {"application/json": {"examples": {"Case A": {"value": "a"}}}},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
from functools import partial
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
def main(some_arg, q: Optional[str] = None):
|
||||
def main(some_arg, q: str | None = None):
|
||||
return {"some_arg": some_arg, "q": q}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI, UploadFile
|
||||
from fastapi._compat import (
|
||||
Undefined,
|
||||
|
|
@ -10,8 +8,6 @@ from fastapi.testclient import TestClient
|
|||
from pydantic import BaseModel, ConfigDict
|
||||
from pydantic.fields import FieldInfo
|
||||
|
||||
from .utils import needs_py310
|
||||
|
||||
|
||||
def test_model_field_default_required():
|
||||
from fastapi._compat import v2
|
||||
|
|
@ -26,7 +22,7 @@ def test_complex():
|
|||
app = FastAPI()
|
||||
|
||||
@app.post("/")
|
||||
def foo(foo: Union[str, list[int]]):
|
||||
def foo(foo: str | list[int]):
|
||||
return foo
|
||||
|
||||
client = TestClient(app)
|
||||
|
|
@ -49,17 +45,17 @@ def test_propagates_pydantic2_model_config():
|
|||
|
||||
class EmbeddedModel(BaseModel):
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
value: Union[str, Missing] = Missing()
|
||||
value: str | Missing = Missing()
|
||||
|
||||
class Model(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
arbitrary_types_allowed=True,
|
||||
)
|
||||
value: Union[str, Missing] = Missing()
|
||||
value: str | Missing = Missing()
|
||||
embedded_model: EmbeddedModel = EmbeddedModel()
|
||||
|
||||
@app.post("/")
|
||||
def foo(req: Model) -> dict[str, Union[str, None]]:
|
||||
def foo(req: Model) -> dict[str, str | None]:
|
||||
return {
|
||||
"value": req.value or None,
|
||||
"embedded_value": req.embedded_model.value or None,
|
||||
|
|
@ -89,7 +85,7 @@ def test_is_bytes_sequence_annotation_union():
|
|||
# TODO: in theory this would allow declaring types that could be lists of bytes
|
||||
# to be read from files and other types, but I'm not even sure it's a good idea
|
||||
# to support it as a first class "feature"
|
||||
assert is_bytes_sequence_annotation(Union[list[str], list[bytes]])
|
||||
assert is_bytes_sequence_annotation(list[str] | list[bytes])
|
||||
|
||||
|
||||
def test_is_uploadfile_sequence_annotation():
|
||||
|
|
@ -97,21 +93,20 @@ def test_is_uploadfile_sequence_annotation():
|
|||
# TODO: in theory this would allow declaring types that could be lists of UploadFile
|
||||
# and other types, but I'm not even sure it's a good idea to support it as a first
|
||||
# class "feature"
|
||||
assert is_uploadfile_sequence_annotation(Union[list[str], list[UploadFile]])
|
||||
assert is_uploadfile_sequence_annotation(list[str] | list[UploadFile])
|
||||
|
||||
|
||||
def test_serialize_sequence_value_with_optional_list():
|
||||
"""Test that serialize_sequence_value handles optional lists correctly."""
|
||||
from fastapi._compat import v2
|
||||
|
||||
field_info = FieldInfo(annotation=Union[list[str], None])
|
||||
field_info = FieldInfo(annotation=list[str] | None)
|
||||
field = v2.ModelField(name="items", field_info=field_info)
|
||||
result = v2.serialize_sequence_value(field=field, value=["a", "b", "c"])
|
||||
assert result == ["a", "b", "c"]
|
||||
assert isinstance(result, list)
|
||||
|
||||
|
||||
@needs_py310
|
||||
def test_serialize_sequence_value_with_optional_list_pipe_union():
|
||||
"""Test that serialize_sequence_value handles optional lists correctly (with new syntax)."""
|
||||
from fastapi._compat import v2
|
||||
|
|
@ -125,9 +120,12 @@ def test_serialize_sequence_value_with_optional_list_pipe_union():
|
|||
|
||||
def test_serialize_sequence_value_with_none_first_in_union():
|
||||
"""Test that serialize_sequence_value handles Union[None, List[...]] correctly."""
|
||||
from typing import Union
|
||||
|
||||
from fastapi._compat import v2
|
||||
|
||||
field_info = FieldInfo(annotation=Union[None, list[str]])
|
||||
# Use Union[None, list[str]] to ensure None comes first in the union args
|
||||
field_info = FieldInfo(annotation=Union[None, list[str]]) # noqa: UP007
|
||||
field = v2.ModelField(name="items", field_info=field_info)
|
||||
result = v2.serialize_sequence_value(field=field, value=["x", "y"])
|
||||
assert result == ["x", "y"]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, FastAPI, File, UploadFile
|
||||
from fastapi.exceptions import HTTPException
|
||||
|
|
@ -17,7 +16,7 @@ class ContentSizeLimitMiddleware:
|
|||
max_content_size (optional): the maximum content size allowed in bytes, None for no limit
|
||||
"""
|
||||
|
||||
def __init__(self, app: APIRouter, max_content_size: Optional[int] = None):
|
||||
def __init__(self, app: APIRouter, max_content_size: int | None = None):
|
||||
self.app = app
|
||||
self.max_content_size = max_content_size
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -10,9 +10,9 @@ app = FastAPI()
|
|||
class Item(BaseModel):
|
||||
name: str
|
||||
|
||||
description: Annotated[
|
||||
Optional[str], WithJsonSchema({"type": ["string", "null"]})
|
||||
] = None
|
||||
description: Annotated[str | None, WithJsonSchema({"type": ["string", "null"]})] = (
|
||||
None
|
||||
)
|
||||
|
||||
model_config = {
|
||||
"json_schema_extra": {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
from collections.abc import Awaitable
|
||||
from collections.abc import Awaitable, Callable
|
||||
from contextvars import ContextVar
|
||||
from typing import Any, Callable, Optional
|
||||
from typing import Any
|
||||
|
||||
from fastapi import Depends, FastAPI, Request, Response
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
legacy_request_state_context_var: ContextVar[Optional[dict[str, Any]]] = ContextVar(
|
||||
legacy_request_state_context_var: ContextVar[dict[str, Any] | None] = ContextVar(
|
||||
"legacy_request_state_context_var", default=None
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from fastapi import APIRouter, Depends, FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -38,7 +36,7 @@ app.include_router(router)
|
|||
client = TestClient(app)
|
||||
|
||||
|
||||
async def overrider_dependency_simple(q: Optional[str] = None):
|
||||
async def overrider_dependency_simple(q: str | None = None):
|
||||
return {"q": q, "skip": 5, "limit": 10}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Union
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Security
|
||||
from fastapi.security import (
|
||||
|
|
@ -13,7 +13,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
|||
|
||||
|
||||
def process_auth(
|
||||
credentials: Annotated[Union[str, None], Security(oauth2_scheme)],
|
||||
credentials: Annotated[str | None, Security(oauth2_scheme)],
|
||||
security_scopes: SecurityScopes,
|
||||
):
|
||||
# This is an incorrect way of using it, this is not checking if the scopes are
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI, Query
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -11,7 +9,7 @@ def _get_client_key(client_id: str = Query(...)) -> str:
|
|||
return f"{client_id}_key"
|
||||
|
||||
|
||||
def _get_client_tag(client_id: Optional[str] = Query(None)) -> Optional[str]:
|
||||
def _get_client_tag(client_id: str | None = Query(None)) -> str | None:
|
||||
if client_id is None:
|
||||
return None
|
||||
return f"{client_id}_tag"
|
||||
|
|
@ -20,7 +18,7 @@ def _get_client_tag(client_id: Optional[str] = Query(None)) -> Optional[str]:
|
|||
@app.get("/foo")
|
||||
def foo_handler(
|
||||
client_key: str = Depends(_get_client_key),
|
||||
client_tag: Optional[str] = Depends(_get_client_tag),
|
||||
client_tag: str | None = Depends(_get_client_tag),
|
||||
):
|
||||
return {"client_id": client_key, "client_tag": client_tag}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -11,7 +9,7 @@ app = FastAPI()
|
|||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: Optional[float] = None
|
||||
price: float | None = None
|
||||
|
||||
|
||||
@app.api_route("/items/{item_id}", methods=["GET"])
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from dirty_equals import HasRepr
|
||||
from fastapi import Depends, FastAPI
|
||||
|
|
@ -22,7 +20,7 @@ def get_client():
|
|||
|
||||
class ModelA(BaseModel):
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
description: str | None = None
|
||||
foo: ModelB
|
||||
tags: dict[str, str] = {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import FastAPI, File, Form
|
||||
from starlette.testclient import TestClient
|
||||
|
|
@ -7,14 +7,14 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.post("/urlencoded")
|
||||
async def post_url_encoded(age: Annotated[Optional[int], Form()] = None):
|
||||
async def post_url_encoded(age: Annotated[int | None, Form()] = None):
|
||||
return age
|
||||
|
||||
|
||||
@app.post("/multipart")
|
||||
async def post_multi_part(
|
||||
age: Annotated[Optional[int], Form()] = None,
|
||||
file: Annotated[Optional[bytes], File()] = None,
|
||||
age: Annotated[int | None, Form()] = None,
|
||||
file: Annotated[bytes | None, File()] = None,
|
||||
):
|
||||
return {"file": file, "age": age}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import FastAPI, Form
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -10,7 +10,7 @@ app = FastAPI()
|
|||
class FormModel(BaseModel):
|
||||
username: str
|
||||
lastname: str
|
||||
age: Optional[int] = None
|
||||
age: int | None = None
|
||||
tags: list[str] = ["foo", "bar"]
|
||||
alias_with: str = Field(alias="with", default="nothing")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -22,7 +20,7 @@ def get_user(user_id: str):
|
|||
|
||||
|
||||
@item_router.get("/")
|
||||
def get_items(user_id: Optional[str] = None):
|
||||
def get_items(user_id: str | None = None):
|
||||
if user_id is None:
|
||||
return [{"item_id": "i1", "user_id": "u1"}, {"item_id": "i2", "user_id": "u2"}]
|
||||
else:
|
||||
|
|
@ -30,7 +28,7 @@ def get_items(user_id: Optional[str] = None):
|
|||
|
||||
|
||||
@item_router.get("/{item_id}")
|
||||
def get_item(item_id: str, user_id: Optional[str] = None):
|
||||
def get_item(item_id: str, user_id: str | None = None):
|
||||
if user_id is None:
|
||||
return {"item_id": item_id}
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI, Query
|
||||
from pydantic import BaseModel
|
||||
|
|
@ -61,5 +59,5 @@ def test_invalid_simple_dict():
|
|||
title: str
|
||||
|
||||
@app.get("/items/")
|
||||
def read_items(q: Optional[dict] = Query(default=None)):
|
||||
def read_items(q: dict | None = Query(default=None)):
|
||||
pass # pragma: no cover
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from decimal import Decimal
|
|||
from enum import Enum
|
||||
from math import isinf, isnan
|
||||
from pathlib import PurePath, PurePosixPath, PureWindowsPath
|
||||
from typing import Optional, TypedDict
|
||||
from typing import TypedDict
|
||||
|
||||
import pytest
|
||||
from fastapi._compat import Undefined
|
||||
|
|
@ -57,7 +57,7 @@ class RoleEnum(Enum):
|
|||
|
||||
|
||||
class ModelWithConfig(BaseModel):
|
||||
role: Optional[RoleEnum] = None
|
||||
role: RoleEnum | None = None
|
||||
|
||||
model_config = {"use_enum_values": True}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Union
|
||||
|
||||
from fastapi import Body, Cookie, FastAPI, Header, Path, Query
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -57,7 +55,7 @@ def path_examples(
|
|||
|
||||
@app.get("/query_examples/")
|
||||
def query_examples(
|
||||
data: Union[str, None] = Query(
|
||||
data: str | None = Query(
|
||||
default=None,
|
||||
examples=[
|
||||
"json_schema_query1",
|
||||
|
|
@ -80,7 +78,7 @@ def query_examples(
|
|||
|
||||
@app.get("/header_examples/")
|
||||
def header_examples(
|
||||
data: Union[str, None] = Header(
|
||||
data: str | None = Header(
|
||||
default=None,
|
||||
examples=[
|
||||
"json_schema_header1",
|
||||
|
|
@ -103,7 +101,7 @@ def header_examples(
|
|||
|
||||
@app.get("/cookie_examples/")
|
||||
def cookie_examples(
|
||||
data: Union[str, None] = Cookie(
|
||||
data: str | None = Cookie(
|
||||
default=None,
|
||||
examples=["json_schema_cookie1", "json_schema_cookie2"],
|
||||
openapi_examples={
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -26,7 +24,7 @@ app = FastAPI()
|
|||
]
|
||||
},
|
||||
)
|
||||
def route_with_extra_query_parameters(standard_query_param: Optional[int] = 50):
|
||||
def route_with_extra_query_parameters(standard_query_param: int | None = 50):
|
||||
return {}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional, Union
|
||||
|
||||
import pytest
|
||||
from fastapi.openapi.models import Schema, SchemaType
|
||||
|
||||
|
|
@ -13,7 +11,7 @@ from fastapi.openapi.models import Schema, SchemaType
|
|||
],
|
||||
)
|
||||
def test_allowed_schema_type(
|
||||
type_value: Optional[Union[SchemaType, list[SchemaType]]],
|
||||
type_value: SchemaType | list[SchemaType] | None,
|
||||
) -> None:
|
||||
"""Test that Schema accepts SchemaType, List[SchemaType] and None for type field."""
|
||||
schema = Schema(type=type_value)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -8,15 +6,15 @@ from pydantic import BaseModel, computed_field
|
|||
|
||||
class SubItem(BaseModel):
|
||||
subname: str
|
||||
sub_description: Optional[str] = None
|
||||
sub_description: str | None = None
|
||||
tags: list[str] = []
|
||||
model_config = {"json_schema_serialization_defaults_required": True}
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
sub: Optional[SubItem] = None
|
||||
description: str | None = None
|
||||
sub: SubItem | None = None
|
||||
model_config = {"json_schema_serialization_defaults_required": True}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, File
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
|
@ -7,7 +5,7 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.post("/files")
|
||||
async def upload_files(files: Optional[list[bytes]] = File(None)):
|
||||
async def upload_files(files: list[bytes] | None = File(None)):
|
||||
if files is None:
|
||||
return {"files_count": 0}
|
||||
return {"files_count": len(files), "sizes": [len(f) for f in files]}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.params import Param
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -8,7 +6,7 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.get("/items/")
|
||||
def read_items(q: Optional[str] = Param(default=None)): # type: ignore
|
||||
def read_items(q: str | None = Param(default=None)): # type: ignore
|
||||
return {"q": q}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from fastapi import Cookie, FastAPI, Header, Path, Query
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -10,14 +8,14 @@ app = FastAPI()
|
|||
|
||||
@app.get("/hidden_cookie")
|
||||
async def hidden_cookie(
|
||||
hidden_cookie: Optional[str] = Cookie(default=None, include_in_schema=False),
|
||||
hidden_cookie: str | None = Cookie(default=None, include_in_schema=False),
|
||||
):
|
||||
return {"hidden_cookie": hidden_cookie}
|
||||
|
||||
|
||||
@app.get("/hidden_header")
|
||||
async def hidden_header(
|
||||
hidden_header: Optional[str] = Header(default=None, include_in_schema=False),
|
||||
hidden_header: str | None = Header(default=None, include_in_schema=False),
|
||||
):
|
||||
return {"hidden_header": hidden_header}
|
||||
|
||||
|
|
@ -29,7 +27,7 @@ async def hidden_path(hidden_path: str = Path(include_in_schema=False)):
|
|||
|
||||
@app.get("/hidden_query")
|
||||
async def hidden_query(
|
||||
hidden_query: Optional[str] = Query(default=None, include_in_schema=False),
|
||||
hidden_query: str | None = Query(default=None, include_in_schema=False),
|
||||
):
|
||||
return {"hidden_query": hidden_query}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import sys
|
||||
import warnings
|
||||
from typing import Union
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -80,7 +79,7 @@ def test_raises_pydantic_v1_model_in_union() -> None:
|
|||
with pytest.raises(PydanticV1NotSupportedError):
|
||||
|
||||
@app.post("/union")
|
||||
def endpoint(data: Union[dict, ModelV1A]): # pragma: no cover
|
||||
def endpoint(data: dict | ModelV1A): # pragma: no cover
|
||||
return data
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ from __future__ import annotations
|
|||
|
||||
import uuid
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Union
|
||||
|
||||
from dirty_equals import IsUUID
|
||||
from fastapi import FastAPI
|
||||
|
|
@ -16,8 +15,8 @@ class Item:
|
|||
name: str
|
||||
price: float
|
||||
tags: list[str] = field(default_factory=list)
|
||||
description: Union[str, None] = None
|
||||
tax: Union[float, None] = None
|
||||
description: str | None = None
|
||||
tax: float | None = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Union
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from dirty_equals import IsOneOf, IsPartialDict
|
||||
|
|
@ -55,7 +55,7 @@ def test_required_list_str_schema(path: str):
|
|||
"path",
|
||||
["/required-list-str", "/model-required-list-str"],
|
||||
)
|
||||
def test_required_list_str_missing(path: str, json: Union[dict, None]):
|
||||
def test_required_list_str_missing(path: str, json: dict | None):
|
||||
client = TestClient(app)
|
||||
response = client.post(path, json=json)
|
||||
assert response.status_code == 422
|
||||
|
|
@ -132,7 +132,7 @@ def test_required_list_str_alias_schema(path: str):
|
|||
"path",
|
||||
["/required-list-alias", "/model-required-list-alias"],
|
||||
)
|
||||
def test_required_list_alias_missing(path: str, json: Union[dict, None]):
|
||||
def test_required_list_alias_missing(path: str, json: dict | None):
|
||||
client = TestClient(app)
|
||||
response = client.post(path, json=json)
|
||||
assert response.status_code == 422
|
||||
|
|
@ -236,7 +236,7 @@ def test_required_list_validation_alias_schema(path: str):
|
|||
"/model-required-list-validation-alias",
|
||||
],
|
||||
)
|
||||
def test_required_list_validation_alias_missing(path: str, json: Union[dict, None]):
|
||||
def test_required_list_validation_alias_missing(path: str, json: dict | None):
|
||||
client = TestClient(app)
|
||||
response = client.post(path, json=json)
|
||||
assert response.status_code == 422
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import Body, FastAPI
|
||||
|
|
@ -15,13 +15,13 @@ app = FastAPI()
|
|||
|
||||
@app.post("/optional-list-str", operation_id="optional_list_str")
|
||||
async def read_optional_list_str(
|
||||
p: Annotated[Optional[list[str]], Body(embed=True)] = None,
|
||||
p: Annotated[list[str] | None, Body(embed=True)] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class BodyModelOptionalListStr(BaseModel):
|
||||
p: Optional[list[str]] = None
|
||||
p: list[str] | None = None
|
||||
|
||||
|
||||
@app.post("/model-optional-list-str", operation_id="model_optional_list_str")
|
||||
|
|
@ -103,13 +103,13 @@ def test_optional_list_str(path: str):
|
|||
|
||||
@app.post("/optional-list-alias", operation_id="optional_list_alias")
|
||||
async def read_optional_list_alias(
|
||||
p: Annotated[Optional[list[str]], Body(embed=True, alias="p_alias")] = None,
|
||||
p: Annotated[list[str] | None, Body(embed=True, alias="p_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class BodyModelOptionalListAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(None, alias="p_alias")
|
||||
p: list[str] | None = Field(None, alias="p_alias")
|
||||
|
||||
|
||||
@app.post("/model-optional-list-alias", operation_id="model_optional_list_alias")
|
||||
|
|
@ -208,14 +208,14 @@ def test_optional_list_alias_by_alias(path: str):
|
|||
)
|
||||
def read_optional_list_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[list[str]], Body(embed=True, validation_alias="p_val_alias")
|
||||
list[str] | None, Body(embed=True, validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class BodyModelOptionalListValidationAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
|
||||
p: list[str] | None = Field(None, validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.post(
|
||||
|
|
@ -323,7 +323,7 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
|
|||
)
|
||||
def read_optional_list_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[list[str]],
|
||||
list[str] | None,
|
||||
Body(embed=True, alias="p_alias", validation_alias="p_val_alias"),
|
||||
] = None,
|
||||
):
|
||||
|
|
@ -331,9 +331,7 @@ def read_optional_list_alias_and_validation_alias(
|
|||
|
||||
|
||||
class BodyModelOptionalListAliasAndValidationAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(
|
||||
None, alias="p_alias", validation_alias="p_val_alias"
|
||||
)
|
||||
p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.post(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import Body, FastAPI
|
||||
|
|
@ -14,12 +14,12 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.post("/optional-str", operation_id="optional_str")
|
||||
async def read_optional_str(p: Annotated[Optional[str], Body(embed=True)] = None):
|
||||
async def read_optional_str(p: Annotated[str | None, Body(embed=True)] = None):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class BodyModelOptionalStr(BaseModel):
|
||||
p: Optional[str] = None
|
||||
p: str | None = None
|
||||
|
||||
|
||||
@app.post("/model-optional-str", operation_id="model_optional_str")
|
||||
|
|
@ -98,13 +98,13 @@ def test_optional_str(path: str):
|
|||
|
||||
@app.post("/optional-alias", operation_id="optional_alias")
|
||||
async def read_optional_alias(
|
||||
p: Annotated[Optional[str], Body(embed=True, alias="p_alias")] = None,
|
||||
p: Annotated[str | None, Body(embed=True, alias="p_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class BodyModelOptionalAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias")
|
||||
p: str | None = Field(None, alias="p_alias")
|
||||
|
||||
|
||||
@app.post("/model-optional-alias", operation_id="model_optional_alias")
|
||||
|
|
@ -197,15 +197,13 @@ def test_optional_alias_by_alias(path: str):
|
|||
|
||||
@app.post("/optional-validation-alias", operation_id="optional_validation_alias")
|
||||
def read_optional_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[str], Body(embed=True, validation_alias="p_val_alias")
|
||||
] = None,
|
||||
p: Annotated[str | None, Body(embed=True, validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class BodyModelOptionalValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.post(
|
||||
|
|
@ -309,14 +307,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
|
|||
)
|
||||
def read_optional_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[str], Body(embed=True, alias="p_alias", validation_alias="p_val_alias")
|
||||
str | None, Body(embed=True, alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class BodyModelOptionalAliasAndValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.post(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Any, Union
|
||||
from typing import Annotated, Any
|
||||
|
||||
import pytest
|
||||
from dirty_equals import IsOneOf
|
||||
|
|
@ -51,7 +51,7 @@ def test_required_str_schema(path: str):
|
|||
"path",
|
||||
["/required-str", "/model-required-str"],
|
||||
)
|
||||
def test_required_str_missing(path: str, json: Union[dict[str, Any], None]):
|
||||
def test_required_str_missing(path: str, json: dict[str, Any] | None):
|
||||
client = TestClient(app)
|
||||
response = client.post(path, json=json)
|
||||
assert response.status_code == 422
|
||||
|
|
@ -124,7 +124,7 @@ def test_required_str_alias_schema(path: str):
|
|||
"path",
|
||||
["/required-alias", "/model-required-alias"],
|
||||
)
|
||||
def test_required_alias_missing(path: str, json: Union[dict[str, Any], None]):
|
||||
def test_required_alias_missing(path: str, json: dict[str, Any] | None):
|
||||
client = TestClient(app)
|
||||
response = client.post(path, json=json)
|
||||
assert response.status_code == 422
|
||||
|
|
@ -221,9 +221,7 @@ def test_required_validation_alias_schema(path: str):
|
|||
"/model-required-validation-alias",
|
||||
],
|
||||
)
|
||||
def test_required_validation_alias_missing(
|
||||
path: str, json: Union[dict[str, Any], None]
|
||||
):
|
||||
def test_required_validation_alias_missing(path: str, json: dict[str, Any] | None):
|
||||
client = TestClient(app)
|
||||
response = client.post(path, json=json)
|
||||
assert response.status_code == 422
|
||||
|
|
@ -338,7 +336,7 @@ def test_required_alias_and_validation_alias_schema(path: str):
|
|||
],
|
||||
)
|
||||
def test_required_alias_and_validation_alias_missing(
|
||||
path: str, json: Union[dict[str, Any], None]
|
||||
path: str, json: dict[str, Any] | None
|
||||
):
|
||||
client = TestClient(app)
|
||||
response = client.post(path, json=json)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import Cookie, FastAPI
|
||||
|
|
@ -13,12 +13,12 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.get("/optional-str")
|
||||
async def read_optional_str(p: Annotated[Optional[str], Cookie()] = None):
|
||||
async def read_optional_str(p: Annotated[str | None, Cookie()] = None):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class CookieModelOptionalStr(BaseModel):
|
||||
p: Optional[str] = None
|
||||
p: str | None = None
|
||||
|
||||
|
||||
@app.get("/model-optional-str")
|
||||
|
|
@ -75,13 +75,13 @@ def test_optional_str(path: str):
|
|||
|
||||
@app.get("/optional-alias")
|
||||
async def read_optional_alias(
|
||||
p: Annotated[Optional[str], Cookie(alias="p_alias")] = None,
|
||||
p: Annotated[str | None, Cookie(alias="p_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class CookieModelOptionalAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias")
|
||||
p: str | None = Field(None, alias="p_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-alias")
|
||||
|
|
@ -153,13 +153,13 @@ def test_optional_alias_by_alias(path: str):
|
|||
|
||||
@app.get("/optional-validation-alias")
|
||||
def read_optional_validation_alias(
|
||||
p: Annotated[Optional[str], Cookie(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[str | None, Cookie(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class CookieModelOptionalValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-validation-alias")
|
||||
|
|
@ -237,14 +237,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
|
|||
@app.get("/optional-alias-and-validation-alias")
|
||||
def read_optional_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[str], Cookie(alias="p_alias", validation_alias="p_val_alias")
|
||||
str | None, Cookie(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class CookieModelOptionalAliasAndValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-alias-and-validation-alias")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI, File, UploadFile
|
||||
|
|
@ -13,12 +13,12 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.post("/optional-bytes", operation_id="optional_bytes")
|
||||
async def read_optional_bytes(p: Annotated[Optional[bytes], File()] = None):
|
||||
async def read_optional_bytes(p: Annotated[bytes | None, File()] = None):
|
||||
return {"file_size": len(p) if p else None}
|
||||
|
||||
|
||||
@app.post("/optional-uploadfile", operation_id="optional_uploadfile")
|
||||
async def read_optional_uploadfile(p: Annotated[Optional[UploadFile], File()] = None):
|
||||
async def read_optional_uploadfile(p: Annotated[UploadFile | None, File()] = None):
|
||||
return {"file_size": p.size if p else None}
|
||||
|
||||
|
||||
|
|
@ -82,14 +82,14 @@ def test_optional(path: str):
|
|||
|
||||
@app.post("/optional-bytes-alias", operation_id="optional_bytes_alias")
|
||||
async def read_optional_bytes_alias(
|
||||
p: Annotated[Optional[bytes], File(alias="p_alias")] = None,
|
||||
p: Annotated[bytes | None, File(alias="p_alias")] = None,
|
||||
):
|
||||
return {"file_size": len(p) if p else None}
|
||||
|
||||
|
||||
@app.post("/optional-uploadfile-alias", operation_id="optional_uploadfile_alias")
|
||||
async def read_optional_uploadfile_alias(
|
||||
p: Annotated[Optional[UploadFile], File(alias="p_alias")] = None,
|
||||
p: Annotated[UploadFile | None, File(alias="p_alias")] = None,
|
||||
):
|
||||
return {"file_size": p.size if p else None}
|
||||
|
||||
|
|
@ -170,7 +170,7 @@ def test_optional_alias_by_alias(path: str):
|
|||
"/optional-bytes-validation-alias", operation_id="optional_bytes_validation_alias"
|
||||
)
|
||||
def read_optional_bytes_validation_alias(
|
||||
p: Annotated[Optional[bytes], File(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[bytes | None, File(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"file_size": len(p) if p else None}
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ def read_optional_bytes_validation_alias(
|
|||
operation_id="optional_uploadfile_validation_alias",
|
||||
)
|
||||
def read_optional_uploadfile_validation_alias(
|
||||
p: Annotated[Optional[UploadFile], File(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[UploadFile | None, File(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"file_size": p.size if p else None}
|
||||
|
||||
|
|
@ -263,7 +263,7 @@ def test_optional_validation_alias_by_validation_alias(path: str):
|
|||
)
|
||||
def read_optional_bytes_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[bytes], File(alias="p_alias", validation_alias="p_val_alias")
|
||||
bytes | None, File(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"file_size": len(p) if p else None}
|
||||
|
|
@ -275,7 +275,7 @@ def read_optional_bytes_alias_and_validation_alias(
|
|||
)
|
||||
def read_optional_uploadfile_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[UploadFile], File(alias="p_alias", validation_alias="p_val_alias")
|
||||
UploadFile | None, File(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"file_size": p.size if p else None}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI, File, UploadFile
|
||||
|
|
@ -13,13 +13,13 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.post("/optional-list-bytes")
|
||||
async def read_optional_list_bytes(p: Annotated[Optional[list[bytes]], File()] = None):
|
||||
async def read_optional_list_bytes(p: Annotated[list[bytes] | None, File()] = None):
|
||||
return {"file_size": [len(file) for file in p] if p else None}
|
||||
|
||||
|
||||
@app.post("/optional-list-uploadfile")
|
||||
async def read_optional_list_uploadfile(
|
||||
p: Annotated[Optional[list[UploadFile]], File()] = None,
|
||||
p: Annotated[list[UploadFile] | None, File()] = None,
|
||||
):
|
||||
return {"file_size": [file.size for file in p] if p else None}
|
||||
|
||||
|
|
@ -87,14 +87,14 @@ def test_optional_list(path: str):
|
|||
|
||||
@app.post("/optional-list-bytes-alias")
|
||||
async def read_optional_list_bytes_alias(
|
||||
p: Annotated[Optional[list[bytes]], File(alias="p_alias")] = None,
|
||||
p: Annotated[list[bytes] | None, File(alias="p_alias")] = None,
|
||||
):
|
||||
return {"file_size": [len(file) for file in p] if p else None}
|
||||
|
||||
|
||||
@app.post("/optional-list-uploadfile-alias")
|
||||
async def read_optional_list_uploadfile_alias(
|
||||
p: Annotated[Optional[list[UploadFile]], File(alias="p_alias")] = None,
|
||||
p: Annotated[list[UploadFile] | None, File(alias="p_alias")] = None,
|
||||
):
|
||||
return {"file_size": [file.size for file in p] if p else None}
|
||||
|
||||
|
|
@ -176,16 +176,14 @@ def test_optional_list_alias_by_alias(path: str):
|
|||
|
||||
@app.post("/optional-list-bytes-validation-alias")
|
||||
def read_optional_list_bytes_validation_alias(
|
||||
p: Annotated[Optional[list[bytes]], File(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[list[bytes] | None, File(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"file_size": [len(file) for file in p] if p else None}
|
||||
|
||||
|
||||
@app.post("/optional-list-uploadfile-validation-alias")
|
||||
def read_optional_list_uploadfile_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[list[UploadFile]], File(validation_alias="p_val_alias")
|
||||
] = None,
|
||||
p: Annotated[list[UploadFile] | None, File(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"file_size": [file.size for file in p] if p else None}
|
||||
|
||||
|
|
@ -270,7 +268,7 @@ def test_optional_validation_alias_by_validation_alias(path: str):
|
|||
@app.post("/optional-list-bytes-alias-and-validation-alias")
|
||||
def read_optional_list_bytes_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[list[bytes]], File(alias="p_alias", validation_alias="p_val_alias")
|
||||
list[bytes] | None, File(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"file_size": [len(file) for file in p] if p else None}
|
||||
|
|
@ -279,7 +277,7 @@ def read_optional_list_bytes_alias_and_validation_alias(
|
|||
@app.post("/optional-list-uploadfile-alias-and-validation-alias")
|
||||
def read_optional_list_uploadfile_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[list[UploadFile]],
|
||||
list[UploadFile] | None,
|
||||
File(alias="p_alias", validation_alias="p_val_alias"),
|
||||
] = None,
|
||||
):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI, Form
|
||||
|
|
@ -15,13 +15,13 @@ app = FastAPI()
|
|||
|
||||
@app.post("/optional-list-str", operation_id="optional_list_str")
|
||||
async def read_optional_list_str(
|
||||
p: Annotated[Optional[list[str]], Form()] = None,
|
||||
p: Annotated[list[str] | None, Form()] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class FormModelOptionalListStr(BaseModel):
|
||||
p: Optional[list[str]] = None
|
||||
p: list[str] | None = None
|
||||
|
||||
|
||||
@app.post("/model-optional-list-str", operation_id="model_optional_list_str")
|
||||
|
|
@ -80,13 +80,13 @@ def test_optional_list_str(path: str):
|
|||
|
||||
@app.post("/optional-list-alias", operation_id="optional_list_alias")
|
||||
async def read_optional_list_alias(
|
||||
p: Annotated[Optional[list[str]], Form(alias="p_alias")] = None,
|
||||
p: Annotated[list[str] | None, Form(alias="p_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class FormModelOptionalListAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(None, alias="p_alias")
|
||||
p: list[str] | None = Field(None, alias="p_alias")
|
||||
|
||||
|
||||
@app.post("/model-optional-list-alias", operation_id="model_optional_list_alias")
|
||||
|
|
@ -163,13 +163,13 @@ def test_optional_list_alias_by_alias(path: str):
|
|||
"/optional-list-validation-alias", operation_id="optional_list_validation_alias"
|
||||
)
|
||||
def read_optional_list_validation_alias(
|
||||
p: Annotated[Optional[list[str]], Form(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[list[str] | None, Form(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class FormModelOptionalListValidationAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
|
||||
p: list[str] | None = Field(None, validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.post(
|
||||
|
|
@ -251,16 +251,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
|
|||
)
|
||||
def read_optional_list_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[list[str]], Form(alias="p_alias", validation_alias="p_val_alias")
|
||||
list[str] | None, Form(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class FormModelOptionalListAliasAndValidationAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(
|
||||
None, alias="p_alias", validation_alias="p_val_alias"
|
||||
)
|
||||
p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.post(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI, Form
|
||||
|
|
@ -14,12 +14,12 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.post("/optional-str", operation_id="optional_str")
|
||||
async def read_optional_str(p: Annotated[Optional[str], Form()] = None):
|
||||
async def read_optional_str(p: Annotated[str | None, Form()] = None):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class FormModelOptionalStr(BaseModel):
|
||||
p: Optional[str] = None
|
||||
p: str | None = None
|
||||
|
||||
|
||||
@app.post("/model-optional-str", operation_id="model_optional_str")
|
||||
|
|
@ -75,13 +75,13 @@ def test_optional_str(path: str):
|
|||
|
||||
@app.post("/optional-alias", operation_id="optional_alias")
|
||||
async def read_optional_alias(
|
||||
p: Annotated[Optional[str], Form(alias="p_alias")] = None,
|
||||
p: Annotated[str | None, Form(alias="p_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class FormModelOptionalAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias")
|
||||
p: str | None = Field(None, alias="p_alias")
|
||||
|
||||
|
||||
@app.post("/model-optional-alias", operation_id="model_optional_alias")
|
||||
|
|
@ -151,13 +151,13 @@ def test_optional_alias_by_alias(path: str):
|
|||
|
||||
@app.post("/optional-validation-alias", operation_id="optional_validation_alias")
|
||||
def read_optional_validation_alias(
|
||||
p: Annotated[Optional[str], Form(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[str | None, Form(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class FormModelOptionalValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.post(
|
||||
|
|
@ -238,14 +238,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
|
|||
)
|
||||
def read_optional_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[str], Form(alias="p_alias", validation_alias="p_val_alias")
|
||||
str | None, Form(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class FormModelOptionalAliasAndValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.post(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI, Header
|
||||
|
|
@ -14,13 +14,13 @@ app = FastAPI()
|
|||
|
||||
@app.get("/optional-list-str")
|
||||
async def read_optional_list_str(
|
||||
p: Annotated[Optional[list[str]], Header()] = None,
|
||||
p: Annotated[list[str] | None, Header()] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class HeaderModelOptionalListStr(BaseModel):
|
||||
p: Optional[list[str]] = None
|
||||
p: list[str] | None = None
|
||||
|
||||
|
||||
@app.get("/model-optional-list-str")
|
||||
|
|
@ -81,13 +81,13 @@ def test_optional_list_str(path: str):
|
|||
|
||||
@app.get("/optional-list-alias")
|
||||
async def read_optional_list_alias(
|
||||
p: Annotated[Optional[list[str]], Header(alias="p_alias")] = None,
|
||||
p: Annotated[list[str] | None, Header(alias="p_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class HeaderModelOptionalListAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(None, alias="p_alias")
|
||||
p: list[str] | None = Field(None, alias="p_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-list-alias")
|
||||
|
|
@ -162,13 +162,13 @@ def test_optional_list_alias_by_alias(path: str):
|
|||
|
||||
@app.get("/optional-list-validation-alias")
|
||||
def read_optional_list_validation_alias(
|
||||
p: Annotated[Optional[list[str]], Header(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[list[str] | None, Header(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class HeaderModelOptionalListValidationAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
|
||||
p: list[str] | None = Field(None, validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-list-validation-alias")
|
||||
|
|
@ -246,16 +246,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
|
|||
@app.get("/optional-list-alias-and-validation-alias")
|
||||
def read_optional_list_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[list[str]], Header(alias="p_alias", validation_alias="p_val_alias")
|
||||
list[str] | None, Header(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class HeaderModelOptionalListAliasAndValidationAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(
|
||||
None, alias="p_alias", validation_alias="p_val_alias"
|
||||
)
|
||||
p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-list-alias-and-validation-alias")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI, Header
|
||||
|
|
@ -13,12 +13,12 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.get("/optional-str")
|
||||
async def read_optional_str(p: Annotated[Optional[str], Header()] = None):
|
||||
async def read_optional_str(p: Annotated[str | None, Header()] = None):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class HeaderModelOptionalStr(BaseModel):
|
||||
p: Optional[str] = None
|
||||
p: str | None = None
|
||||
|
||||
|
||||
@app.get("/model-optional-str")
|
||||
|
|
@ -74,13 +74,13 @@ def test_optional_str(path: str):
|
|||
|
||||
@app.get("/optional-alias")
|
||||
async def read_optional_alias(
|
||||
p: Annotated[Optional[str], Header(alias="p_alias")] = None,
|
||||
p: Annotated[str | None, Header(alias="p_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class HeaderModelOptionalAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias")
|
||||
p: str | None = Field(None, alias="p_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-alias")
|
||||
|
|
@ -150,13 +150,13 @@ def test_optional_alias_by_alias(path: str):
|
|||
|
||||
@app.get("/optional-validation-alias")
|
||||
def read_optional_validation_alias(
|
||||
p: Annotated[Optional[str], Header(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[str | None, Header(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class HeaderModelOptionalValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-validation-alias")
|
||||
|
|
@ -232,14 +232,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
|
|||
@app.get("/optional-alias-and-validation-alias")
|
||||
def read_optional_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[str], Header(alias="p_alias", validation_alias="p_val_alias")
|
||||
str | None, Header(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class HeaderModelOptionalAliasAndValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-alias-and-validation-alias")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI, Query
|
||||
|
|
@ -14,13 +14,13 @@ app = FastAPI()
|
|||
|
||||
@app.get("/optional-list-str")
|
||||
async def read_optional_list_str(
|
||||
p: Annotated[Optional[list[str]], Query()] = None,
|
||||
p: Annotated[list[str] | None, Query()] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class QueryModelOptionalListStr(BaseModel):
|
||||
p: Optional[list[str]] = None
|
||||
p: list[str] | None = None
|
||||
|
||||
|
||||
@app.get("/model-optional-list-str")
|
||||
|
|
@ -81,13 +81,13 @@ def test_optional_list_str(path: str):
|
|||
|
||||
@app.get("/optional-list-alias")
|
||||
async def read_optional_list_alias(
|
||||
p: Annotated[Optional[list[str]], Query(alias="p_alias")] = None,
|
||||
p: Annotated[list[str] | None, Query(alias="p_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class QueryModelOptionalListAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(None, alias="p_alias")
|
||||
p: list[str] | None = Field(None, alias="p_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-list-alias")
|
||||
|
|
@ -162,13 +162,13 @@ def test_optional_list_alias_by_alias(path: str):
|
|||
|
||||
@app.get("/optional-list-validation-alias")
|
||||
def read_optional_list_validation_alias(
|
||||
p: Annotated[Optional[list[str]], Query(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[list[str] | None, Query(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class QueryModelOptionalListValidationAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
|
||||
p: list[str] | None = Field(None, validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-list-validation-alias")
|
||||
|
|
@ -244,16 +244,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
|
|||
@app.get("/optional-list-alias-and-validation-alias")
|
||||
def read_optional_list_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[list[str]], Query(alias="p_alias", validation_alias="p_val_alias")
|
||||
list[str] | None, Query(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class QueryModelOptionalListAliasAndValidationAlias(BaseModel):
|
||||
p: Optional[list[str]] = Field(
|
||||
None, alias="p_alias", validation_alias="p_val_alias"
|
||||
)
|
||||
p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-list-alias-and-validation-alias")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI, Query
|
||||
|
|
@ -13,12 +13,12 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.get("/optional-str")
|
||||
async def read_optional_str(p: Optional[str] = None):
|
||||
async def read_optional_str(p: str | None = None):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class QueryModelOptionalStr(BaseModel):
|
||||
p: Optional[str] = None
|
||||
p: str | None = None
|
||||
|
||||
|
||||
@app.get("/model-optional-str")
|
||||
|
|
@ -74,13 +74,13 @@ def test_optional_str(path: str):
|
|||
|
||||
@app.get("/optional-alias")
|
||||
async def read_optional_alias(
|
||||
p: Annotated[Optional[str], Query(alias="p_alias")] = None,
|
||||
p: Annotated[str | None, Query(alias="p_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class QueryModelOptionalAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias")
|
||||
p: str | None = Field(None, alias="p_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-alias")
|
||||
|
|
@ -150,13 +150,13 @@ def test_optional_alias_by_alias(path: str):
|
|||
|
||||
@app.get("/optional-validation-alias")
|
||||
def read_optional_validation_alias(
|
||||
p: Annotated[Optional[str], Query(validation_alias="p_val_alias")] = None,
|
||||
p: Annotated[str | None, Query(validation_alias="p_val_alias")] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class QueryModelOptionalValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-validation-alias")
|
||||
|
|
@ -232,14 +232,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
|
|||
@app.get("/optional-alias-and-validation-alias")
|
||||
def read_optional_alias_and_validation_alias(
|
||||
p: Annotated[
|
||||
Optional[str], Query(alias="p_alias", validation_alias="p_val_alias")
|
||||
str | None, Query(alias="p_alias", validation_alias="p_val_alias")
|
||||
] = None,
|
||||
):
|
||||
return {"p": p}
|
||||
|
||||
|
||||
class QueryModelOptionalAliasAndValidationAlias(BaseModel):
|
||||
p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
|
||||
|
||||
|
||||
@app.get("/model-optional-alias-and-validation-alias")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Union
|
||||
|
||||
from fastapi import Body, FastAPI, Query
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
|
@ -7,17 +5,17 @@ app = FastAPI()
|
|||
|
||||
|
||||
@app.get("/query")
|
||||
def read_query(q: Union[str, None]):
|
||||
def read_query(q: str | None):
|
||||
return q
|
||||
|
||||
|
||||
@app.get("/explicit-query")
|
||||
def read_explicit_query(q: Union[str, None] = Query()):
|
||||
def read_explicit_query(q: str | None = Query()):
|
||||
return q
|
||||
|
||||
|
||||
@app.post("/body-embed")
|
||||
def send_body_embed(b: Union[str, None] = Body(embed=True)):
|
||||
def send_body_embed(b: str | None = Body(embed=True)):
|
||||
return b
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Union
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI
|
||||
from fastapi.exceptions import FastAPIError, ResponseValidationError
|
||||
|
|
@ -216,7 +214,7 @@ def no_response_model_annotation_forward_ref_list_of_model() -> "list[User]":
|
|||
|
||||
@app.get(
|
||||
"/response_model_union-no_annotation-return_model1",
|
||||
response_model=Union[User, Item],
|
||||
response_model=User | Item,
|
||||
)
|
||||
def response_model_union_no_annotation_return_model1():
|
||||
return DBUser(name="John", surname="Doe", password_hash="secret")
|
||||
|
|
@ -224,19 +222,19 @@ def response_model_union_no_annotation_return_model1():
|
|||
|
||||
@app.get(
|
||||
"/response_model_union-no_annotation-return_model2",
|
||||
response_model=Union[User, Item],
|
||||
response_model=User | Item,
|
||||
)
|
||||
def response_model_union_no_annotation_return_model2():
|
||||
return Item(name="Foo", price=42.0)
|
||||
|
||||
|
||||
@app.get("/no_response_model-annotation_union-return_model1")
|
||||
def no_response_model_annotation_union_return_model1() -> Union[User, Item]:
|
||||
def no_response_model_annotation_union_return_model1() -> User | Item:
|
||||
return DBUser(name="John", surname="Doe", password_hash="secret")
|
||||
|
||||
|
||||
@app.get("/no_response_model-annotation_union-return_model2")
|
||||
def no_response_model_annotation_union_return_model2() -> Union[User, Item]:
|
||||
def no_response_model_annotation_union_return_model2() -> User | Item:
|
||||
return Item(name="Foo", price=42.0)
|
||||
|
||||
|
||||
|
|
@ -503,7 +501,7 @@ def test_invalid_response_model_field():
|
|||
with pytest.raises(FastAPIError) as e:
|
||||
|
||||
@app.get("/")
|
||||
def read_root() -> Union[Response, None]:
|
||||
def read_root() -> Response | None:
|
||||
return Response(content="Foo") # pragma: no cover
|
||||
|
||||
assert "valid Pydantic field type" in e.value.args[0]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
from collections.abc import AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Union
|
||||
|
||||
import pytest
|
||||
from fastapi import APIRouter, FastAPI, Request
|
||||
|
|
@ -176,7 +175,7 @@ def test_router_nested_lifespan_state_overriding_by_parent() -> None:
|
|||
@asynccontextmanager
|
||||
async def lifespan(
|
||||
app: FastAPI,
|
||||
) -> AsyncGenerator[dict[str, Union[str, bool]], None]:
|
||||
) -> AsyncGenerator[dict[str, str | bool], None]:
|
||||
yield {
|
||||
"app_specific": True,
|
||||
"overridden": "app",
|
||||
|
|
@ -185,7 +184,7 @@ def test_router_nested_lifespan_state_overriding_by_parent() -> None:
|
|||
@asynccontextmanager
|
||||
async def router_lifespan(
|
||||
app: FastAPI,
|
||||
) -> AsyncGenerator[dict[str, Union[str, bool]], None]:
|
||||
) -> AsyncGenerator[dict[str, str | bool], None]:
|
||||
yield {
|
||||
"router_specific": True,
|
||||
"overridden": "router", # should override parent
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Union
|
||||
|
||||
import pytest
|
||||
from fastapi import Body, Cookie, FastAPI, Header, Path, Query
|
||||
from fastapi.exceptions import FastAPIDeprecationWarning
|
||||
|
|
@ -117,7 +115,7 @@ def create_app():
|
|||
|
||||
@app.get("/query_example/")
|
||||
def query_example(
|
||||
data: Union[str, None] = Query(
|
||||
data: str | None = Query(
|
||||
default=None,
|
||||
example="query1",
|
||||
),
|
||||
|
|
@ -126,7 +124,7 @@ def create_app():
|
|||
|
||||
@app.get("/query_examples/")
|
||||
def query_examples(
|
||||
data: Union[str, None] = Query(
|
||||
data: str | None = Query(
|
||||
default=None,
|
||||
examples=["query1", "query2"],
|
||||
),
|
||||
|
|
@ -137,7 +135,7 @@ def create_app():
|
|||
|
||||
@app.get("/query_example_examples/")
|
||||
def query_example_examples(
|
||||
data: Union[str, None] = Query(
|
||||
data: str | None = Query(
|
||||
default=None,
|
||||
example="query_overridden",
|
||||
examples=["query1", "query2"],
|
||||
|
|
@ -149,7 +147,7 @@ def create_app():
|
|||
|
||||
@app.get("/header_example/")
|
||||
def header_example(
|
||||
data: Union[str, None] = Header(
|
||||
data: str | None = Header(
|
||||
default=None,
|
||||
example="header1",
|
||||
),
|
||||
|
|
@ -158,7 +156,7 @@ def create_app():
|
|||
|
||||
@app.get("/header_examples/")
|
||||
def header_examples(
|
||||
data: Union[str, None] = Header(
|
||||
data: str | None = Header(
|
||||
default=None,
|
||||
examples=[
|
||||
"header1",
|
||||
|
|
@ -172,7 +170,7 @@ def create_app():
|
|||
|
||||
@app.get("/header_example_examples/")
|
||||
def header_example_examples(
|
||||
data: Union[str, None] = Header(
|
||||
data: str | None = Header(
|
||||
default=None,
|
||||
example="header_overridden",
|
||||
examples=["header1", "header2"],
|
||||
|
|
@ -184,7 +182,7 @@ def create_app():
|
|||
|
||||
@app.get("/cookie_example/")
|
||||
def cookie_example(
|
||||
data: Union[str, None] = Cookie(
|
||||
data: str | None = Cookie(
|
||||
default=None,
|
||||
example="cookie1",
|
||||
),
|
||||
|
|
@ -193,7 +191,7 @@ def create_app():
|
|||
|
||||
@app.get("/cookie_examples/")
|
||||
def cookie_examples(
|
||||
data: Union[str, None] = Cookie(
|
||||
data: str | None = Cookie(
|
||||
default=None,
|
||||
examples=["cookie1", "cookie2"],
|
||||
),
|
||||
|
|
@ -204,7 +202,7 @@ def create_app():
|
|||
|
||||
@app.get("/cookie_example_examples/")
|
||||
def cookie_example_examples(
|
||||
data: Union[str, None] = Cookie(
|
||||
data: str | None = Cookie(
|
||||
default=None,
|
||||
example="cookie_overridden",
|
||||
examples=["cookie1", "cookie2"],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI, Security
|
||||
from fastapi.security import APIKeyCookie
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -15,7 +13,7 @@ class User(BaseModel):
|
|||
username: str
|
||||
|
||||
|
||||
def get_current_user(oauth_header: Optional[str] = Security(api_key)):
|
||||
def get_current_user(oauth_header: str | None = Security(api_key)):
|
||||
if oauth_header is None:
|
||||
return None
|
||||
user = User(username=oauth_header)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI, Security
|
||||
from fastapi.security import APIKeyHeader
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -15,7 +13,7 @@ class User(BaseModel):
|
|||
username: str
|
||||
|
||||
|
||||
def get_current_user(oauth_header: Optional[str] = Security(api_key)):
|
||||
def get_current_user(oauth_header: str | None = Security(api_key)):
|
||||
if oauth_header is None:
|
||||
return None
|
||||
user = User(username=oauth_header)
|
||||
|
|
@ -23,7 +21,7 @@ def get_current_user(oauth_header: Optional[str] = Security(api_key)):
|
|||
|
||||
|
||||
@app.get("/users/me")
|
||||
def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
|
||||
def read_current_user(current_user: User | None = Depends(get_current_user)):
|
||||
if current_user is None:
|
||||
return {"msg": "Create an account first"}
|
||||
return current_user
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI, Security
|
||||
from fastapi.security import APIKeyQuery
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -15,7 +13,7 @@ class User(BaseModel):
|
|||
username: str
|
||||
|
||||
|
||||
def get_current_user(oauth_header: Optional[str] = Security(api_key)):
|
||||
def get_current_user(oauth_header: str | None = Security(api_key)):
|
||||
if oauth_header is None:
|
||||
return None
|
||||
user = User(username=oauth_header)
|
||||
|
|
@ -23,7 +21,7 @@ def get_current_user(oauth_header: Optional[str] = Security(api_key)):
|
|||
|
||||
|
||||
@app.get("/users/me")
|
||||
def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
|
||||
def read_current_user(current_user: User | None = Depends(get_current_user)):
|
||||
if current_user is None:
|
||||
return {"msg": "Create an account first"}
|
||||
return current_user
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Security
|
||||
from fastapi.security.http import HTTPAuthorizationCredentials, HTTPBase
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -12,7 +10,7 @@ security = HTTPBase(scheme="Other", auto_error=False)
|
|||
|
||||
@app.get("/users/me")
|
||||
def read_current_user(
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Security(security),
|
||||
credentials: HTTPAuthorizationCredentials | None = Security(security),
|
||||
):
|
||||
if credentials is None:
|
||||
return {"msg": "Create an account first"}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from base64 import b64encode
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Security
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
|
|
@ -12,7 +11,7 @@ security = HTTPBasic(auto_error=False)
|
|||
|
||||
|
||||
@app.get("/users/me")
|
||||
def read_current_user(credentials: Optional[HTTPBasicCredentials] = Security(security)):
|
||||
def read_current_user(credentials: HTTPBasicCredentials | None = Security(security)):
|
||||
if credentials is None:
|
||||
return {"msg": "Create an account first"}
|
||||
return {"username": credentials.username, "password": credentials.password}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Security
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -12,7 +10,7 @@ security = HTTPBearer(auto_error=False)
|
|||
|
||||
@app.get("/users/me")
|
||||
def read_current_user(
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Security(security),
|
||||
credentials: HTTPAuthorizationCredentials | None = Security(security),
|
||||
):
|
||||
if credentials is None:
|
||||
return {"msg": "Create an account first"}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Security
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -12,7 +10,7 @@ security = HTTPDigest(auto_error=False)
|
|||
|
||||
@app.get("/users/me")
|
||||
def read_current_user(
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Security(security),
|
||||
credentials: HTTPAuthorizationCredentials | None = Security(security),
|
||||
):
|
||||
if credentials is None:
|
||||
return {"msg": "Create an account first"}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Security
|
||||
from fastapi.security import OAuth2AuthorizationCodeBearer
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -13,7 +11,7 @@ oauth2_scheme = OAuth2AuthorizationCodeBearer(
|
|||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(token: Optional[str] = Security(oauth2_scheme)):
|
||||
async def read_items(token: str | None = Security(oauth2_scheme)):
|
||||
return {"token": token}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Security
|
||||
from fastapi.security import OAuth2AuthorizationCodeBearer
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -16,7 +14,7 @@ oauth2_scheme = OAuth2AuthorizationCodeBearer(
|
|||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(token: Optional[str] = Security(oauth2_scheme)):
|
||||
async def read_items(token: str | None = Security(oauth2_scheme)):
|
||||
return {"token": token}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Ref: https://github.com/fastapi/fastapi/issues/14454
|
||||
|
||||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, FastAPI, Security
|
||||
from fastapi.security import OAuth2AuthorizationCodeBearer
|
||||
|
|
@ -46,13 +46,13 @@ router = APIRouter(dependencies=[Security(oauth2_scheme, scopes=["read"])])
|
|||
|
||||
|
||||
@router.get("/items/")
|
||||
async def read_items(token: Optional[str] = Depends(oauth2_scheme)):
|
||||
async def read_items(token: str | None = Depends(oauth2_scheme)):
|
||||
return {"token": token}
|
||||
|
||||
|
||||
@router.post("/items/")
|
||||
async def create_item(
|
||||
token: Optional[str] = Security(oauth2_scheme, scopes=["read", "write"]),
|
||||
token: str | None = Security(oauth2_scheme, scopes=["read", "write"]),
|
||||
):
|
||||
return {"token": token}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from fastapi import Depends, FastAPI, Security
|
||||
from fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict
|
||||
|
|
@ -24,7 +22,7 @@ class User(BaseModel):
|
|||
username: str
|
||||
|
||||
|
||||
def get_current_user(oauth_header: Optional[str] = Security(reusable_oauth2)):
|
||||
def get_current_user(oauth_header: str | None = Security(reusable_oauth2)):
|
||||
if oauth_header is None:
|
||||
return None
|
||||
user = User(username=oauth_header)
|
||||
|
|
@ -37,7 +35,7 @@ def login(form_data: OAuth2PasswordRequestFormStrict = Depends()):
|
|||
|
||||
|
||||
@app.get("/users/me")
|
||||
def read_users_me(current_user: Optional[User] = Depends(get_current_user)):
|
||||
def read_users_me(current_user: User | None = Depends(get_current_user)):
|
||||
if current_user is None:
|
||||
return {"msg": "Create an account first"}
|
||||
return current_user
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from fastapi import Depends, FastAPI, Security
|
||||
from fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict
|
||||
|
|
@ -25,7 +23,7 @@ class User(BaseModel):
|
|||
username: str
|
||||
|
||||
|
||||
def get_current_user(oauth_header: Optional[str] = Security(reusable_oauth2)):
|
||||
def get_current_user(oauth_header: str | None = Security(reusable_oauth2)):
|
||||
if oauth_header is None:
|
||||
return None
|
||||
user = User(username=oauth_header)
|
||||
|
|
@ -38,7 +36,7 @@ def login(form_data: OAuth2PasswordRequestFormStrict = Depends()):
|
|||
|
||||
|
||||
@app.get("/users/me")
|
||||
def read_users_me(current_user: Optional[User] = Depends(get_current_user)):
|
||||
def read_users_me(current_user: User | None = Depends(get_current_user)):
|
||||
if current_user is None:
|
||||
return {"msg": "Create an account first"}
|
||||
return current_user
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Security
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -11,7 +9,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token", auto_error=False)
|
|||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(token: Optional[str] = Security(oauth2_scheme)):
|
||||
async def read_items(token: str | None = Security(oauth2_scheme)):
|
||||
if token is None:
|
||||
return {"msg": "Create an account first"}
|
||||
return {"token": token}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Security
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -15,7 +13,7 @@ oauth2_scheme = OAuth2PasswordBearer(
|
|||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(token: Optional[str] = Security(oauth2_scheme)):
|
||||
async def read_items(token: str | None = Security(oauth2_scheme)):
|
||||
if token is None:
|
||||
return {"msg": "Create an account first"}
|
||||
return {"token": token}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI, Security
|
||||
from fastapi.security.open_id_connect_url import OpenIdConnect
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -15,7 +13,7 @@ class User(BaseModel):
|
|||
username: str
|
||||
|
||||
|
||||
def get_current_user(oauth_header: Optional[str] = Security(oid)):
|
||||
def get_current_user(oauth_header: str | None = Security(oid)):
|
||||
if oauth_header is None:
|
||||
return None
|
||||
user = User(username=oauth_header)
|
||||
|
|
@ -23,7 +21,7 @@ def get_current_user(oauth_header: Optional[str] = Security(oid)):
|
|||
|
||||
|
||||
@app.get("/users/me")
|
||||
def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
|
||||
def read_current_user(current_user: User | None = Depends(get_current_user)):
|
||||
if current_user is None:
|
||||
return {"msg": "Create an account first"}
|
||||
return current_user
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from pydantic import BaseModel
|
||||
|
|
@ -9,8 +7,8 @@ app = FastAPI()
|
|||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: Optional[float] = None
|
||||
owner_ids: Optional[list[int]] = None
|
||||
price: float | None = None
|
||||
owner_ids: list[int] | None = None
|
||||
|
||||
|
||||
@app.get("/items/valid", response_model=Item)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -12,8 +11,8 @@ app = FastAPI()
|
|||
class Item:
|
||||
name: str
|
||||
date: datetime
|
||||
price: Optional[float] = None
|
||||
owner_ids: Optional[list[int]] = None
|
||||
price: float | None = None
|
||||
owner_ids: list[int] | None = None
|
||||
|
||||
|
||||
@app.get("/items/valid", response_model=Item)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel, Field
|
||||
from starlette.testclient import TestClient
|
||||
|
|
@ -9,8 +7,8 @@ app = FastAPI()
|
|||
|
||||
class Item(BaseModel):
|
||||
name: str = Field(alias="aliased_name")
|
||||
price: Optional[float] = None
|
||||
owner_ids: Optional[list[int]] = None
|
||||
price: float | None = None
|
||||
owner_ids: list[int] | None = None
|
||||
|
||||
|
||||
@app.get("/items/valid", response_model=Item)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from pydantic import BaseModel
|
||||
|
|
@ -8,23 +6,23 @@ app = FastAPI()
|
|||
|
||||
|
||||
class SubModel(BaseModel):
|
||||
a: Optional[str] = "foo"
|
||||
a: str | None = "foo"
|
||||
|
||||
|
||||
class Model(BaseModel):
|
||||
x: Optional[int] = None
|
||||
x: int | None = None
|
||||
sub: SubModel
|
||||
|
||||
|
||||
class ModelSubclass(Model):
|
||||
y: int
|
||||
z: int = 0
|
||||
w: Optional[int] = None
|
||||
w: int | None = None
|
||||
|
||||
|
||||
class ModelDefaults(BaseModel):
|
||||
w: Optional[str] = None
|
||||
x: Optional[str] = None
|
||||
w: str | None = None
|
||||
x: str | None = None
|
||||
y: str = "y"
|
||||
z: str = "z"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -10,7 +8,7 @@ app = FastAPI()
|
|||
|
||||
class Invoice(BaseModel):
|
||||
id: str
|
||||
title: Optional[str] = None
|
||||
title: str | None = None
|
||||
customer: str
|
||||
total: float
|
||||
|
||||
|
|
@ -51,7 +49,7 @@ subrouter = APIRouter()
|
|||
|
||||
|
||||
@subrouter.post("/invoices/", callbacks=invoices_callback_router.routes)
|
||||
def create_invoice(invoice: Invoice, callback_url: Optional[HttpUrl] = None):
|
||||
def create_invoice(invoice: Invoice, callback_url: HttpUrl | None = None):
|
||||
"""
|
||||
Create an invoice.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional, Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -9,7 +7,7 @@ app = FastAPI()
|
|||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: Optional[str] = None
|
||||
name: str | None = None
|
||||
|
||||
|
||||
class OtherItem(BaseModel):
|
||||
|
|
@ -17,7 +15,7 @@ class OtherItem(BaseModel):
|
|||
|
||||
|
||||
@app.post("/items/")
|
||||
def save_union_body(item: Union[OtherItem, Item]):
|
||||
def save_union_body(item: OtherItem | Item):
|
||||
return {"item": item}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
from typing import Annotated, Any, Union
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
from pydantic import BaseModel, Field
|
||||
from typing_extensions import Literal
|
||||
|
||||
|
||||
def test_discriminator_pydantic_v2() -> None:
|
||||
|
|
@ -21,7 +20,7 @@ def test_discriminator_pydantic_v2() -> None:
|
|||
price: float
|
||||
|
||||
Item = Annotated[
|
||||
Union[Annotated[FirstItem, Tag("first")], Annotated[OtherItem, Tag("other")]],
|
||||
Annotated[FirstItem, Tag("first")] | Annotated[OtherItem, Tag("other")],
|
||||
Field(discriminator="value"),
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Ref: https://github.com/fastapi/fastapi/discussions/14495
|
||||
|
||||
from typing import Annotated, Union
|
||||
from typing import Annotated
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI
|
||||
|
|
@ -27,7 +27,7 @@ def client_fixture() -> TestClient:
|
|||
return v.get("pet_type", "")
|
||||
|
||||
Pet = Annotated[
|
||||
Union[Annotated[Cat, Tag("cat")], Annotated[Dog, Tag("dog")]],
|
||||
Annotated[Cat, Tag("cat")] | Annotated[Dog, Tag("dog")],
|
||||
Discriminator(get_pet_type),
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Union
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import FastAPI, Form
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -19,7 +19,7 @@ class CompanyForm(BaseModel):
|
|||
|
||||
|
||||
@app.post("/form-union/")
|
||||
def post_union_form(data: Annotated[Union[UserForm, CompanyForm], Form()]):
|
||||
def post_union_form(data: Annotated[UserForm | CompanyForm, Form()]):
|
||||
return {"received": data}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional, Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
|
@ -9,7 +7,7 @@ app = FastAPI()
|
|||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: Optional[str] = None
|
||||
name: str | None = None
|
||||
|
||||
|
||||
class ExtendedItem(Item):
|
||||
|
|
@ -17,7 +15,7 @@ class ExtendedItem(Item):
|
|||
|
||||
|
||||
@app.post("/items/")
|
||||
def save_union_different_body(item: Union[ExtendedItem, Item]):
|
||||
def save_union_different_body(item: ExtendedItem | Item):
|
||||
return {"item": item}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional, Union
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI
|
||||
from fastapi.exceptions import ResponseValidationError
|
||||
|
|
@ -11,8 +9,8 @@ app = FastAPI()
|
|||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: Optional[float] = None
|
||||
owner_ids: Optional[list[int]] = None
|
||||
price: float | None = None
|
||||
owner_ids: list[int] | None = None
|
||||
|
||||
|
||||
@app.get("/items/invalid", response_model=Item)
|
||||
|
|
@ -25,7 +23,7 @@ def get_invalid_none():
|
|||
return None
|
||||
|
||||
|
||||
@app.get("/items/validnone", response_model=Union[Item, None])
|
||||
@app.get("/items/validnone", response_model=Item | None)
|
||||
def get_valid_none(send_none: bool = False):
|
||||
if send_none:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI
|
||||
from fastapi.exceptions import ResponseValidationError
|
||||
|
|
@ -12,8 +10,8 @@ app = FastAPI()
|
|||
@dataclass
|
||||
class Item:
|
||||
name: str
|
||||
price: Optional[float] = None
|
||||
owner_ids: Optional[list[int]] = None
|
||||
price: float | None = None
|
||||
owner_ids: list[int] | None = None
|
||||
|
||||
|
||||
@app.get("/items/invalid", response_model=Item)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import sys
|
|||
|
||||
import pytest
|
||||
|
||||
needs_py39 = pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python3.9+")
|
||||
needs_py310 = pytest.mark.skipif(
|
||||
sys.version_info < (3, 10), reason="requires python3.10+"
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue