diff --git a/.github/DISCUSSION_TEMPLATE/questions.yml b/.github/DISCUSSION_TEMPLATE/questions.yml
index 3726b7d18..98424a341 100644
--- a/.github/DISCUSSION_TEMPLATE/questions.yml
+++ b/.github/DISCUSSION_TEMPLATE/questions.yml
@@ -123,6 +123,20 @@ body:
```
validations:
required: true
+ - type: input
+ id: pydantic-version
+ attributes:
+ label: Pydantic Version
+ description: |
+ What Pydantic version are you using?
+
+ You can find the Pydantic version with:
+
+ ```bash
+ python -c "import pydantic; print(pydantic.version.VERSION)"
+ ```
+ validations:
+ required: true
- type: input
id: python-version
attributes:
diff --git a/.github/actions/people/Dockerfile b/.github/actions/people/Dockerfile
index fa4197e6a..1455106bd 100644
--- a/.github/actions/people/Dockerfile
+++ b/.github/actions/people/Dockerfile
@@ -1,6 +1,6 @@
-FROM python:3.7
+FROM python:3.9
-RUN pip install httpx PyGithub "pydantic==1.5.1" "pyyaml>=5.3.1,<6.0.0"
+RUN pip install httpx PyGithub "pydantic==2.0.2" pydantic-settings "pyyaml>=5.3.1,<6.0.0"
COPY ./app /app
diff --git a/.github/actions/people/app/main.py b/.github/actions/people/app/main.py
index b11e3456d..cb6b229e8 100644
--- a/.github/actions/people/app/main.py
+++ b/.github/actions/people/app/main.py
@@ -9,7 +9,8 @@ from typing import Any, Container, DefaultDict, Dict, List, Set, Union
import httpx
import yaml
from github import Github
-from pydantic import BaseModel, BaseSettings, SecretStr
+from pydantic import BaseModel, SecretStr
+from pydantic_settings import BaseSettings
github_graphql_url = "https://api.github.com/graphql"
questions_category_id = "MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMyMDAxNDM0"
@@ -382,6 +383,7 @@ def get_graphql_response(
data = response.json()
if "errors" in data:
logging.error(f"Errors in response, after: {after}, category_id: {category_id}")
+ logging.error(data["errors"])
logging.error(response.text)
raise RuntimeError(response.text)
return data
@@ -389,7 +391,7 @@ def get_graphql_response(
def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=issues_query, after=after)
- graphql_response = IssuesResponse.parse_obj(data)
+ graphql_response = IssuesResponse.model_validate(data)
return graphql_response.data.repository.issues.edges
@@ -404,19 +406,19 @@ def get_graphql_question_discussion_edges(
after=after,
category_id=questions_category_id,
)
- graphql_response = DiscussionsResponse.parse_obj(data)
+ graphql_response = DiscussionsResponse.model_validate(data)
return graphql_response.data.repository.discussions.edges
def get_graphql_pr_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=prs_query, after=after)
- graphql_response = PRsResponse.parse_obj(data)
+ graphql_response = PRsResponse.model_validate(data)
return graphql_response.data.repository.pullRequests.edges
def get_graphql_sponsor_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=sponsors_query, after=after)
- graphql_response = SponsorsResponse.parse_obj(data)
+ graphql_response = SponsorsResponse.model_validate(data)
return graphql_response.data.user.sponsorshipsAsMaintainer.edges
@@ -607,7 +609,7 @@ def get_top_users(
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
settings = Settings()
- logging.info(f"Using config: {settings.json()}")
+ logging.info(f"Using config: {settings.model_dump_json()}")
g = Github(settings.input_token.get_secret_value())
repo = g.get_repo(settings.github_repository)
question_commentors, question_last_month_commentors, question_authors = get_experts(
diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml
index 19009447b..dedf23fb9 100644
--- a/.github/workflows/build-docs.yml
+++ b/.github/workflows/build-docs.yml
@@ -44,7 +44,7 @@ jobs:
id: cache
with:
path: ${{ env.pythonLocation }}
- key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v05
+ key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v06
- name: Install docs extras
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-docs.txt
@@ -80,7 +80,7 @@ jobs:
id: cache
with:
path: ${{ env.pythonLocation }}
- key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v05
+ key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v06
- name: Install docs extras
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-docs.txt
diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml
index 312d835af..dcd6d7107 100644
--- a/.github/workflows/deploy-docs.yml
+++ b/.github/workflows/deploy-docs.yml
@@ -29,21 +29,20 @@ jobs:
run_id: ${{ github.event.workflow_run.id }}
name: docs-site
path: ./site/
- - name: Deploy to Netlify
+ - name: Deploy to Cloudflare Pages
if: steps.download.outputs.found_artifact == 'true'
- id: netlify
- uses: nwtgck/actions-netlify@v2.0.0
+ id: deploy
+ uses: cloudflare/pages-action@v1
with:
- publish-dir: './site'
- production-deploy: ${{ github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'master' }}
- github-token: ${{ secrets.FASTAPI_PREVIEW_DOCS_NETLIFY }}
- enable-commit-comment: false
- env:
- NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
- NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
+ apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+ accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+ projectName: fastapitiangolo
+ directory: './site'
+ gitHubToken: ${{ secrets.GITHUB_TOKEN }}
+ branch: ${{ ( github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'master' && 'main' ) || ( github.event.workflow_run.head_sha ) }}
- name: Comment Deploy
- if: steps.netlify.outputs.deploy-url != ''
+ if: steps.deploy.outputs.url != ''
uses: ./.github/actions/comment-docs-preview-in-pr
with:
token: ${{ secrets.FASTAPI_PREVIEW_DOCS_COMMENT_DEPLOY }}
- deploy_url: "${{ steps.netlify.outputs.deploy-url }}"
+ deploy_url: "${{ steps.deploy.outputs.url }}"
diff --git a/.github/workflows/issue-manager.yml b/.github/workflows/issue-manager.yml
index 324623103..bb967fa11 100644
--- a/.github/workflows/issue-manager.yml
+++ b/.github/workflows/issue-manager.yml
@@ -19,6 +19,10 @@ jobs:
if: github.repository_owner == 'tiangolo'
runs-on: ubuntu-latest
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- uses: tiangolo/issue-manager@0.4.0
with:
token: ${{ secrets.FASTAPI_ISSUE_MANAGER }}
diff --git a/.github/workflows/label-approved.yml b/.github/workflows/label-approved.yml
index 976d29f74..2113c468a 100644
--- a/.github/workflows/label-approved.yml
+++ b/.github/workflows/label-approved.yml
@@ -9,6 +9,10 @@ jobs:
if: github.repository_owner == 'tiangolo'
runs-on: ubuntu-latest
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- uses: docker://tiangolo/label-approved:0.0.2
with:
token: ${{ secrets.FASTAPI_LABEL_APPROVED }}
diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml
index 1f7ac7b28..e38870f46 100644
--- a/.github/workflows/latest-changes.yml
+++ b/.github/workflows/latest-changes.yml
@@ -14,20 +14,24 @@ on:
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
- default: false
+ default: 'false'
jobs:
latest-changes:
runs-on: ubuntu-latest
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
with:
- # To allow latest-changes to commit to master
+ # To allow latest-changes to commit to the main branch
token: ${{ secrets.FASTAPI_LATEST_CHANGES }}
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
- if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
+ if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- uses: docker://tiangolo/latest-changes:0.0.3
diff --git a/.github/workflows/notify-translations.yml b/.github/workflows/notify-translations.yml
index 0926486e9..44ee83ec0 100644
--- a/.github/workflows/notify-translations.yml
+++ b/.github/workflows/notify-translations.yml
@@ -5,16 +5,29 @@ on:
types:
- labeled
- closed
+ workflow_dispatch:
+ inputs:
+ number:
+ description: PR number
+ required: true
+ debug_enabled:
+ description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
+ required: false
+ default: 'false'
jobs:
notify-translations:
runs-on: ubuntu-latest
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
- if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
+ if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- uses: ./.github/actions/notify-translations
diff --git a/.github/workflows/people.yml b/.github/workflows/people.yml
index dac526a6c..4480a1427 100644
--- a/.github/workflows/people.yml
+++ b/.github/workflows/people.yml
@@ -8,13 +8,17 @@ on:
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
- default: false
+ default: 'false'
jobs:
fastapi-people:
if: github.repository_owner == 'tiangolo'
runs-on: ubuntu-latest
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
# Ref: https://github.com/actions/runner/issues/2033
- name: Fix git safe.directory in container
@@ -22,7 +26,7 @@ jobs:
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
- if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
+ if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- uses: ./.github/actions/people
diff --git a/.github/workflows/smokeshow.yml b/.github/workflows/smokeshow.yml
index c6d894d9f..4e689d95c 100644
--- a/.github/workflows/smokeshow.yml
+++ b/.github/workflows/smokeshow.yml
@@ -14,6 +14,10 @@ jobs:
runs-on: ubuntu-latest
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- uses: actions/setup-python@v4
with:
python-version: '3.9'
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b95358d01..6a512a019 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -13,6 +13,10 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
@@ -25,7 +29,7 @@ jobs:
id: cache
with:
path: ${{ env.pythonLocation }}
- key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v03
+ key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v04
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-tests.txt
@@ -42,6 +46,10 @@ jobs:
pydantic-version: ["pydantic-v1", "pydantic-v2"]
fail-fast: false
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
@@ -54,7 +62,7 @@ jobs:
id: cache
with:
path: ${{ env.pythonLocation }}
- key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v03
+ key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v04
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-tests.txt
@@ -80,6 +88,10 @@ jobs:
needs: [test]
runs-on: ubuntu-latest
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
@@ -110,6 +122,10 @@ jobs:
- coverage-combine
runs-on: ubuntu-latest
steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:
diff --git a/README.md b/README.md
index f0e76c4b6..50f80ded6 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@ The key features are:
-
+
diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml
index ad738df35..a7f766d16 100644
--- a/docs/en/data/external_links.yml
+++ b/docs/en/data/external_links.yml
@@ -1,5 +1,9 @@
articles:
english:
+ - author: Adejumo Ridwan Suleiman
+ author_link: https://www.linkedin.com/in/adejumoridwan/
+ link: https://medium.com/python-in-plain-english/build-an-sms-spam-classifier-serverless-database-with-faunadb-and-fastapi-23dbb275bc5b
+ title: Build an SMS Spam Classifier Serverless Database with FaunaDB and FastAPI
- author: Raf Rasenberg
author_link: https://rafrasenberg.com/about/
link: https://rafrasenberg.com/fastapi-lambda/
diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml
index 56a886c68..3a68ba62b 100644
--- a/docs/en/data/github_sponsors.yml
+++ b/docs/en/data/github_sponsors.yml
@@ -2,6 +2,9 @@ sponsors:
- - login: cryptapi
avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4
url: https://github.com/cryptapi
+ - login: fern-api
+ avatarUrl: https://avatars.githubusercontent.com/u/102944815?v=4
+ url: https://github.com/fern-api
- login: nanram22
avatarUrl: https://avatars.githubusercontent.com/u/116367316?v=4
url: https://github.com/nanram22
@@ -29,15 +32,18 @@ sponsors:
- login: VincentParedes
avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4
url: https://github.com/VincentParedes
+- - login: arcticfly
+ avatarUrl: https://avatars.githubusercontent.com/u/41524992?u=03c88529a86cf51f7a380e890d84d84c71468848&v=4
+ url: https://github.com/arcticfly
- - login: getsentry
avatarUrl: https://avatars.githubusercontent.com/u/1396951?v=4
url: https://github.com/getsentry
-- - login: takashi-yoneya
+- - login: acsone
+ avatarUrl: https://avatars.githubusercontent.com/u/7601056?v=4
+ url: https://github.com/acsone
+ - login: takashi-yoneya
avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
url: https://github.com/takashi-yoneya
- - login: mercedes-benz
- avatarUrl: https://avatars.githubusercontent.com/u/34240465?v=4
- url: https://github.com/mercedes-benz
- login: xoflare
avatarUrl: https://avatars.githubusercontent.com/u/74335107?v=4
url: https://github.com/xoflare
@@ -50,12 +56,12 @@ sponsors:
- login: BoostryJP
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
url: https://github.com/BoostryJP
+ - login: jina-ai
+ avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4
+ url: https://github.com/jina-ai
- - login: HiredScore
avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4
url: https://github.com/HiredScore
- - login: petebachant
- avatarUrl: https://avatars.githubusercontent.com/u/4604869?u=b17a5a4ac82f77b7efff864d439e8068d2a36593&v=4
- url: https://github.com/petebachant
- login: Trivie
avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4
url: https://github.com/Trivie
@@ -74,9 +80,6 @@ sponsors:
- login: RodneyU215
avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4
url: https://github.com/RodneyU215
- - login: tizz98
- avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4
- url: https://github.com/tizz98
- login: americanair
avatarUrl: https://avatars.githubusercontent.com/u/12281813?v=4
url: https://github.com/americanair
@@ -92,11 +95,17 @@ sponsors:
- - login: indeedeng
avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4
url: https://github.com/indeedeng
+ - login: iguit0
+ avatarUrl: https://avatars.githubusercontent.com/u/12905770?u=63a1a96d1e6c27d85c4f946b84836599de047f65&v=4
+ url: https://github.com/iguit0
+ - login: JacobKochems
+ avatarUrl: https://avatars.githubusercontent.com/u/41692189?u=a75f62ddc0d060ee6233a91e19c433d2687b8eb6&v=4
+ url: https://github.com/JacobKochems
- - login: Kludex
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: samuelcolvin
- avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4
url: https://github.com/samuelcolvin
- login: jefftriplett
avatarUrl: https://avatars.githubusercontent.com/u/50527?u=af1ddfd50f6afd6d99f333ba2ac8d0a5b245ea74&v=4
@@ -104,9 +113,6 @@ sponsors:
- login: jstanden
avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4
url: https://github.com/jstanden
- - login: kamalgill
- avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4
- url: https://github.com/kamalgill
- login: dekoza
avatarUrl: https://avatars.githubusercontent.com/u/210980?u=c03c78a8ae1039b500dfe343665536ebc51979b2&v=4
url: https://github.com/dekoza
@@ -149,6 +155,9 @@ sponsors:
- login: zsinx6
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
url: https://github.com/zsinx6
+ - login: kennywakeland
+ avatarUrl: https://avatars.githubusercontent.com/u/3631417?u=7c8f743f1ae325dfadea7c62bbf1abd6a824fc55&v=4
+ url: https://github.com/kennywakeland
- login: aacayaco
avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4
url: https://github.com/aacayaco
@@ -194,9 +203,6 @@ sponsors:
- login: Shackelford-Arden
avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4
url: https://github.com/Shackelford-Arden
- - login: savannahostrowski
- avatarUrl: https://avatars.githubusercontent.com/u/8949415?u=c3177aa099fb2b8c36aeba349278b77f9a8df211&v=4
- url: https://github.com/savannahostrowski
- login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
url: https://github.com/wdwinslow
@@ -236,9 +242,6 @@ sponsors:
- login: ygorpontelo
avatarUrl: https://avatars.githubusercontent.com/u/32963605?u=35f7103f9c4c4c2589ae5737ee882e9375ef072e&v=4
url: https://github.com/ygorpontelo
- - login: AlrasheedA
- avatarUrl: https://avatars.githubusercontent.com/u/33544979?u=7fe66bf62b47682612b222e3e8f4795ef3be769b&v=4
- url: https://github.com/AlrasheedA
- login: ProteinQure
avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4
url: https://github.com/ProteinQure
@@ -281,9 +284,6 @@ sponsors:
- login: DelfinaCare
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
url: https://github.com/DelfinaCare
- - login: khoadaniel
- avatarUrl: https://avatars.githubusercontent.com/u/84840546?v=4
- url: https://github.com/khoadaniel
- login: osawa-koki
avatarUrl: https://avatars.githubusercontent.com/u/94336223?u=59c6fe6945bcbbaff87b2a794238671b060620d2&v=4
url: https://github.com/osawa-koki
@@ -327,14 +327,11 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4
url: https://github.com/browniebroke
- login: janfilips
- avatarUrl: https://avatars.githubusercontent.com/u/870699?u=96df18ad355e58b9397accc55f4eeb7a86e959b0&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/870699?u=80702ec63f14e675cd4cdcc6ce3821d2ed207fd7&v=4
url: https://github.com/janfilips
- login: WillHogan
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4
url: https://github.com/WillHogan
- - login: NateShoffner
- avatarUrl: https://avatars.githubusercontent.com/u/1712163?u=b43cc2fa3fd8bec54b7706e4b98b72543c7bfea8&v=4
- url: https://github.com/NateShoffner
- login: my3
avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4
url: https://github.com/my3
@@ -344,12 +341,6 @@ sponsors:
- login: cbonoz
avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4
url: https://github.com/cbonoz
- - login: Patechoc
- avatarUrl: https://avatars.githubusercontent.com/u/2376641?u=23b49e9eda04f078cb74fa3f93593aa6a57bb138&v=4
- url: https://github.com/Patechoc
- - login: larsvik
- avatarUrl: https://avatars.githubusercontent.com/u/3442226?v=4
- url: https://github.com/larsvik
- login: anthonycorletti
avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4
url: https://github.com/anthonycorletti
@@ -359,6 +350,9 @@ sponsors:
- login: Alisa-lisa
avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4
url: https://github.com/Alisa-lisa
+ - login: piotrgredowski
+ avatarUrl: https://avatars.githubusercontent.com/u/4294480?v=4
+ url: https://github.com/piotrgredowski
- login: danielunderwood
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
url: https://github.com/danielunderwood
@@ -383,6 +377,9 @@ sponsors:
- login: mattwelke
avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=80f02a799323b1472b389b836d95957c93a6d856&v=4
url: https://github.com/mattwelke
+ - login: harsh183
+ avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4
+ url: https://github.com/harsh183
- login: hcristea
avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=61d7a4fcf846983a4606788eac25e1c6c1209ba8&v=4
url: https://github.com/hcristea
@@ -428,9 +425,6 @@ sponsors:
- login: shuheng-liu
avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4
url: https://github.com/shuheng-liu
- - login: ghandic
- avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
- url: https://github.com/ghandic
- login: pers0n4
avatarUrl: https://avatars.githubusercontent.com/u/24864600?u=f211a13a7b572cbbd7779b9c8d8cb428cc7ba07e&v=4
url: https://github.com/pers0n4
@@ -458,9 +452,6 @@ sponsors:
- login: bnkc
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=527044d90b5ebb7f8dad517db5da1f45253b774b&v=4
url: https://github.com/bnkc
- - login: devbruce
- avatarUrl: https://avatars.githubusercontent.com/u/35563380?u=ca4e811ac7f7b3eb1600fa63285119fcdee01188&v=4
- url: https://github.com/devbruce
- login: declon
avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4
url: https://github.com/declon
@@ -476,6 +467,9 @@ sponsors:
- login: ArtyomVancyan
avatarUrl: https://avatars.githubusercontent.com/u/44609997?v=4
url: https://github.com/ArtyomVancyan
+ - login: josehenriqueroveda
+ avatarUrl: https://avatars.githubusercontent.com/u/46685746?u=2e672057a7dbe1dba47e57c378fc0cac336022eb&v=4
+ url: https://github.com/josehenriqueroveda
- login: hgalytoby
avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=f4888c2c54929bd86eed0d3971d09fcb306e5088&v=4
url: https://github.com/hgalytoby
@@ -485,27 +479,36 @@ sponsors:
- login: conservative-dude
avatarUrl: https://avatars.githubusercontent.com/u/55538308?u=f250c44942ea6e73a6bd90739b381c470c192c11&v=4
url: https://github.com/conservative-dude
- - login: leo-jp-edwards
- avatarUrl: https://avatars.githubusercontent.com/u/58213433?u=2c128e8b0794b7a66211cd7d8ebe05db20b7e9c0&v=4
- url: https://github.com/leo-jp-edwards
- login: 0417taehyun
avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4
url: https://github.com/0417taehyun
- - login: ssbarnea
avatarUrl: https://avatars.githubusercontent.com/u/102495?u=b4bf6818deefe59952ac22fec6ed8c76de1b8f7c&v=4
url: https://github.com/ssbarnea
- - login: tomast1337
- avatarUrl: https://avatars.githubusercontent.com/u/15125899?u=2c2f2907012d820499e2c43632389184923513fe&v=4
- url: https://github.com/tomast1337
+ - login: Patechoc
+ avatarUrl: https://avatars.githubusercontent.com/u/2376641?u=23b49e9eda04f078cb74fa3f93593aa6a57bb138&v=4
+ url: https://github.com/Patechoc
+ - login: LanceMoe
+ avatarUrl: https://avatars.githubusercontent.com/u/18505474?u=7fd3ead4364bdf215b6d75cb122b3811c391ef6b&v=4
+ url: https://github.com/LanceMoe
- login: sadikkuzu
avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=d179c06bb9f65c4167fcab118526819f8e0dac17&v=4
url: https://github.com/sadikkuzu
- login: ruizdiazever
avatarUrl: https://avatars.githubusercontent.com/u/29817086?u=2df54af55663d246e3a4dc8273711c37f1adb117&v=4
url: https://github.com/ruizdiazever
+ - login: samnimoh
+ avatarUrl: https://avatars.githubusercontent.com/u/33413170?u=147bc516be6cb647b28d7e3b3fea3a018a331145&v=4
+ url: https://github.com/samnimoh
- login: danburonline
avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4
url: https://github.com/danburonline
+ - login: iharshgor
+ avatarUrl: https://avatars.githubusercontent.com/u/35490011?u=2dea054476e752d9e92c9d71a9a7cc919b1c2f8e&v=4
+ url: https://github.com/iharshgor
- login: rwxd
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4
url: https://github.com/rwxd
+ - login: ThomasPalma1
+ avatarUrl: https://avatars.githubusercontent.com/u/66331874?u=5763f7402d784ba189b60d704ff5849b4d0a63fb&v=4
+ url: https://github.com/ThomasPalma1
diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml
index dd2dbe5ea..89d189564 100644
--- a/docs/en/data/people.yml
+++ b/docs/en/data/people.yml
@@ -1,16 +1,16 @@
maintainers:
- login: tiangolo
- answers: 1844
- prs: 430
+ answers: 1849
+ prs: 466
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4
url: https://github.com/tiangolo
experts:
- login: Kludex
- count: 434
+ count: 463
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: dmontagu
- count: 237
+ count: 239
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
url: https://github.com/dmontagu
- login: Mause
@@ -25,34 +25,34 @@ experts:
count: 193
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT
-- login: euri10
- count: 152
- avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
- url: https://github.com/euri10
- login: jgould22
- count: 139
+ count: 157
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
+- login: euri10
+ count: 153
+ avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
+ url: https://github.com/euri10
- login: phy25
count: 126
- avatarUrl: https://avatars.githubusercontent.com/u/331403?u=191cd73f0c936497c8d1931a217bb3039d050265&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4
url: https://github.com/phy25
- login: iudeen
- count: 118
+ count: 121
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: raphaelauv
count: 83
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
url: https://github.com/raphaelauv
-- login: ghandic
- count: 71
- avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
- url: https://github.com/ghandic
- login: ArcLightSlavik
count: 71
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
url: https://github.com/ArcLightSlavik
+- login: ghandic
+ count: 71
+ avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
+ url: https://github.com/ghandic
- login: falkben
count: 57
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=ad9838e089058c9e5a0bab94c0eec7cc181e0cd0&v=4
@@ -61,10 +61,10 @@ experts:
count: 49
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
url: https://github.com/sm-Fifteen
-- login: adriangb
+- login: insomnes
count: 45
- avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4
- url: https://github.com/adriangb
+ avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
+ url: https://github.com/insomnes
- login: yinziyan1206
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
@@ -73,22 +73,22 @@ experts:
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
url: https://github.com/acidjunk
-- login: insomnes
- count: 45
- avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
- url: https://github.com/insomnes
- login: Dustyposa
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
url: https://github.com/Dustyposa
-- login: odiseo0
- count: 43
- avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=2da05dab6cc8e1ade557801634760a56e4101796&v=4
- url: https://github.com/odiseo0
+- login: adriangb
+ count: 44
+ avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4
+ url: https://github.com/adriangb
- login: frankie567
count: 43
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
url: https://github.com/frankie567
+- login: odiseo0
+ count: 43
+ avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4
+ url: https://github.com/odiseo0
- login: includeamin
count: 40
avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
@@ -97,14 +97,14 @@ experts:
count: 37
avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4
url: https://github.com/STeveShary
-- login: chbndrhnns
- count: 35
- avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
- url: https://github.com/chbndrhnns
- login: krishnardt
count: 35
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
url: https://github.com/krishnardt
+- login: chbndrhnns
+ count: 35
+ avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
+ url: https://github.com/chbndrhnns
- login: panla
count: 32
avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4
@@ -121,38 +121,38 @@ experts:
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes
+- login: acnebs
+ count: 23
+ avatarUrl: https://avatars.githubusercontent.com/u/9054108?v=4
+ url: https://github.com/acnebs
- login: SirTelemak
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
url: https://github.com/SirTelemak
-- login: acnebs
- count: 22
- avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4
- url: https://github.com/acnebs
- login: rafsaf
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
url: https://github.com/rafsaf
-- login: chris-allnutt
+- login: n8sty
count: 20
- avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4
- url: https://github.com/chris-allnutt
+ avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
+ url: https://github.com/n8sty
- login: nsidnev
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4
url: https://github.com/nsidnev
-- login: n8sty
+- login: chris-allnutt
+ count: 20
+ avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4
+ url: https://github.com/chris-allnutt
+- login: zoliknemet
count: 18
- avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
- url: https://github.com/n8sty
+ avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4
+ url: https://github.com/zoliknemet
- login: retnikt
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4
url: https://github.com/retnikt
-- login: zoliknemet
- count: 18
- avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4
- url: https://github.com/zoliknemet
- login: Hultner
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
@@ -198,38 +198,30 @@ experts:
avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
url: https://github.com/jorgerpo
last_month_active:
-- login: jgould22
- count: 15
- avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
- url: https://github.com/jgould22
- login: Kludex
- count: 13
+ count: 24
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
-- login: abhint
- count: 5
- avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=b5d219277b4d001ac26fb8be357fddd88c29d51b&v=4
- url: https://github.com/abhint
-- login: chrisK824
- count: 4
- avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4
- url: https://github.com/chrisK824
+- login: jgould22
+ count: 17
+ avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
+ url: https://github.com/jgould22
- login: arjwilliams
- count: 3
+ count: 8
avatarUrl: https://avatars.githubusercontent.com/u/22227620?v=4
url: https://github.com/arjwilliams
-- login: wu-clan
- count: 3
- avatarUrl: https://avatars.githubusercontent.com/u/52145145?u=f8c9e5c8c259d248e1683fedf5027b4ee08a0967&v=4
- url: https://github.com/wu-clan
- login: Ahmed-Abdou14
- count: 3
- avatarUrl: https://avatars.githubusercontent.com/u/104530599?u=d1e1c064d57c3ad5b6481716928da840f6d5a492&v=4
+ count: 4
+ avatarUrl: https://avatars.githubusercontent.com/u/104530599?u=05365b155a1ff911532e8be316acfad2e0736f98&v=4
url: https://github.com/Ahmed-Abdou14
-- login: esrefzeki
+- login: iudeen
count: 3
- avatarUrl: https://avatars.githubusercontent.com/u/54935247?u=193cf5a169ca05fc54995a4dceabc82c7dc6e5ea&v=4
- url: https://github.com/esrefzeki
+ avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
+ url: https://github.com/iudeen
+- login: mikeedjones
+ count: 3
+ avatarUrl: https://avatars.githubusercontent.com/u/4087139?u=cc4a242896ac2fcf88a53acfaf190d0fe0a1f0c9&v=4
+ url: https://github.com/mikeedjones
top_contributors:
- login: waynerv
count: 25
@@ -240,7 +232,7 @@ top_contributors:
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
url: https://github.com/tokusumi
- login: Kludex
- count: 20
+ count: 21
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: jaystone776
@@ -264,7 +256,7 @@ top_contributors:
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
url: https://github.com/mariacamilagl
- login: Smlep
- count: 10
+ count: 11
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
url: https://github.com/Smlep
- login: Serrones
@@ -287,6 +279,10 @@ top_contributors:
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4
url: https://github.com/Alexandrhub
+- login: NinaHwang
+ count: 6
+ avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=eee6bfe9224c71193025ab7477f4f96ceaa05c62&v=4
+ url: https://github.com/NinaHwang
- login: batlopes
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
@@ -297,7 +293,7 @@ top_contributors:
url: https://github.com/wshayes
- login: samuelcolvin
count: 5
- avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4
url: https://github.com/samuelcolvin
- login: SwftAlpc
count: 5
@@ -311,10 +307,6 @@ top_contributors:
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4
url: https://github.com/ComicShrimp
-- login: NinaHwang
- count: 5
- avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=eee6bfe9224c71193025ab7477f4f96ceaa05c62&v=4
- url: https://github.com/NinaHwang
- login: jekirl
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4
@@ -335,10 +327,18 @@ top_contributors:
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/3360631?u=5fa1f475ad784d64eb9666bdd43cc4d285dcc773&v=4
url: https://github.com/hitrust
+- login: JulianMaurin
+ count: 4
+ avatarUrl: https://avatars.githubusercontent.com/u/63545168?u=b7d15ac865268cbefc2d739e2f23d9aeeac1a622&v=4
+ url: https://github.com/JulianMaurin
- login: lsglucas
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas
+- login: iudeen
+ count: 4
+ avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
+ url: https://github.com/iudeen
- login: axel584
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4
@@ -349,7 +349,7 @@ top_contributors:
url: https://github.com/ivan-abc
top_reviewers:
- login: Kludex
- count: 122
+ count: 136
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: BilalAlpaslan
@@ -357,7 +357,7 @@ top_reviewers:
avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
url: https://github.com/BilalAlpaslan
- login: yezz123
- count: 77
+ count: 78
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=d7062cbc6eb7671d5dc9cc0e32a24ae335e0f225&v=4
url: https://github.com/yezz123
- login: tokusumi
@@ -372,20 +372,20 @@ top_reviewers:
count: 47
avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4
url: https://github.com/Laineyzhang55
+- login: iudeen
+ count: 46
+ avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
+ url: https://github.com/iudeen
- login: ycd
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
url: https://github.com/ycd
-- login: iudeen
- count: 44
- avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
- url: https://github.com/iudeen
- login: cikay
count: 41
avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4
url: https://github.com/cikay
- login: Xewus
- count: 35
+ count: 38
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
url: https://github.com/Xewus
- login: JarroVGIT
@@ -412,6 +412,10 @@ top_reviewers:
count: 26
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas
+- login: LorhanSohaky
+ count: 24
+ avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
+ url: https://github.com/LorhanSohaky
- login: Ryandaydev
count: 24
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=809f3d1074d04bbc28012a7f17f06ea56f5bd71a&v=4
@@ -420,10 +424,6 @@ top_reviewers:
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
url: https://github.com/dmontagu
-- login: LorhanSohaky
- count: 23
- avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
- url: https://github.com/LorhanSohaky
- login: rjNemo
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
@@ -434,7 +434,7 @@ top_reviewers:
url: https://github.com/hard-coders
- login: odiseo0
count: 20
- avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=2da05dab6cc8e1ade557801634760a56e4101796&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4
url: https://github.com/odiseo0
- login: 0417taehyun
count: 19
@@ -456,6 +456,10 @@ top_reviewers:
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
url: https://github.com/SwftAlpc
+- login: axel584
+ count: 16
+ avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4
+ url: https://github.com/axel584
- login: DevDae
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/87962045?u=08e10fa516e844934f4b3fc7c38b33c61697e4a1&v=4
@@ -488,10 +492,6 @@ top_reviewers:
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4
url: https://github.com/RunningIkkyu
-- login: axel584
- count: 12
- avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4
- url: https://github.com/axel584
- login: ivan-abc
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/36765187?u=c6e0ba571c1ccb6db9d94e62e4b8b5eda811a870&v=4
@@ -500,6 +500,10 @@ top_reviewers:
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=789927ee09cfabd752d3bd554fa6baf4850d2777&v=4
url: https://github.com/solomein-sv
+- login: wdh99
+ count: 11
+ avatarUrl: https://avatars.githubusercontent.com/u/108172295?u=8a8fb95d5afe3e0fa33257b2aecae88d436249eb&v=4
+ url: https://github.com/wdh99
- login: mariacamilagl
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
@@ -540,7 +544,3 @@ top_reviewers:
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4
url: https://github.com/bezaca
-- login: oandersonmagalhaes
- count: 9
- avatarUrl: https://avatars.githubusercontent.com/u/83456692?v=4
- url: https://github.com/oandersonmagalhaes
diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml
index 33d57c873..53cdb9bad 100644
--- a/docs/en/data/sponsors.yml
+++ b/docs/en/data/sponsors.yml
@@ -7,7 +7,7 @@ gold:
img: https://fastapi.tiangolo.com/img/sponsors/platform-sh.png
- url: https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge
title: Fern | SDKs and API docs
- img: https://fastapi.tiangolo.com/img/sponsors/fern.png
+ img: https://fastapi.tiangolo.com/img/sponsors/fern.svg
silver:
- url: https://www.deta.sh/?ref=fastapi
title: The launchpad for all your (team's) ideas
diff --git a/docs/en/docs/advanced/generate-clients.md b/docs/en/docs/advanced/generate-clients.md
index f62c0b57c..3fed48b0b 100644
--- a/docs/en/docs/advanced/generate-clients.md
+++ b/docs/en/docs/advanced/generate-clients.md
@@ -12,6 +12,11 @@ A common tool is openapi-typescript-codegen .
+Another option you could consider for several languages is Fern .
+
+!!! info
+ Fern is also a FastAPI sponsor. 😎🎉
+
## Generate a TypeScript Frontend Client
Let's start with a simple FastAPI application:
diff --git a/docs/en/docs/alternatives.md b/docs/en/docs/alternatives.md
index 0f074ccf3..a777ddb98 100644
--- a/docs/en/docs/alternatives.md
+++ b/docs/en/docs/alternatives.md
@@ -119,6 +119,8 @@ That's why when talking about version 2.0 it's common to say "Swagger", and for
These two were chosen for being fairly popular and stable, but doing a quick search, you could find dozens of additional alternative user interfaces for OpenAPI (that you can use with **FastAPI**).
+ For example, you could try Fern which is also a FastAPI sponsor. 😎🎉
+
### Flask REST frameworks
There are several Flask REST frameworks, but after investing the time and work into investigating them, I found that many are discontinued or abandoned, with several standing issues that made them unfit.
diff --git a/docs/en/docs/contributing.md b/docs/en/docs/contributing.md
index f968489ae..cfdb607d7 100644
--- a/docs/en/docs/contributing.md
+++ b/docs/en/docs/contributing.md
@@ -126,7 +126,7 @@ And if you update that local FastAPI source code when you run that Python file a
That way, you don't have to "install" your local version to be able to test every change.
!!! note "Technical Details"
- This only happens when you install using this included `requiements.txt` instead of installing `pip install fastapi` directly.
+ This only happens when you install using this included `requirements.txt` instead of installing `pip install fastapi` directly.
That is because inside of the `requirements.txt` file, the local version of FastAPI is marked to be installed in "editable" mode, with the `-e` option.
diff --git a/docs/en/docs/img/sponsors/fern-banner.svg b/docs/en/docs/img/sponsors/fern-banner.svg
new file mode 100644
index 000000000..e05ccc3a4
--- /dev/null
+++ b/docs/en/docs/img/sponsors/fern-banner.svg
@@ -0,0 +1 @@
+
diff --git a/docs/en/docs/img/sponsors/fern.svg b/docs/en/docs/img/sponsors/fern.svg
new file mode 100644
index 000000000..ad3842fe0
--- /dev/null
+++ b/docs/en/docs/img/sponsors/fern.svg
@@ -0,0 +1 @@
+
diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md
index 4addb83cc..723f338a9 100644
--- a/docs/en/docs/release-notes.md
+++ b/docs/en/docs/release-notes.md
@@ -2,8 +2,52 @@
## Latest Changes
+* ✏️ Fix typo in deprecation warnings in `fastapi/params.py`. PR [#9854](https://github.com/tiangolo/fastapi/pull/9854) by [@russbiggs](https://github.com/russbiggs).
+* ✏️ Fix typo in release notes. PR [#9835](https://github.com/tiangolo/fastapi/pull/9835) by [@francisbergin](https://github.com/francisbergin).
+* ✏️ Fix typos in comments on internal code in `fastapi/concurrency.py` and `fastapi/routing.py`. PR [#9590](https://github.com/tiangolo/fastapi/pull/9590) by [@ElliottLarsen](https://github.com/ElliottLarsen).
+* 📝 Add external article: Build an SMS Spam Classifier Serverless Database with FaunaDB and FastAPI. PR [#9847](https://github.com/tiangolo/fastapi/pull/9847) by [@adejumoridwan](https://github.com/adejumoridwan).
+* 📝 Fix typo in `docs/en/docs/contributing.md`. PR [#9878](https://github.com/tiangolo/fastapi/pull/9878) by [@VicenteMerino](https://github.com/VicenteMerino).
+* 📝 Fix code highlighting in `docs/en/docs/tutorial/bigger-applications.md`. PR [#9806](https://github.com/tiangolo/fastapi/pull/9806) by [@theonlykingpin](https://github.com/theonlykingpin).
+* 🌐 Add Russian translation for `docs/ru/docs/tutorial/dependencies/global-dependencies.md`. PR [#9970](https://github.com/tiangolo/fastapi/pull/9970) by [@dudyaosuplayer](https://github.com/dudyaosuplayer).
+* 🌐 Add Urdu translation for `docs/ur/docs/benchmarks.md`. PR [#9974](https://github.com/tiangolo/fastapi/pull/9974) by [@AhsanSheraz](https://github.com/AhsanSheraz).
+* ⬆ Bump mypy from 1.4.0 to 1.4.1. PR [#9756](https://github.com/tiangolo/fastapi/pull/9756) by [@dependabot[bot]](https://github.com/apps/dependabot).
+* ⬆ Bump mkdocs-material from 9.1.17 to 9.1.21. PR [#9960](https://github.com/tiangolo/fastapi/pull/9960) by [@dependabot[bot]](https://github.com/apps/dependabot).
+
+## 0.101.0
+
+### Features
+
+* ✨ Enable Pydantic's serialization mode for responses, add support for Pydantic's `computed_field`, better OpenAPI for response models, proper required attributes, better generated clients. PR [#10011](https://github.com/tiangolo/fastapi/pull/10011) by [@tiangolo](https://github.com/tiangolo).
+
+### Refactors
+
+* ✅ Fix tests for compatibility with pydantic 2.1.1. PR [#9943](https://github.com/tiangolo/fastapi/pull/9943) by [@dmontagu](https://github.com/dmontagu).
+* ✅ Fix test error in Windows for `jsonable_encoder`. PR [#9840](https://github.com/tiangolo/fastapi/pull/9840) by [@iudeen](https://github.com/iudeen).
+
+### Upgrades
+
+* 📌 Do not allow Pydantic 2.1.0 that breaks (require 2.1.1). PR [#10012](https://github.com/tiangolo/fastapi/pull/10012) by [@tiangolo](https://github.com/tiangolo).
+
+### Translations
+
+* 🌐 Add Russian translation for `docs/ru/docs/tutorial/security/index.md`. PR [#9963](https://github.com/tiangolo/fastapi/pull/9963) by [@eVery1337](https://github.com/eVery1337).
* 🌐 Remove Vietnamese note about missing translation. PR [#9957](https://github.com/tiangolo/fastapi/pull/9957) by [@tiangolo](https://github.com/tiangolo).
+### Internal
+
+* 👷 Add GitHub Actions step dump context to debug external failures. PR [#10008](https://github.com/tiangolo/fastapi/pull/10008) by [@tiangolo](https://github.com/tiangolo).
+* 🔧 Restore MkDocs Material pin after the fix. PR [#10001](https://github.com/tiangolo/fastapi/pull/10001) by [@tiangolo](https://github.com/tiangolo).
+* 🔧 Update the Question template to ask for the Pydantic version. PR [#10000](https://github.com/tiangolo/fastapi/pull/10000) by [@tiangolo](https://github.com/tiangolo).
+* 📍 Update MkDocs Material dependencies. PR [#9986](https://github.com/tiangolo/fastapi/pull/9986) by [@tiangolo](https://github.com/tiangolo).
+* 👥 Update FastAPI People. PR [#9999](https://github.com/tiangolo/fastapi/pull/9999) by [@tiangolo](https://github.com/tiangolo).
+* 🐳 Update Dockerfile with compatibility versions, to upgrade later. PR [#9998](https://github.com/tiangolo/fastapi/pull/9998) by [@tiangolo](https://github.com/tiangolo).
+* ➕ Add pydantic-settings to FastAPI People dependencies. PR [#9988](https://github.com/tiangolo/fastapi/pull/9988) by [@tiangolo](https://github.com/tiangolo).
+* ♻️ Update FastAPI People logic with new Pydantic. PR [#9985](https://github.com/tiangolo/fastapi/pull/9985) by [@tiangolo](https://github.com/tiangolo).
+* 🍱 Update sponsors, Fern badge. PR [#9982](https://github.com/tiangolo/fastapi/pull/9982) by [@tiangolo](https://github.com/tiangolo).
+* 👷 Deploy docs to Cloudflare Pages. PR [#9978](https://github.com/tiangolo/fastapi/pull/9978) by [@tiangolo](https://github.com/tiangolo).
+* 🔧 Update sponsor Fern. PR [#9979](https://github.com/tiangolo/fastapi/pull/9979) by [@tiangolo](https://github.com/tiangolo).
+* 👷 Update CI debug mode with Tmate. PR [#9977](https://github.com/tiangolo/fastapi/pull/9977) by [@tiangolo](https://github.com/tiangolo).
+
## 0.100.1
### Fixes
@@ -66,7 +110,7 @@ A command line tool that will **process your code** and update most of the thing
### Pydantic v1
-**This version of FastAPI still supports Pydantic v1**. And although Pydantic v1 will be deprecated at some point, ti will still be supported for a while.
+**This version of FastAPI still supports Pydantic v1**. And although Pydantic v1 will be deprecated at some point, it will still be supported for a while.
This means that you can install the new Pydantic v2, and if something fails, you can install Pydantic v1 while you fix any problems you might have, but having the latest FastAPI.
diff --git a/docs/en/docs/tutorial/bigger-applications.md b/docs/en/docs/tutorial/bigger-applications.md
index daa7353a2..26d26475f 100644
--- a/docs/en/docs/tutorial/bigger-applications.md
+++ b/docs/en/docs/tutorial/bigger-applications.md
@@ -377,7 +377,7 @@ The `router` from `users` would overwrite the one from `items` and we wouldn't b
So, to be able to use both of them in the same file, we import the submodules directly:
-```Python hl_lines="4"
+```Python hl_lines="5"
{!../../../docs_src/bigger_applications/app/main.py!}
```
diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html
index fcd1704b9..7e6c0f763 100644
--- a/docs/en/overrides/main.html
+++ b/docs/en/overrides/main.html
@@ -37,7 +37,7 @@
diff --git a/docs/ru/docs/tutorial/dependencies/global-dependencies.md b/docs/ru/docs/tutorial/dependencies/global-dependencies.md
new file mode 100644
index 000000000..870d42cf5
--- /dev/null
+++ b/docs/ru/docs/tutorial/dependencies/global-dependencies.md
@@ -0,0 +1,34 @@
+# Глобальные зависимости
+
+Для некоторых типов приложений может потребоваться добавить зависимости ко всему приложению.
+
+Подобно тому, как вы можете [добавлять зависимости через параметр `dependencies` в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, вы можете добавлять зависимости сразу ко всему `FastAPI` приложению.
+
+В этом случае они будут применяться ко всем *операциям пути* в приложении:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/dependencies/tutorial012_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/dependencies/tutorial012_an.py!}
+ ```
+
+=== "Python 3.6 non-Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать 'Annotated' версию, если это возможно.
+
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/dependencies/tutorial012.py!}
+ ```
+
+Все способы [добавления зависимостей в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения.
+
+## Зависимости для групп *операций пути*
+
+Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр dependencies для целой группы *операций пути*.
diff --git a/docs/ru/docs/tutorial/security/index.md b/docs/ru/docs/tutorial/security/index.md
new file mode 100644
index 000000000..d5fe4e76f
--- /dev/null
+++ b/docs/ru/docs/tutorial/security/index.md
@@ -0,0 +1,101 @@
+# Настройка авторизации
+
+Существует множество способов обеспечения безопасности, аутентификации и авторизации.
+
+Обычно эта тема является достаточно сложной и трудной.
+
+Во многих фреймворках и системах только работа с определением доступов к приложению и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять более 50% от всего написанного кода).
+
+**FastAPI** предоставляет несколько инструментов, которые помогут вам настроить **Авторизацию** легко, быстро, стандартным способом, без необходимости изучать все её тонкости.
+
+Но сначала давайте рассмотрим некоторые небольшие концепции.
+
+## Куда-то торопишься?
+
+Если вам не нужна информация о каких-либо из следующих терминов и вам просто нужно добавить защиту с аутентификацией на основе логина и пароля *прямо сейчас*, переходите к следующим главам.
+
+## OAuth2
+
+OAuth2 - это протокол, который определяет несколько способов обработки аутентификации и авторизации.
+
+Он довольно обширен и охватывает несколько сложных вариантов использования.
+
+OAuth2 включает в себя способы аутентификации с использованием "третьей стороны".
+
+Это то, что используют под собой все кнопки "вход с помощью Facebook, Google, Twitter, GitHub" на страницах авторизации.
+
+### OAuth 1
+
+Ранее использовался протокол OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые описания того, как шифровать сообщение.
+
+В настоящее время он не очень популярен и не используется.
+
+OAuth2 не указывает, как шифровать сообщение, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS.
+
+!!! tip "Подсказка"
+ В разделе **Развертывание** вы увидите [как настроить протокол HTTPS бесплатно, используя Traefik и Let's Encrypt.](https://fastapi.tiangolo.com/ru/deployment/https/)
+
+
+## OpenID Connect
+
+OpenID Connect - это еще один протокол, основанный на **OAuth2**.
+
+Он просто расширяет OAuth2, уточняя некоторые вещи, не имеющие однозначного определения в OAuth2, в попытке сделать его более совместимым.
+
+Например, для входа в Google используется OpenID Connect (который под собой использует OAuth2).
+
+Но вход в Facebook не поддерживает OpenID Connect. У него есть собственная вариация OAuth2.
+
+### OpenID (не "OpenID Connect")
+
+Также ранее использовался стандарт "OpenID", который пытался решить ту же проблему, что и **OpenID Connect**, но не был основан на OAuth2.
+
+Таким образом, это была полноценная дополнительная система.
+
+В настоящее время не очень популярен и не используется.
+
+## OpenAPI
+
+OpenAPI (ранее известный как Swagger) - это открытая спецификация для создания API (в настоящее время является частью Linux Foundation).
+
+**FastAPI** основан на **OpenAPI**.
+
+Это то, что делает возможным наличие множества автоматических интерактивных интерфейсов документирования, сгенерированного кода и т.д.
+
+В OpenAPI есть способ использовать несколько "схем" безопасности.
+
+Таким образом, вы можете воспользоваться преимуществами Всех этих стандартных инструментов, включая интерактивные системы документирования.
+
+OpenAPI может использовать следующие схемы авторизации:
+
+* `apiKey`: уникальный идентификатор для приложения, который может быть получен из:
+ * Параметров запроса.
+ * Заголовка.
+ * Cookies.
+* `http`: стандартные системы аутентификации по протоколу HTTP, включая:
+ * `bearer`: заголовок `Authorization` со значением `Bearer {уникальный токен}`. Это унаследовано от OAuth2.
+ * Базовая аутентификация по протоколу HTTP.
+ * HTTP Digest и т.д.
+* `oauth2`: все способы обеспечения безопасности OAuth2 называемые "потоки" (англ. "flows").
+ * Некоторые из этих "потоков" подходят для реализации аутентификации через сторонний сервис использующий OAuth 2.0 (например, Google, Facebook, Twitter, GitHub и т.д.):
+ * `implicit`
+ * `clientCredentials`
+ * `authorizationCode`
+ * Но есть один конкретный "поток", который может быть идеально использован для обработки аутентификации непосредственно в том же приложении:
+ * `password`: в некоторых следующих главах будут рассмотрены примеры этого.
+* `openIdConnect`: способ определить, как автоматически обнаруживать данные аутентификации OAuth2.
+ * Это автоматическое обнаружение определено в спецификации OpenID Connect.
+
+
+!!! tip "Подсказка"
+ Интеграция сторонних сервисов для аутентификации/авторизации таких как Google, Facebook, Twitter, GitHub и т.д. осуществляется достаточно легко.
+
+ Самой сложной проблемой является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжелую работу за вас.
+
+## Преимущества **FastAPI**
+
+Fast API предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности.
+
+В следующих главах вы увидите, как обезопасить свой API, используя инструменты, предоставляемые **FastAPI**.
+
+И вы также увидите, как он автоматически интегрируется в систему интерактивной документации.
diff --git a/docs/ur/docs/benchmarks.md b/docs/ur/docs/benchmarks.md
new file mode 100644
index 000000000..9fc793e6f
--- /dev/null
+++ b/docs/ur/docs/benchmarks.md
@@ -0,0 +1,52 @@
+# بینچ مارکس
+
+انڈیپنڈنٹ ٹیک امپور بینچ مارک **FASTAPI** Uvicorn کے تحت چلنے والی ایپلی کیشنز کو ایک تیز رفتار Python فریم ورک میں سے ایک ، صرف Starlette اور Uvicorn کے نیچے ( FASTAPI کے ذریعہ اندرونی طور پر استعمال کیا جاتا ہے ) (*)
+
+لیکن جب بینچ مارک اور موازنہ کی جانچ پڑتال کرتے ہو تو آپ کو مندرجہ ذیل بات ذہن میں رکھنی چاہئے.
+
+## بینچ مارک اور رفتار
+
+جب آپ بینچ مارک کی جانچ کرتے ہیں تو ، مساوی کے مقابلے میں مختلف اقسام کے متعدد اوزار دیکھنا عام ہے.
+
+خاص طور پر ، Uvicorn, Starlette اور FastAPI کو دیکھنے کے لئے ( بہت سے دوسرے ٹولز ) کے ساتھ موازنہ کیا گیا.
+
+ٹول کے ذریعہ حل ہونے والا آسان مسئلہ ، اس کی بہتر کارکردگی ہوگی. اور زیادہ تر بینچ مارک ٹول کے ذریعہ فراہم کردہ اضافی خصوصیات کی جانچ نہیں کرتے ہیں.
+
+درجہ بندی کی طرح ہے:
+
+
+
+
+ Uvicorn :
+
+ بہترین کارکردگی ہوگی، کیونکہ اس میں سرور کے علاوہ زیادہ اضافی کوڈ نہیں ہے۔
+ آپ براہ راست Uvicorn میں درخواست نہیں لکھیں گے۔ اس کا مطلب یہ ہوگا کہ آپ کے کوڈ میں کم و بیش، کم از کم، Starlette (یا FastAPI ) کی طرف سے فراہم کردہ تمام کوڈ شامل کرنا ہوں گے۔ اور اگر آپ نے ایسا کیا تو، آپ کی حتمی ایپلیکیشن کا وہی اوور ہیڈ ہوگا جیسا کہ ایک فریم ورک استعمال کرنے اور آپ کے ایپ کوڈ اور کیڑے کو کم سے کم کرنا۔
+ اگر آپ Uvicorn کا موازنہ کر رہے ہیں تو اس کا موازنہ Daphne، Hypercorn، uWSGI وغیرہ ایپلیکیشن سرورز سے کریں۔
+
+
+
+ Starlette :
+
+ Uvicorn کے بعد اگلی بہترین کارکردگی ہوگی۔ درحقیقت، Starlette چلانے کے لیے Uvicorn کا استعمال کرتی ہے۔ لہذا، یہ شاید زیادہ کوڈ پر عمل درآمد کرکے Uvicorn سے "سست" ہوسکتا ہے۔
+ لیکن یہ آپ کو آسان ویب ایپلیکیشنز بنانے کے لیے ٹولز فراہم کرتا ہے، راستوں پر مبنی روٹنگ کے ساتھ، وغیرہ۔
+ اگر آپ سٹارلیٹ کا موازنہ کر رہے ہیں تو اس کا موازنہ Sanic، Flask، Django وغیرہ سے کریں۔ ویب فریم ورکس (یا مائیکرو فریم ورکس)
+
+
+
+ FastAPI :
+
+ جس طرح سے Uvicorn Starlette کا استعمال کرتا ہے اور اس سے تیز نہیں ہو سکتا، Starlette FastAPI کا استعمال کرتا ہے، اس لیے یہ اس سے تیز نہیں ہو سکتا۔
+ Starlette FastAPI کے اوپری حصے میں مزید خصوصیات فراہم کرتا ہے۔ وہ خصوصیات جن کی آپ کو APIs بناتے وقت تقریباً ہمیشہ ضرورت ہوتی ہے، جیسے ڈیٹا کی توثیق اور سیریلائزیشن۔ اور اسے استعمال کرنے سے، آپ کو خودکار دستاویزات مفت میں مل جاتی ہیں (خودکار دستاویزات چلنے والی ایپلی کیشنز میں اوور ہیڈ کو بھی شامل نہیں کرتی ہیں، یہ اسٹارٹ اپ پر تیار ہوتی ہیں)۔
+ اگر آپ نے FastAPI کا استعمال نہیں کیا ہے اور Starlette کو براہ راست استعمال کیا ہے (یا کوئی دوسرا ٹول، جیسے Sanic، Flask، Responder، وغیرہ) آپ کو تمام ڈیٹا کی توثیق اور سیریلائزیشن کو خود نافذ کرنا ہوگا۔ لہذا، آپ کی حتمی ایپلیکیشن اب بھی وہی اوور ہیڈ ہوگی جیسا کہ اسے FastAPI کا استعمال کرتے ہوئے بنایا گیا تھا۔ اور بہت سے معاملات میں، یہ ڈیٹا کی توثیق اور سیریلائزیشن ایپلی کیشنز میں لکھے گئے کوڈ کی سب سے بڑی مقدار ہے۔
+ لہذا، FastAPI کا استعمال کرکے آپ ترقیاتی وقت، Bugs، کوڈ کی لائنوں کی بچت کر رہے ہیں، اور شاید آپ کو وہی کارکردگی (یا بہتر) ملے گی اگر آپ اسے استعمال نہیں کرتے (جیسا کہ آپ کو یہ سب اپنے کوڈ میں لاگو کرنا ہوگا۔ )
+ اگر آپ FastAPI کا موازنہ کر رہے ہیں، تو اس کا موازنہ ویب ایپلیکیشن فریم ورک (یا ٹولز کے سیٹ) سے کریں جو ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات فراہم کرتا ہے، جیسے Flask-apispec، NestJS، Molten، وغیرہ۔ مربوط خودکار ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات کے ساتھ فریم ورک۔
+
+
diff --git a/docs/ur/mkdocs.yml b/docs/ur/mkdocs.yml
new file mode 100644
index 000000000..de18856f4
--- /dev/null
+++ b/docs/ur/mkdocs.yml
@@ -0,0 +1 @@
+INHERIT: ../en/mkdocs.yml
diff --git a/fastapi/__init__.py b/fastapi/__init__.py
index 7dfeca0d4..c113ac1fd 100644
--- a/fastapi/__init__.py
+++ b/fastapi/__init__.py
@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
-__version__ = "0.100.1"
+__version__ = "0.101.0"
from starlette import status as status
diff --git a/fastapi/concurrency.py b/fastapi/concurrency.py
index 31b878d5d..754061c86 100644
--- a/fastapi/concurrency.py
+++ b/fastapi/concurrency.py
@@ -19,7 +19,7 @@ async def contextmanager_in_threadpool(
) -> AsyncGenerator[_T, None]:
# blocking __exit__ from running waiting on a free thread
# can create race conditions/deadlocks if the context manager itself
- # has it's own internal pool (e.g. a database connection pool)
+ # has its own internal pool (e.g. a database connection pool)
# to avoid this we let __exit__ run without a capacity limit
# since we're creating a new limiter for each call, any non-zero limit
# works (1 is arbitrary)
diff --git a/fastapi/params.py b/fastapi/params.py
index 30af5713e..2d8100650 100644
--- a/fastapi/params.py
+++ b/fastapi/params.py
@@ -69,7 +69,7 @@ class Param(FieldInfo):
self.deprecated = deprecated
if example is not _Unset:
warnings.warn(
- "`example` has been depreacated, please use `examples` instead",
+ "`example` has been deprecated, please use `examples` instead",
category=DeprecationWarning,
stacklevel=4,
)
@@ -98,7 +98,7 @@ class Param(FieldInfo):
kwargs["examples"] = examples
if regex is not None:
warnings.warn(
- "`regex` has been depreacated, please use `pattern` instead",
+ "`regex` has been deprecated, please use `pattern` instead",
category=DeprecationWarning,
stacklevel=4,
)
@@ -512,7 +512,7 @@ class Body(FieldInfo):
self.deprecated = deprecated
if example is not _Unset:
warnings.warn(
- "`example` has been depreacated, please use `examples` instead",
+ "`example` has been deprecated, please use `examples` instead",
category=DeprecationWarning,
stacklevel=4,
)
diff --git a/fastapi/routing.py b/fastapi/routing.py
index d8ff0579c..1e3dfb4d5 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -83,7 +83,7 @@ def _prepare_response_content(
if read_with_orm_mode:
# Let from_orm extract the data from this model instead of converting
# it now to a dict.
- # Otherwise there's no way to extract lazy data that requires attribute
+ # Otherwise, there's no way to extract lazy data that requires attribute
# access instead of dict iteration, e.g. lazy relationships.
return res
return _model_dump(
@@ -448,9 +448,7 @@ class APIRoute(routing.Route):
self.response_field = create_response_field(
name=response_name,
type_=self.response_model,
- # TODO: This should actually set mode='serialization', just, that changes the schemas
- # mode="serialization",
- mode="validation",
+ mode="serialization",
)
# Create a clone of the field, so that a Pydantic submodel is not returned
# as is just because it's an instance of a subclass of a more limited class
@@ -458,7 +456,7 @@ class APIRoute(routing.Route):
# that doesn't have the hashed_password. But because it's a subclass, it
# would pass the validation and be returned as is.
# By being a new field, no inheritance will be passed as is. A new model
- # will be always created.
+ # will always be created.
# TODO: remove when deprecating Pydantic v1
self.secure_cloned_response_field: Optional[
ModelField
diff --git a/pyproject.toml b/pyproject.toml
index f0917578f..9b7cca9c9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -42,7 +42,7 @@ classifiers = [
]
dependencies = [
"starlette>=0.27.0,<0.28.0",
- "pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,<3.0.0",
+ "pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0",
"typing-extensions>=4.5.0",
]
dynamic = ["version"]
diff --git a/requirements-docs.txt b/requirements-docs.txt
index df60ca4df..220d1ec3a 100644
--- a/requirements-docs.txt
+++ b/requirements-docs.txt
@@ -1,6 +1,5 @@
-e .
-mkdocs==1.4.3
-mkdocs-material==9.1.17
+mkdocs-material==9.1.21
mdx-include >=1.4.1,<2.0.0
mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0
typer-cli >=0.0.13,<0.0.14
diff --git a/requirements-tests.txt b/requirements-tests.txt
index abefac685..0113b6f7a 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -2,7 +2,7 @@
pydantic-settings >=2.0.0
pytest >=7.1.3,<8.0.0
coverage[toml] >= 6.5.0,< 8.0
-mypy ==1.4.0
+mypy ==1.4.1
ruff ==0.0.275
black == 23.3.0
httpx >=0.23.0,<0.25.0
diff --git a/tests/test_computed_fields.py b/tests/test_computed_fields.py
new file mode 100644
index 000000000..5286507b2
--- /dev/null
+++ b/tests/test_computed_fields.py
@@ -0,0 +1,77 @@
+import pytest
+from fastapi import FastAPI
+from fastapi.testclient import TestClient
+
+from .utils import needs_pydanticv2
+
+
+@pytest.fixture(name="client")
+def get_client():
+ app = FastAPI()
+
+ from pydantic import BaseModel, computed_field
+
+ class Rectangle(BaseModel):
+ width: int
+ length: int
+
+ @computed_field
+ @property
+ def area(self) -> int:
+ return self.width * self.length
+
+ @app.get("/")
+ def read_root() -> Rectangle:
+ return Rectangle(width=3, length=4)
+
+ client = TestClient(app)
+ return client
+
+
+@needs_pydanticv2
+def test_get(client: TestClient):
+ response = client.get("/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"width": 3, "length": 4, "area": 12}
+
+
+@needs_pydanticv2
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "get": {
+ "summary": "Read Root",
+ "operationId": "read_root__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Rectangle"}
+ }
+ },
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Rectangle": {
+ "properties": {
+ "width": {"type": "integer", "title": "Width"},
+ "length": {"type": "integer", "title": "Length"},
+ "area": {"type": "integer", "title": "Area", "readOnly": True},
+ },
+ "type": "object",
+ "required": ["width", "length", "area"],
+ "title": "Rectangle",
+ }
+ }
+ },
+ }
diff --git a/tests/test_filter_pydantic_sub_model_pv2.py b/tests/test_filter_pydantic_sub_model_pv2.py
index 656332a01..9f5e6b08f 100644
--- a/tests/test_filter_pydantic_sub_model_pv2.py
+++ b/tests/test_filter_pydantic_sub_model_pv2.py
@@ -1,7 +1,7 @@
from typing import Optional
import pytest
-from dirty_equals import IsDict
+from dirty_equals import HasRepr, IsDict, IsOneOf
from fastapi import Depends, FastAPI
from fastapi.exceptions import ResponseValidationError
from fastapi.testclient import TestClient
@@ -66,7 +66,7 @@ def test_validator_is_cloned(client: TestClient):
"loc": ("response", "name"),
"msg": "Value error, name must end in A",
"input": "modelX",
- "ctx": {"error": "name must end in A"},
+ "ctx": {"error": HasRepr("ValueError('name must end in A')")},
"url": match_pydantic_error_url("value_error"),
}
)
@@ -139,7 +139,11 @@ def test_openapi_schema(client: TestClient):
},
"ModelA": {
"title": "ModelA",
- "required": ["name", "foo"],
+ "required": IsOneOf(
+ ["name", "description", "foo"],
+ # TODO remove when deprecating Pydantic v1
+ ["name", "foo"],
+ ),
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py
index ff3033ecd..7c8338ff3 100644
--- a/tests/test_jsonable_encoder.py
+++ b/tests/test_jsonable_encoder.py
@@ -247,8 +247,9 @@ def test_encode_model_with_pure_path():
class Config:
arbitrary_types_allowed = True
- obj = ModelWithPath(path=PurePath("/foo", "bar"))
- assert jsonable_encoder(obj) == {"path": "/foo/bar"}
+ test_path = PurePath("/foo", "bar")
+ obj = ModelWithPath(path=test_path)
+ assert jsonable_encoder(obj) == {"path": str(test_path)}
def test_encode_model_with_pure_posix_path():
diff --git a/tests/test_multi_body_errors.py b/tests/test_multi_body_errors.py
index aa989c612..931f08fc1 100644
--- a/tests/test_multi_body_errors.py
+++ b/tests/test_multi_body_errors.py
@@ -51,7 +51,7 @@ def test_jsonable_encoder_requiring_error():
"loc": ["body", 0, "age"],
"msg": "Input should be greater than 0",
"input": -1.0,
- "ctx": {"gt": 0.0},
+ "ctx": {"gt": "0"},
"url": match_pydantic_error_url("greater_than"),
}
]
@@ -84,9 +84,23 @@ def test_put_incorrect_body_multiple():
"input": {"age": "five"},
"url": match_pydantic_error_url("missing"),
},
+ {
+ "ctx": {"class": "Decimal"},
+ "input": "five",
+ "loc": ["body", 0, "age", "is-instance[Decimal]"],
+ "msg": "Input should be an instance of Decimal",
+ "type": "is_instance_of",
+ "url": match_pydantic_error_url("is_instance_of"),
+ },
{
"type": "decimal_parsing",
- "loc": ["body", 0, "age"],
+ "loc": [
+ "body",
+ 0,
+ "age",
+ "function-after[to_decimal(), "
+ "union[int,constrained-str,function-plain[str()]]]",
+ ],
"msg": "Input should be a valid decimal",
"input": "five",
},
@@ -97,9 +111,23 @@ def test_put_incorrect_body_multiple():
"input": {"age": "six"},
"url": match_pydantic_error_url("missing"),
},
+ {
+ "ctx": {"class": "Decimal"},
+ "input": "six",
+ "loc": ["body", 1, "age", "is-instance[Decimal]"],
+ "msg": "Input should be an instance of Decimal",
+ "type": "is_instance_of",
+ "url": match_pydantic_error_url("is_instance_of"),
+ },
{
"type": "decimal_parsing",
- "loc": ["body", 1, "age"],
+ "loc": [
+ "body",
+ 1,
+ "age",
+ "function-after[to_decimal(), "
+ "union[int,constrained-str,function-plain[str()]]]",
+ ],
"msg": "Input should be a valid decimal",
"input": "six",
},
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py
index b02f7c81c..f1a46210a 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py
@@ -1,7 +1,8 @@
import pytest
-from dirty_equals import IsDict
from fastapi.testclient import TestClient
+from ...utils import needs_pydanticv1, needs_pydanticv2
+
@pytest.fixture(name="client")
def get_client():
@@ -36,7 +37,181 @@ def test_put(client: TestClient):
}
+@needs_pydanticv2
def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ItemInput"}
+ }
+ },
+ "required": True,
+ },
+ },
+ }
+ },
+ "components": {
+ "schemas": {
+ "ItemInput": {
+ "title": "Item",
+ "type": "object",
+ "properties": {
+ "name": {
+ "title": "Name",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "price": {
+ "title": "Price",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tax": {"title": "Tax", "type": "number", "default": 10.5},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ItemOutput": {
+ "title": "Item",
+ "type": "object",
+ "required": ["name", "description", "price", "tax", "tags"],
+ "properties": {
+ "name": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "title": "Name",
+ },
+ "description": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "title": "Description",
+ },
+ "price": {
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ "title": "Price",
+ },
+ "tax": {"title": "Tax", "type": "number", "default": 10.5},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
+
+
+# TODO: remove when deprecating Pydantic v1
+@needs_pydanticv1
+def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
@@ -124,36 +299,9 @@ def test_openapi_schema(client: TestClient):
"title": "Item",
"type": "object",
"properties": {
- "name": IsDict(
- {
- "title": "Name",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Name", "type": "string"}
- ),
- "description": IsDict(
- {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Description", "type": "string"}
- ),
- "price": IsDict(
- {
- "title": "Price",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Price", "type": "number"}
- ),
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
"tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": {
"title": "Tags",
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
index 4af2652a7..ab696e4c8 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
@@ -1,8 +1,7 @@
import pytest
-from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from ...utils import needs_py310
+from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client")
@@ -41,7 +40,182 @@ def test_put(client: TestClient):
@needs_py310
+@needs_pydanticv2
def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ItemInput"}
+ }
+ },
+ "required": True,
+ },
+ },
+ }
+ },
+ "components": {
+ "schemas": {
+ "ItemInput": {
+ "title": "Item",
+ "type": "object",
+ "properties": {
+ "name": {
+ "title": "Name",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "price": {
+ "title": "Price",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tax": {"title": "Tax", "type": "number", "default": 10.5},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ItemOutput": {
+ "title": "Item",
+ "type": "object",
+ "required": ["name", "description", "price", "tax", "tags"],
+ "properties": {
+ "name": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "title": "Name",
+ },
+ "description": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "title": "Description",
+ },
+ "price": {
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ "title": "Price",
+ },
+ "tax": {"title": "Tax", "type": "number", "default": 10.5},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
+
+
+# TODO: remove when deprecating Pydantic v1
+@needs_py310
+@needs_pydanticv1
+def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
@@ -129,36 +303,9 @@ def test_openapi_schema(client: TestClient):
"title": "Item",
"type": "object",
"properties": {
- "name": IsDict(
- {
- "title": "Name",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Name", "type": "string"}
- ),
- "description": IsDict(
- {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Description", "type": "string"}
- ),
- "price": IsDict(
- {
- "title": "Price",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Price", "type": "number"}
- ),
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
"tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": {
"title": "Tags",
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
index 832f45388..2ee6a5cb4 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
@@ -1,8 +1,7 @@
import pytest
-from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from ...utils import needs_py39
+from ...utils import needs_py39, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client")
@@ -41,7 +40,182 @@ def test_put(client: TestClient):
@needs_py39
+@needs_pydanticv2
def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ItemInput"}
+ }
+ },
+ "required": True,
+ },
+ },
+ }
+ },
+ "components": {
+ "schemas": {
+ "ItemInput": {
+ "title": "Item",
+ "type": "object",
+ "properties": {
+ "name": {
+ "title": "Name",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "price": {
+ "title": "Price",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tax": {"title": "Tax", "type": "number", "default": 10.5},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ItemOutput": {
+ "title": "Item",
+ "type": "object",
+ "required": ["name", "description", "price", "tax", "tags"],
+ "properties": {
+ "name": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "title": "Name",
+ },
+ "description": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "title": "Description",
+ },
+ "price": {
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ "title": "Price",
+ },
+ "tax": {"title": "Tax", "type": "number", "default": 10.5},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
+
+
+# TODO: remove when deprecating Pydantic v1
+@needs_py39
+@needs_pydanticv1
+def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
@@ -129,36 +303,9 @@ def test_openapi_schema(client: TestClient):
"title": "Item",
"type": "object",
"properties": {
- "name": IsDict(
- {
- "title": "Name",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Name", "type": "string"}
- ),
- "description": IsDict(
- {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Description", "type": "string"}
- ),
- "price": IsDict(
- {
- "title": "Price",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Price", "type": "number"}
- ),
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
"tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": {
"title": "Tags",
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial002.py b/tests/test_tutorial/test_dataclasses/test_tutorial002.py
index 7d88e2861..4146f4cd6 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial002.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial002.py
@@ -1,4 +1,4 @@
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from docs_src.dataclasses.tutorial002 import app
@@ -21,8 +21,7 @@ def test_get_item():
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200
- data = response.json()
- assert data == {
+ assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
@@ -47,7 +46,11 @@ def test_openapi_schema():
"schemas": {
"Item": {
"title": "Item",
- "required": ["name", "price"],
+ "required": IsOneOf(
+ ["name", "price", "tags", "description", "tax"],
+ # TODO: remove when deprecating Pydantic v1
+ ["name", "price"],
+ ),
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
@@ -57,7 +60,6 @@ def test_openapi_schema():
"title": "Tags",
"type": "array",
"items": {"type": "string"},
- "default": [],
}
)
| IsDict(
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py
index 597757e09..2e5809914 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py
@@ -1,8 +1,9 @@
-from dirty_equals import IsDict
from fastapi.testclient import TestClient
from docs_src.dataclasses.tutorial003 import app
+from ...utils import needs_pydanticv1, needs_pydanticv2
+
client = TestClient(app)
@@ -52,6 +53,7 @@ def test_get_authors():
]
+@needs_pydanticv2
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200
@@ -77,7 +79,7 @@ def test_openapi_schema():
"schema": {
"title": "Items",
"type": "array",
- "items": {"$ref": "#/components/schemas/Item"},
+ "items": {"$ref": "#/components/schemas/ItemInput"},
}
}
},
@@ -132,26 +134,164 @@ def test_openapi_schema():
"schemas": {
"Author": {
"title": "Author",
+ "required": ["name", "items"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "items": {
+ "title": "Items",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ItemOutput"},
+ },
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ItemInput": {
+ "title": "Item",
"required": ["name"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
- "items": IsDict(
- {
- "title": "Items",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Item"},
- "default": [],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "Items",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Item"},
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ },
+ },
+ "ItemOutput": {
+ "title": "Item",
+ "required": ["name", "description"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
+
+
+# TODO: remove when deprecating Pydantic v1
+@needs_pydanticv1
+def test_openapi_schema_pv1():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/authors/{author_id}/items/": {
+ "post": {
+ "summary": "Create Author Items",
+ "operationId": "create_author_items_authors__author_id__items__post",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Author Id", "type": "string"},
+ "name": "author_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Items",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
}
- ),
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Author"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/authors/": {
+ "get": {
+ "summary": "Get Authors",
+ "operationId": "get_authors_authors__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Get Authors Authors Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Author"
+ },
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Author": {
+ "title": "Author",
+ "required": ["name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "items": {
+ "title": "Items",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ },
},
},
"HTTPValidationError": {
@@ -171,16 +311,7 @@ def test_openapi_schema():
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
- "description": IsDict(
- {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Description", "type": "string"}
- ),
+ "description": {"title": "Description", "type": "string"},
},
},
"ValidationError": {
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py
index 21192b7db..0ccb99948 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial003.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py
@@ -1,3 +1,4 @@
+from dirty_equals import IsOneOf
from fastapi.testclient import TestClient
from docs_src.extra_models.tutorial003 import app
@@ -76,7 +77,11 @@ def test_openapi_schema():
"schemas": {
"PlaneItem": {
"title": "PlaneItem",
- "required": ["description", "size"],
+ "required": IsOneOf(
+ ["description", "type", "size"],
+ # TODO: remove when deprecating Pydantic v1
+ ["description", "size"],
+ ),
"type": "object",
"properties": {
"description": {"title": "Description", "type": "string"},
@@ -86,7 +91,11 @@ def test_openapi_schema():
},
"CarItem": {
"title": "CarItem",
- "required": ["description"],
+ "required": IsOneOf(
+ ["description", "type"],
+ # TODO: remove when deprecating Pydantic v1
+ ["description"],
+ ),
"type": "object",
"properties": {
"description": {"title": "Description", "type": "string"},
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
index c17ddbbe1..b2fe65fd9 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
@@ -1,4 +1,5 @@
import pytest
+from dirty_equals import IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -86,7 +87,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"PlaneItem": {
"title": "PlaneItem",
- "required": ["description", "size"],
+ "required": IsOneOf(
+ ["description", "type", "size"],
+ # TODO: remove when deprecating Pydantic v1
+ ["description", "size"],
+ ),
"type": "object",
"properties": {
"description": {"title": "Description", "type": "string"},
@@ -96,7 +101,11 @@ def test_openapi_schema(client: TestClient):
},
"CarItem": {
"title": "CarItem",
- "required": ["description"],
+ "required": IsOneOf(
+ ["description", "type"],
+ # TODO: remove when deprecating Pydantic v1
+ ["description"],
+ ),
"type": "object",
"properties": {
"description": {"title": "Description", "type": "string"},
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
index dd123f48d..3ffc0bca7 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
@@ -1,8 +1,9 @@
-from dirty_equals import IsDict
from fastapi.testclient import TestClient
from docs_src.path_operation_advanced_configuration.tutorial004 import app
+from ...utils import needs_pydanticv1, needs_pydanticv2
+
client = TestClient(app)
@@ -18,7 +19,137 @@ def test_query_params_str_validations():
}
+@needs_pydanticv2
def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create an item",
+ "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ItemInput"}
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ItemInput": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "price": {"title": "Price", "type": "number"},
+ "tax": {
+ "title": "Tax",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ItemOutput": {
+ "title": "Item",
+ "required": ["name", "description", "price", "tax", "tags"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "price": {"title": "Price", "type": "number"},
+ "tax": {
+ "title": "Tax",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
+
+
+# TODO: remove when deprecating Pydantic v1
+@needs_pydanticv1
+def test_openapi_schema_pv1():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
@@ -69,27 +200,9 @@ def test_openapi_schema():
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
- "description": IsDict(
- {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Description", "type": "string"}
- ),
+ "description": {"title": "Description", "type": "string"},
"price": {"title": "Price", "type": "number"},
- "tax": IsDict(
- {
- "title": "Tax",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Tax", "type": "number"}
- ),
+ "tax": {"title": "Tax", "type": "number"},
"tags": {
"title": "Tags",
"uniqueItems": True,
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
index e7e9a982e..ff98295a6 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
@@ -1,8 +1,9 @@
-from dirty_equals import IsDict
from fastapi.testclient import TestClient
from docs_src.path_operation_configuration.tutorial005 import app
+from ...utils import needs_pydanticv1, needs_pydanticv2
+
client = TestClient(app)
@@ -18,7 +19,137 @@ def test_query_params_str_validations():
}
+@needs_pydanticv2
def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "The created item",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create an item",
+ "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ItemInput"}
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ItemInput": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "price": {"title": "Price", "type": "number"},
+ "tax": {
+ "title": "Tax",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ItemOutput": {
+ "title": "Item",
+ "required": ["name", "description", "price", "tax", "tags"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "title": "Description",
+ },
+ "price": {"title": "Price", "type": "number"},
+ "tax": {
+ "title": "Tax",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
+
+
+# TODO: remove when deprecating Pydantic v1
+@needs_pydanticv1
+def test_openapi_schema_pv1():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
@@ -69,27 +200,9 @@ def test_openapi_schema():
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
- "description": IsDict(
- {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Description", "type": "string"}
- ),
+ "description": {"title": "Description", "type": "string"},
"price": {"title": "Price", "type": "number"},
- "tax": IsDict(
- {
- "title": "Tax",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Tax", "type": "number"}
- ),
+ "tax": {"title": "Tax", "type": "number"},
"tags": {
"title": "Tags",
"uniqueItems": True,
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
index ebfeb809c..ad1c09eae 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
@@ -1,8 +1,7 @@
import pytest
-from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from ...utils import needs_py310
+from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client")
@@ -27,7 +26,138 @@ def test_query_params_str_validations(client: TestClient):
@needs_py310
+@needs_pydanticv2
def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "The created item",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create an item",
+ "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ItemInput"}
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ItemInput": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "price": {"title": "Price", "type": "number"},
+ "tax": {
+ "title": "Tax",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ItemOutput": {
+ "title": "Item",
+ "required": ["name", "description", "price", "tax", "tags"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "title": "Description",
+ },
+ "price": {"title": "Price", "type": "number"},
+ "tax": {
+ "title": "Tax",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
+
+
+# TODO: remove when deprecating Pydantic v1
+@needs_py310
+@needs_pydanticv1
+def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
@@ -78,27 +208,9 @@ def test_openapi_schema(client: TestClient):
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
- "description": IsDict(
- {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Description", "type": "string"}
- ),
+ "description": {"title": "Description", "type": "string"},
"price": {"title": "Price", "type": "number"},
- "tax": IsDict(
- {
- "title": "Tax",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Tax", "type": "number"}
- ),
+ "tax": {"title": "Tax", "type": "number"},
"tags": {
"title": "Tags",
"uniqueItems": True,
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
index 8e79afe96..045d1d402 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
@@ -1,8 +1,7 @@
import pytest
-from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from ...utils import needs_py39
+from ...utils import needs_py39, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client")
@@ -27,7 +26,138 @@ def test_query_params_str_validations(client: TestClient):
@needs_py39
+@needs_pydanticv2
def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.1.0",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "The created item",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ItemOutput"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create an item",
+ "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ItemInput"}
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ItemInput": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "Description",
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ },
+ "price": {"title": "Price", "type": "number"},
+ "tax": {
+ "title": "Tax",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ItemOutput": {
+ "title": "Item",
+ "required": ["name", "description", "price", "tax", "tags"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "title": "Description",
+ },
+ "price": {"title": "Price", "type": "number"},
+ "tax": {
+ "title": "Tax",
+ "anyOf": [{"type": "number"}, {"type": "null"}],
+ },
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
+
+
+# TODO: remove when deprecating Pydantic v1
+@needs_py39
+@needs_pydanticv1
+def test_openapi_schema_pv1(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
@@ -78,27 +208,9 @@ def test_openapi_schema(client: TestClient):
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
- "description": IsDict(
- {
- "title": "Description",
- "anyOf": [{"type": "string"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Description", "type": "string"}
- ),
+ "description": {"title": "Description", "type": "string"},
"price": {"title": "Price", "type": "number"},
- "tax": IsDict(
- {
- "title": "Tax",
- "anyOf": [{"type": "number"}, {"type": "null"}],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {"title": "Tax", "type": "number"}
- ),
+ "tax": {"title": "Tax", "type": "number"},
"tags": {
"title": "Tags",
"uniqueItems": True,
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003.py b/tests/test_tutorial/test_response_model/test_tutorial003.py
index 20221399b..384c8e0f1 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003.py
@@ -1,4 +1,4 @@
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from docs_src.response_model.tutorial003 import app
@@ -70,7 +70,11 @@ def test_openapi_schema():
"schemas": {
"UserOut": {
"title": "UserOut",
- "required": ["username", "email"],
+ "required": IsOneOf(
+ ["username", "email", "full_name"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username", "email"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_01.py b/tests/test_tutorial/test_response_model/test_tutorial003_01.py
index e8f0658f4..3a6a0b20d 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003_01.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003_01.py
@@ -1,4 +1,4 @@
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from docs_src.response_model.tutorial003_01 import app
@@ -70,7 +70,11 @@ def test_openapi_schema():
"schemas": {
"BaseUser": {
"title": "BaseUser",
- "required": ["username", "email"],
+ "required": IsOneOf(
+ ["username", "email", "full_name"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username", "email"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py b/tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py
index a69f8cc8d..6985b9de6 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -79,7 +79,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"BaseUser": {
"title": "BaseUser",
- "required": ["username", "email"],
+ "required": IsOneOf(
+ ["username", "email", "full_name"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username", "email"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_py310.py b/tests/test_tutorial/test_response_model/test_tutorial003_py310.py
index 64dcd6cbd..3a3aee38a 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003_py310.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003_py310.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -79,7 +79,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"UserOut": {
"title": "UserOut",
- "required": ["username", "email"],
+ "required": IsOneOf(
+ ["username", "email", "full_name"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username", "email"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial004.py b/tests/test_tutorial/test_response_model/test_tutorial004.py
index 8beb847d1..e9bde18dd 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial004.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial004.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from docs_src.response_model.tutorial004 import app
@@ -79,7 +79,11 @@ def test_openapi_schema():
"schemas": {
"Item": {
"title": "Item",
- "required": ["name", "price"],
+ "required": IsOneOf(
+ ["name", "description", "price", "tax", "tags"],
+ # TODO: remove when deprecating Pydantic v1
+ ["name", "price"],
+ ),
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial004_py310.py b/tests/test_tutorial/test_response_model/test_tutorial004_py310.py
index 28eb88c34..6f8a3cbea 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial004_py310.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial004_py310.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -87,7 +87,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"Item": {
"title": "Item",
- "required": ["name", "price"],
+ "required": IsOneOf(
+ ["name", "description", "price", "tax", "tags"],
+ # TODO: remove when deprecating Pydantic v1
+ ["name", "price"],
+ ),
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial004_py39.py b/tests/test_tutorial/test_response_model/test_tutorial004_py39.py
index 9e1a21f8d..cfaa1eba2 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial004_py39.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial004_py39.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py39
@@ -87,7 +87,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"Item": {
"title": "Item",
- "required": ["name", "price"],
+ "required": IsOneOf(
+ ["name", "description", "price", "tax", "tags"],
+ # TODO: remove when deprecating Pydantic v1
+ ["name", "price"],
+ ),
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial005.py b/tests/test_tutorial/test_response_model/test_tutorial005.py
index 06e5d0fd1..b20864c07 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial005.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial005.py
@@ -1,4 +1,4 @@
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from docs_src.response_model.tutorial005 import app
@@ -102,7 +102,11 @@ def test_openapi_schema():
"schemas": {
"Item": {
"title": "Item",
- "required": ["name", "price"],
+ "required": IsOneOf(
+ ["name", "description", "price", "tax"],
+ # TODO: remove when deprecating Pydantic v1
+ ["name", "price"],
+ ),
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial005_py310.py b/tests/test_tutorial/test_response_model/test_tutorial005_py310.py
index 0f1566243..de552c8f2 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial005_py310.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial005_py310.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -112,7 +112,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"Item": {
"title": "Item",
- "required": ["name", "price"],
+ "required": IsOneOf(
+ ["name", "description", "price", "tax"],
+ # TODO: remove when deprecating Pydantic v1
+ ["name", "price"],
+ ),
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial006.py b/tests/test_tutorial/test_response_model/test_tutorial006.py
index 6e6152b9f..1e47e2ead 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial006.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial006.py
@@ -1,4 +1,4 @@
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from docs_src.response_model.tutorial006 import app
@@ -102,7 +102,11 @@ def test_openapi_schema():
"schemas": {
"Item": {
"title": "Item",
- "required": ["name", "price"],
+ "required": IsOneOf(
+ ["name", "description", "price", "tax"],
+ # TODO: remove when deprecating Pydantic v1
+ ["name", "price"],
+ ),
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial006_py310.py b/tests/test_tutorial/test_response_model/test_tutorial006_py310.py
index 9a980ab5b..40058b12d 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial006_py310.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial006_py310.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -112,7 +112,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"Item": {
"title": "Item",
- "required": ["name", "price"],
+ "required": IsOneOf(
+ ["name", "description", "price", "tax"],
+ # TODO: remove when deprecating Pydantic v1
+ ["name", "price"],
+ ),
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py
index 22ae76f42..c669c306d 100644
--- a/tests/test_tutorial/test_security/test_tutorial005.py
+++ b/tests/test_tutorial/test_security/test_tutorial005.py
@@ -1,4 +1,4 @@
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from docs_src.security.tutorial005 import (
@@ -267,7 +267,11 @@ def test_openapi_schema():
"schemas": {
"User": {
"title": "User",
- "required": ["username"],
+ "required": IsOneOf(
+ ["username", "email", "full_name", "disabled"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial005_an.py b/tests/test_tutorial/test_security/test_tutorial005_an.py
index 07239cc89..aaab04f78 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_an.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_an.py
@@ -1,4 +1,4 @@
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from docs_src.security.tutorial005_an import (
@@ -267,7 +267,11 @@ def test_openapi_schema():
"schemas": {
"User": {
"title": "User",
- "required": ["username"],
+ "required": IsOneOf(
+ ["username", "email", "full_name", "disabled"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial005_an_py310.py b/tests/test_tutorial/test_security/test_tutorial005_an_py310.py
index 1ab836639..243d0773c 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_an_py310.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_an_py310.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"User": {
"title": "User",
- "required": ["username"],
+ "required": IsOneOf(
+ ["username", "email", "full_name", "disabled"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial005_an_py39.py b/tests/test_tutorial/test_security/test_tutorial005_an_py39.py
index 6aabbe04a..17a3f9aa2 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_an_py39.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_an_py39.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py39
@@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"User": {
"title": "User",
- "required": ["username"],
+ "required": IsOneOf(
+ ["username", "email", "full_name", "disabled"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial005_py310.py b/tests/test_tutorial/test_security/test_tutorial005_py310.py
index c21884df8..06455cd63 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_py310.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_py310.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"User": {
"title": "User",
- "required": ["username"],
+ "required": IsOneOf(
+ ["username", "email", "full_name", "disabled"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial005_py39.py b/tests/test_tutorial/test_security/test_tutorial005_py39.py
index 170c5d60b..9455bfb4e 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_py39.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_py39.py
@@ -1,5 +1,5 @@
import pytest
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from ...utils import needs_py39
@@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": {
"User": {
"title": "User",
- "required": ["username"],
+ "required": IsOneOf(
+ ["username", "email", "full_name", "disabled"],
+ # TODO: remove when deprecating Pydantic v1
+ ["username"],
+ ),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},