committed by
GitHub
164 changed files with 2289 additions and 4507 deletions
@ -7,7 +7,8 @@ on: |
|||
- synchronize |
|||
|
|||
env: |
|||
IS_FORK: ${{ github.event.pull_request.head.repo.full_name != github.repository }} |
|||
# Forks and Dependabot don't have access to secrets |
|||
HAS_SECRETS: ${{ secrets.PRE_COMMIT != '' }} |
|||
|
|||
jobs: |
|||
pre-commit: |
|||
@ -19,7 +20,7 @@ jobs: |
|||
run: echo "$GITHUB_CONTEXT" |
|||
- uses: actions/checkout@v5 |
|||
name: Checkout PR for own repo |
|||
if: env.IS_FORK == 'false' |
|||
if: env.HAS_SECRETS == 'true' |
|||
with: |
|||
# To be able to commit it needs to fetch the head of the branch, not the |
|||
# merge commit |
|||
@ -31,7 +32,7 @@ jobs: |
|||
# pre-commit lite ci needs the default checkout configs to work |
|||
- uses: actions/checkout@v5 |
|||
name: Checkout PR for fork |
|||
if: env.IS_FORK == 'true' |
|||
if: env.HAS_SECRETS == 'false' |
|||
with: |
|||
# To be able to commit it needs the head branch of the PR, the remote one |
|||
ref: ${{ github.event.pull_request.head.sha }} |
|||
@ -56,7 +57,7 @@ jobs: |
|||
run: uvx prek run --from-ref origin/${GITHUB_BASE_REF} --to-ref HEAD --show-diff-on-failure |
|||
continue-on-error: true |
|||
- name: Commit and push changes |
|||
if: env.IS_FORK == 'false' |
|||
if: env.HAS_SECRETS == 'true' |
|||
run: | |
|||
git config user.name "github-actions[bot]" |
|||
git config user.email "github-actions[bot]@users.noreply.github.com" |
|||
@ -68,7 +69,7 @@ jobs: |
|||
git push |
|||
fi |
|||
- uses: pre-commit-ci/[email protected] |
|||
if: env.IS_FORK == 'true' |
|||
if: env.HAS_SECRETS == 'false' |
|||
with: |
|||
msg: 🎨 Auto format |
|||
- name: Error out on pre-commit errors |
|||
|
|||
@ -22,21 +22,13 @@ Hier ist eine allgemeine Idee, wie die Modelle mit ihren Passwortfeldern aussehe |
|||
|
|||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *} |
|||
|
|||
/// info | Info |
|||
### Über `**user_in.model_dump()` { #about-user-in-model-dump } |
|||
|
|||
In Pydantic v1 hieß die Methode `.dict()`, in Pydantic v2 wurde sie <abbr title="veraltet, obsolet: Es soll nicht mehr verwendet werden">deprecatet</abbr> (aber weiterhin unterstützt) und in `.model_dump()` umbenannt. |
|||
|
|||
Die Beispiele hier verwenden `.dict()` für die Kompatibilität mit Pydantic v1, aber Sie sollten `.model_dump()` verwenden, wenn Sie Pydantic v2 verwenden können. |
|||
|
|||
/// |
|||
|
|||
### Über `**user_in.dict()` { #about-user-in-dict } |
|||
|
|||
#### Die `.dict()`-Methode von Pydantic { #pydantics-dict } |
|||
#### Pydantics `.model_dump()` { #pydantics-model-dump } |
|||
|
|||
`user_in` ist ein Pydantic-Modell der Klasse `UserIn`. |
|||
|
|||
Pydantic-Modelle haben eine `.dict()`-Methode, die ein <abbr title="Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr> mit den Daten des Modells zurückgibt. |
|||
Pydantic-Modelle haben eine `.model_dump()`-Methode, die ein <abbr title="Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr> mit den Daten des Modells zurückgibt. |
|||
|
|||
Wenn wir also ein Pydantic-Objekt `user_in` erstellen, etwa so: |
|||
|
|||
@ -47,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="[email protected] |
|||
und dann aufrufen: |
|||
|
|||
```Python |
|||
user_dict = user_in.dict() |
|||
user_dict = user_in.model_dump() |
|||
``` |
|||
|
|||
haben wir jetzt ein `dict` mit den Daten in der Variablen `user_dict` (es ist ein `dict` statt eines Pydantic-Modellobjekts). |
|||
@ -103,20 +95,20 @@ UserInDB( |
|||
|
|||
#### Ein Pydantic-Modell aus dem Inhalt eines anderen { #a-pydantic-model-from-the-contents-of-another } |
|||
|
|||
Da wir im obigen Beispiel `user_dict` von `user_in.dict()` bekommen haben, wäre dieser Code: |
|||
Da wir im obigen Beispiel `user_dict` von `user_in.model_dump()` bekommen haben, wäre dieser Code: |
|||
|
|||
```Python |
|||
user_dict = user_in.dict() |
|||
user_dict = user_in.model_dump() |
|||
UserInDB(**user_dict) |
|||
``` |
|||
|
|||
gleichwertig zu: |
|||
|
|||
```Python |
|||
UserInDB(**user_in.dict()) |
|||
UserInDB(**user_in.model_dump()) |
|||
``` |
|||
|
|||
... weil `user_in.dict()` ein `dict` ist, und dann lassen wir Python es „entpacken“, indem wir es an `UserInDB` mit vorangestelltem `**` übergeben. |
|||
... weil `user_in.model_dump()` ein `dict` ist, und dann lassen wir Python es „entpacken“, indem wir es an `UserInDB` mit vorangestelltem `**` übergeben. |
|||
|
|||
Auf diese Weise erhalten wir ein Pydantic-Modell aus den Daten eines anderen Pydantic-Modells. |
|||
|
|||
@ -125,7 +117,7 @@ Auf diese Weise erhalten wir ein Pydantic-Modell aus den Daten eines anderen Pyd |
|||
Und dann fügen wir das zusätzliche Schlüsselwort-Argument `hashed_password=hashed_password` hinzu, wie in: |
|||
|
|||
```Python |
|||
UserInDB(**user_in.dict(), hashed_password=hashed_password) |
|||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password) |
|||
``` |
|||
|
|||
... was so ist wie: |
|||
@ -180,7 +172,6 @@ Wenn Sie eine <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" |
|||
|
|||
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *} |
|||
|
|||
|
|||
### `Union` in Python 3.10 { #union-in-python-3-10 } |
|||
|
|||
In diesem Beispiel übergeben wir `Union[PlaneItem, CarItem]` als Wert des Arguments `response_model`. |
|||
@ -203,7 +194,6 @@ Dafür verwenden Sie Pythons Standard-`typing.List` (oder nur `list` in Python 3 |
|||
|
|||
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *} |
|||
|
|||
|
|||
## Response mit beliebigem `dict` { #response-with-arbitrary-dict } |
|||
|
|||
Sie können auch eine Response deklarieren, die ein beliebiges `dict` zurückgibt, indem Sie nur die Typen der Schlüssel und Werte ohne ein Pydantic-Modell deklarieren. |
|||
@ -214,7 +204,6 @@ In diesem Fall können Sie `typing.Dict` verwenden (oder nur `dict` in Python 3. |
|||
|
|||
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *} |
|||
|
|||
|
|||
## Zusammenfassung { #recap } |
|||
|
|||
Verwenden Sie gerne mehrere Pydantic-Modelle und vererben Sie je nach Bedarf. |
|||
|
|||
|
After Width: | Height: | Size: 187 KiB |
@ -22,22 +22,13 @@ Here's a general idea of how the models could look like with their password fiel |
|||
|
|||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *} |
|||
|
|||
### About `**user_in.model_dump()` { #about-user-in-model-dump } |
|||
|
|||
/// info |
|||
|
|||
In Pydantic v1 the method was called `.dict()`, it was deprecated (but still supported) in Pydantic v2, and renamed to `.model_dump()`. |
|||
|
|||
The examples here use `.dict()` for compatibility with Pydantic v1, but you should use `.model_dump()` instead if you can use Pydantic v2. |
|||
|
|||
/// |
|||
|
|||
### About `**user_in.dict()` { #about-user-in-dict } |
|||
|
|||
#### Pydantic's `.dict()` { #pydantics-dict } |
|||
#### Pydantic's `.model_dump()` { #pydantics-model-dump } |
|||
|
|||
`user_in` is a Pydantic model of class `UserIn`. |
|||
|
|||
Pydantic models have a `.dict()` method that returns a `dict` with the model's data. |
|||
Pydantic models have a `.model_dump()` method that returns a `dict` with the model's data. |
|||
|
|||
So, if we create a Pydantic object `user_in` like: |
|||
|
|||
@ -48,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="[email protected] |
|||
and then we call: |
|||
|
|||
```Python |
|||
user_dict = user_in.dict() |
|||
user_dict = user_in.model_dump() |
|||
``` |
|||
|
|||
we now have a `dict` with the data in the variable `user_dict` (it's a `dict` instead of a Pydantic model object). |
|||
@ -104,20 +95,20 @@ UserInDB( |
|||
|
|||
#### A Pydantic model from the contents of another { #a-pydantic-model-from-the-contents-of-another } |
|||
|
|||
As in the example above we got `user_dict` from `user_in.dict()`, this code: |
|||
As in the example above we got `user_dict` from `user_in.model_dump()`, this code: |
|||
|
|||
```Python |
|||
user_dict = user_in.dict() |
|||
user_dict = user_in.model_dump() |
|||
UserInDB(**user_dict) |
|||
``` |
|||
|
|||
would be equivalent to: |
|||
|
|||
```Python |
|||
UserInDB(**user_in.dict()) |
|||
UserInDB(**user_in.model_dump()) |
|||
``` |
|||
|
|||
...because `user_in.dict()` is a `dict`, and then we make Python "unpack" it by passing it to `UserInDB` prefixed with `**`. |
|||
...because `user_in.model_dump()` is a `dict`, and then we make Python "unpack" it by passing it to `UserInDB` prefixed with `**`. |
|||
|
|||
So, we get a Pydantic model from the data in another Pydantic model. |
|||
|
|||
@ -126,7 +117,7 @@ So, we get a Pydantic model from the data in another Pydantic model. |
|||
And then adding the extra keyword argument `hashed_password=hashed_password`, like in: |
|||
|
|||
```Python |
|||
UserInDB(**user_in.dict(), hashed_password=hashed_password) |
|||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password) |
|||
``` |
|||
|
|||
...ends up being like: |
|||
@ -181,7 +172,6 @@ When defining a <a href="https://docs.pydantic.dev/latest/concepts/types/#unions |
|||
|
|||
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *} |
|||
|
|||
|
|||
### `Union` in Python 3.10 { #union-in-python-3-10 } |
|||
|
|||
In this example we pass `Union[PlaneItem, CarItem]` as the value of the argument `response_model`. |
|||
@ -204,7 +194,6 @@ For that, use the standard Python `typing.List` (or just `list` in Python 3.9 an |
|||
|
|||
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *} |
|||
|
|||
|
|||
## Response with arbitrary `dict` { #response-with-arbitrary-dict } |
|||
|
|||
You can also declare a response using a plain arbitrary `dict`, declaring just the type of the keys and values, without using a Pydantic model. |
|||
@ -215,7 +204,6 @@ In this case, you can use `typing.Dict` (or just `dict` in Python 3.9 and above) |
|||
|
|||
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *} |
|||
|
|||
|
|||
## Recap { #recap } |
|||
|
|||
Use multiple Pydantic models and inherit freely for each case. |
|||
|
|||
@ -0,0 +1,47 @@ |
|||
### Target language |
|||
|
|||
Translate to Japanese (日本語). |
|||
|
|||
Language code: ja. |
|||
|
|||
### Grammar and tone |
|||
|
|||
1) Use polite, instructional Japanese (です/ます調). |
|||
2) Keep the tone concise and technical (match existing Japanese FastAPI docs). |
|||
|
|||
### Headings |
|||
|
|||
1) Follow the existing Japanese style: short, descriptive headings (often noun phrases), e.g. 「チェック」. |
|||
2) Do not add a trailing period at the end of headings. |
|||
|
|||
### Quotes |
|||
|
|||
1) Prefer Japanese corner brackets 「」 in normal prose when quoting a term. |
|||
2) Do not change quotes inside inline code, code blocks, URLs, or file paths. |
|||
|
|||
### Ellipsis |
|||
|
|||
1) Keep ellipsis style consistent with existing Japanese docs (commonly `...`). |
|||
2) Never change `...` in code, URLs, or CLI examples. |
|||
|
|||
### Preferred translations / glossary |
|||
|
|||
Use the following preferred translations when they apply in documentation prose: |
|||
|
|||
- request (HTTP): リクエスト |
|||
- response (HTTP): レスポンス |
|||
- path operation: パスオペレーション |
|||
- path operation function: パスオペレーション関数 |
|||
|
|||
### `///` admonitions |
|||
|
|||
1) Keep the admonition keyword in English (do not translate `note`, `tip`, etc.). |
|||
2) If a title is present, prefer these canonical titles: |
|||
|
|||
- `/// note | 備考` |
|||
- `/// note | 技術詳細` |
|||
- `/// tip | 豆知識` |
|||
- `/// warning | 注意` |
|||
- `/// info | 情報` |
|||
- `/// check | 確認` |
|||
- `/// danger | 警告` |
|||
@ -0,0 +1,51 @@ |
|||
### Target language |
|||
|
|||
Translate to Korean (한국어). |
|||
|
|||
Language code: ko. |
|||
|
|||
### Grammar and tone |
|||
|
|||
1) Use polite, instructional Korean (e.g. 합니다/하세요 style). |
|||
2) Keep the tone consistent with the existing Korean FastAPI docs. |
|||
|
|||
### Headings |
|||
|
|||
1) Follow existing Korean heading style (short, action-oriented headings like “확인하기”). |
|||
2) Do not add trailing punctuation to headings. |
|||
|
|||
### Quotes |
|||
|
|||
1) Keep quote style consistent with the existing Korean docs. |
|||
2) Never change quotes inside inline code, code blocks, URLs, or file paths. |
|||
|
|||
### Ellipsis |
|||
|
|||
1) Keep ellipsis style consistent with existing Korean docs (often `...`). |
|||
2) Never change `...` in code, URLs, or CLI examples. |
|||
|
|||
### Preferred translations / glossary |
|||
|
|||
Use the following preferred translations when they apply in documentation prose: |
|||
|
|||
- request (HTTP): 요청 |
|||
- response (HTTP): 응답 |
|||
- path operation: 경로 처리 |
|||
- path operation function: 경로 처리 함수 |
|||
|
|||
### `///` admonitions |
|||
|
|||
1) Keep the admonition keyword in English (do not translate `note`, `tip`, etc.). |
|||
2) If a title is present, prefer these canonical titles: |
|||
|
|||
- `/// note | 참고` |
|||
- `/// tip | 팁` |
|||
- `/// warning | 경고` |
|||
- `/// info | 정보` |
|||
- `/// danger | 위험` |
|||
- `/// note Technical Details | 기술 세부사항` |
|||
- `/// check | 확인` |
|||
Notes: |
|||
|
|||
- `details` blocks exist in Korean docs; keep `/// details` as-is and translate only the title after `|`. |
|||
- Example canonical title used: `/// details | 상세 설명` |
|||
@ -1,20 +0,0 @@ |
|||
from typing import Annotated |
|||
|
|||
from fastapi import Cookie, FastAPI |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class Cookies(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
session_id: str |
|||
fatebook_tracker: str | None = None |
|||
googall_tracker: str | None = None |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(cookies: Annotated[Cookies, Cookie()]): |
|||
return cookies |
|||
@ -1,20 +0,0 @@ |
|||
from typing import Annotated, Union |
|||
|
|||
from fastapi import Cookie, FastAPI |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class Cookies(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
session_id: str |
|||
fatebook_tracker: Union[str, None] = None |
|||
googall_tracker: Union[str, None] = None |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(cookies: Annotated[Cookies, Cookie()]): |
|||
return cookies |
|||
@ -1,18 +0,0 @@ |
|||
from fastapi import Cookie, FastAPI |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class Cookies(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
session_id: str |
|||
fatebook_tracker: str | None = None |
|||
googall_tracker: str | None = None |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(cookies: Cookies = Cookie()): |
|||
return cookies |
|||
@ -1,20 +0,0 @@ |
|||
from typing import Union |
|||
|
|||
from fastapi import Cookie, FastAPI |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class Cookies(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
session_id: str |
|||
fatebook_tracker: Union[str, None] = None |
|||
googall_tracker: Union[str, None] = None |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(cookies: Cookies = Cookie()): |
|||
return cookies |
|||
@ -1,22 +0,0 @@ |
|||
from typing import Annotated |
|||
|
|||
from fastapi import FastAPI, Header |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class CommonHeaders(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
host: str |
|||
save_data: bool |
|||
if_modified_since: str | None = None |
|||
traceparent: str | None = None |
|||
x_tag: list[str] = [] |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(headers: Annotated[CommonHeaders, Header()]): |
|||
return headers |
|||
@ -1,22 +0,0 @@ |
|||
from typing import Annotated, Union |
|||
|
|||
from fastapi import FastAPI, Header |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class CommonHeaders(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
host: str |
|||
save_data: bool |
|||
if_modified_since: Union[str, None] = None |
|||
traceparent: Union[str, None] = None |
|||
x_tag: list[str] = [] |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(headers: Annotated[CommonHeaders, Header()]): |
|||
return headers |
|||
@ -1,20 +0,0 @@ |
|||
from fastapi import FastAPI, Header |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class CommonHeaders(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
host: str |
|||
save_data: bool |
|||
if_modified_since: str | None = None |
|||
traceparent: str | None = None |
|||
x_tag: list[str] = [] |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(headers: CommonHeaders = Header()): |
|||
return headers |
|||
@ -1,22 +0,0 @@ |
|||
from typing import Union |
|||
|
|||
from fastapi import FastAPI, Header |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class CommonHeaders(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
host: str |
|||
save_data: bool |
|||
if_modified_since: Union[str, None] = None |
|||
traceparent: Union[str, None] = None |
|||
x_tag: list[str] = [] |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(headers: CommonHeaders = Header()): |
|||
return headers |
|||
@ -1,21 +0,0 @@ |
|||
from typing import Annotated, Literal |
|||
|
|||
from fastapi import FastAPI, Query |
|||
from pydantic import BaseModel, Field |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class FilterParams(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
limit: int = Field(100, gt=0, le=100) |
|||
offset: int = Field(0, ge=0) |
|||
order_by: Literal["created_at", "updated_at"] = "created_at" |
|||
tags: list[str] = [] |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(filter_query: Annotated[FilterParams, Query()]): |
|||
return filter_query |
|||
@ -1,21 +0,0 @@ |
|||
from typing import Annotated, Literal |
|||
|
|||
from fastapi import FastAPI, Query |
|||
from pydantic import BaseModel, Field |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class FilterParams(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
limit: int = Field(100, gt=0, le=100) |
|||
offset: int = Field(0, ge=0) |
|||
order_by: Literal["created_at", "updated_at"] = "created_at" |
|||
tags: list[str] = [] |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(filter_query: Annotated[FilterParams, Query()]): |
|||
return filter_query |
|||
@ -1,21 +0,0 @@ |
|||
from typing import Literal |
|||
|
|||
from fastapi import FastAPI, Query |
|||
from pydantic import BaseModel, Field |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class FilterParams(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
limit: int = Field(100, gt=0, le=100) |
|||
offset: int = Field(0, ge=0) |
|||
order_by: Literal["created_at", "updated_at"] = "created_at" |
|||
tags: list[str] = [] |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(filter_query: FilterParams = Query()): |
|||
return filter_query |
|||
@ -1,21 +0,0 @@ |
|||
from typing import Literal |
|||
|
|||
from fastapi import FastAPI, Query |
|||
from pydantic import BaseModel, Field |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class FilterParams(BaseModel): |
|||
class Config: |
|||
extra = "forbid" |
|||
|
|||
limit: int = Field(100, gt=0, le=100) |
|||
offset: int = Field(0, ge=0) |
|||
order_by: Literal["created_at", "updated_at"] = "created_at" |
|||
tags: list[str] = [] |
|||
|
|||
|
|||
@app.get("/items/") |
|||
async def read_items(filter_query: FilterParams = Query()): |
|||
return filter_query |
|||
@ -0,0 +1,98 @@ |
|||
import sys |
|||
|
|||
import pytest |
|||
|
|||
from tests.utils import skip_module_if_py_gte_314 |
|||
|
|||
if sys.version_info >= (3, 14): |
|||
skip_module_if_py_gte_314() |
|||
|
|||
from fastapi import FastAPI |
|||
from fastapi._compat.v1 import BaseModel |
|||
from fastapi.testclient import TestClient |
|||
|
|||
|
|||
def test_warns_pydantic_v1_model_in_endpoint_param() -> None: |
|||
class ParamModelV1(BaseModel): |
|||
name: str |
|||
|
|||
app = FastAPI() |
|||
|
|||
with pytest.warns( |
|||
DeprecationWarning, |
|||
match=r"pydantic\.v1 is deprecated.*Please update the param data:", |
|||
): |
|||
|
|||
@app.post("/param") |
|||
def endpoint(data: ParamModelV1): |
|||
return data |
|||
|
|||
client = TestClient(app) |
|||
response = client.post("/param", json={"name": "test"}) |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == {"name": "test"} |
|||
|
|||
|
|||
def test_warns_pydantic_v1_model_in_return_type() -> None: |
|||
class ReturnModelV1(BaseModel): |
|||
name: str |
|||
|
|||
app = FastAPI() |
|||
|
|||
with pytest.warns( |
|||
DeprecationWarning, |
|||
match=r"pydantic\.v1 is deprecated.*Please update the response model", |
|||
): |
|||
|
|||
@app.get("/return") |
|||
def endpoint() -> ReturnModelV1: |
|||
return ReturnModelV1(name="test") |
|||
|
|||
client = TestClient(app) |
|||
response = client.get("/return") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == {"name": "test"} |
|||
|
|||
|
|||
def test_warns_pydantic_v1_model_in_response_model() -> None: |
|||
class ResponseModelV1(BaseModel): |
|||
name: str |
|||
|
|||
app = FastAPI() |
|||
|
|||
with pytest.warns( |
|||
DeprecationWarning, |
|||
match=r"pydantic\.v1 is deprecated.*Please update the response model", |
|||
): |
|||
|
|||
@app.get("/response-model", response_model=ResponseModelV1) |
|||
def endpoint(): |
|||
return {"name": "test"} |
|||
|
|||
client = TestClient(app) |
|||
response = client.get("/response-model") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == {"name": "test"} |
|||
|
|||
|
|||
def test_warns_pydantic_v1_model_in_additional_responses_model() -> None: |
|||
class ErrorModelV1(BaseModel): |
|||
detail: str |
|||
|
|||
app = FastAPI() |
|||
|
|||
with pytest.warns( |
|||
DeprecationWarning, |
|||
match=r"pydantic\.v1 is deprecated.*In responses=\{\}, please update", |
|||
): |
|||
|
|||
@app.get( |
|||
"/responses", response_model=None, responses={400: {"model": ErrorModelV1}} |
|||
) |
|||
def endpoint(): |
|||
return {"ok": True} |
|||
|
|||
client = TestClient(app) |
|||
response = client.get("/responses") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == {"ok": True} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue