Browse Source

Merge branch 'master' into bugfix/subapp-custom-openapi

pull/4657/head
Lorhan Sohaky 2 years ago
committed by GitHub
parent
commit
e8c5f8cd64
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      .github/DISCUSSION_TEMPLATE/questions.yml
  2. 4
      .github/actions/people/Dockerfile
  3. 14
      .github/actions/people/app/main.py
  4. 4
      .github/workflows/build-docs.yml
  5. 23
      .github/workflows/deploy-docs.yml
  6. 4
      .github/workflows/issue-manager.yml
  7. 4
      .github/workflows/label-approved.yml
  8. 10
      .github/workflows/latest-changes.yml
  9. 15
      .github/workflows/notify-translations.yml
  10. 8
      .github/workflows/people.yml
  11. 4
      .github/workflows/smokeshow.yml
  12. 20
      .github/workflows/test.yml
  13. 2
      README.md
  14. 4
      docs/en/data/external_links.yml
  15. 93
      docs/en/data/github_sponsors.yml
  16. 188
      docs/en/data/people.yml
  17. 2
      docs/en/data/sponsors.yml
  18. 5
      docs/en/docs/advanced/generate-clients.md
  19. 2
      docs/en/docs/alternatives.md
  20. 2
      docs/en/docs/contributing.md
  21. 1
      docs/en/docs/img/sponsors/fern-banner.svg
  22. 1
      docs/en/docs/img/sponsors/fern.svg
  23. 46
      docs/en/docs/release-notes.md
  24. 2
      docs/en/docs/tutorial/bigger-applications.md
  25. 2
      docs/en/overrides/main.html
  26. 34
      docs/ru/docs/tutorial/dependencies/global-dependencies.md
  27. 101
      docs/ru/docs/tutorial/security/index.md
  28. 52
      docs/ur/docs/benchmarks.md
  29. 1
      docs/ur/mkdocs.yml
  30. 2
      fastapi/__init__.py
  31. 2
      fastapi/concurrency.py
  32. 6
      fastapi/params.py
  33. 8
      fastapi/routing.py
  34. 2
      pyproject.toml
  35. 3
      requirements-docs.txt
  36. 2
      requirements-tests.txt
  37. 77
      tests/test_computed_fields.py
  38. 10
      tests/test_filter_pydantic_sub_model_pv2.py
  39. 5
      tests/test_jsonable_encoder.py
  40. 34
      tests/test_multi_body_errors.py
  41. 210
      tests/test_tutorial/test_body_updates/test_tutorial001.py
  42. 211
      tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
  43. 211
      tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
  44. 12
      tests/test_tutorial/test_dataclasses/test_tutorial002.py
  45. 185
      tests/test_tutorial/test_dataclasses/test_tutorial003.py
  46. 13
      tests/test_tutorial/test_extra_models/test_tutorial003.py
  47. 13
      tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
  48. 155
      tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
  49. 155
      tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
  50. 156
      tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
  51. 156
      tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
  52. 8
      tests/test_tutorial/test_response_model/test_tutorial003.py
  53. 8
      tests/test_tutorial/test_response_model/test_tutorial003_01.py
  54. 8
      tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py
  55. 8
      tests/test_tutorial/test_response_model/test_tutorial003_py310.py
  56. 8
      tests/test_tutorial/test_response_model/test_tutorial004.py
  57. 8
      tests/test_tutorial/test_response_model/test_tutorial004_py310.py
  58. 8
      tests/test_tutorial/test_response_model/test_tutorial004_py39.py
  59. 8
      tests/test_tutorial/test_response_model/test_tutorial005.py
  60. 8
      tests/test_tutorial/test_response_model/test_tutorial005_py310.py
  61. 8
      tests/test_tutorial/test_response_model/test_tutorial006.py
  62. 8
      tests/test_tutorial/test_response_model/test_tutorial006_py310.py
  63. 8
      tests/test_tutorial/test_security/test_tutorial005.py
  64. 8
      tests/test_tutorial/test_security/test_tutorial005_an.py
  65. 8
      tests/test_tutorial/test_security/test_tutorial005_an_py310.py
  66. 8
      tests/test_tutorial/test_security/test_tutorial005_an_py39.py
  67. 8
      tests/test_tutorial/test_security/test_tutorial005_py310.py
  68. 8
      tests/test_tutorial/test_security/test_tutorial005_py39.py

14
.github/DISCUSSION_TEMPLATE/questions.yml

@ -123,6 +123,20 @@ body:
``` ```
validations: validations:
required: true 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 - type: input
id: python-version id: python-version
attributes: attributes:

4
.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 COPY ./app /app

14
.github/actions/people/app/main.py

@ -9,7 +9,8 @@ from typing import Any, Container, DefaultDict, Dict, List, Set, Union
import httpx import httpx
import yaml import yaml
from github import Github 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" github_graphql_url = "https://api.github.com/graphql"
questions_category_id = "MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMyMDAxNDM0" questions_category_id = "MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMyMDAxNDM0"
@ -382,6 +383,7 @@ def get_graphql_response(
data = response.json() data = response.json()
if "errors" in data: if "errors" in data:
logging.error(f"Errors in response, after: {after}, category_id: {category_id}") logging.error(f"Errors in response, after: {after}, category_id: {category_id}")
logging.error(data["errors"])
logging.error(response.text) logging.error(response.text)
raise RuntimeError(response.text) raise RuntimeError(response.text)
return data return data
@ -389,7 +391,7 @@ def get_graphql_response(
def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = None): def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=issues_query, after=after) 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 return graphql_response.data.repository.issues.edges
@ -404,19 +406,19 @@ def get_graphql_question_discussion_edges(
after=after, after=after,
category_id=questions_category_id, category_id=questions_category_id,
) )
graphql_response = DiscussionsResponse.parse_obj(data) graphql_response = DiscussionsResponse.model_validate(data)
return graphql_response.data.repository.discussions.edges return graphql_response.data.repository.discussions.edges
def get_graphql_pr_edges(*, settings: Settings, after: Union[str, None] = None): def get_graphql_pr_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=prs_query, after=after) 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 return graphql_response.data.repository.pullRequests.edges
def get_graphql_sponsor_edges(*, settings: Settings, after: Union[str, None] = None): def get_graphql_sponsor_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=sponsors_query, after=after) 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 return graphql_response.data.user.sponsorshipsAsMaintainer.edges
@ -607,7 +609,7 @@ def get_top_users(
if __name__ == "__main__": if __name__ == "__main__":
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
settings = Settings() 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()) g = Github(settings.input_token.get_secret_value())
repo = g.get_repo(settings.github_repository) repo = g.get_repo(settings.github_repository)
question_commentors, question_last_month_commentors, question_authors = get_experts( question_commentors, question_last_month_commentors, question_authors = get_experts(

4
.github/workflows/build-docs.yml

@ -44,7 +44,7 @@ jobs:
id: cache id: cache
with: with:
path: ${{ env.pythonLocation }} 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 - name: Install docs extras
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-docs.txt run: pip install -r requirements-docs.txt
@ -80,7 +80,7 @@ jobs:
id: cache id: cache
with: with:
path: ${{ env.pythonLocation }} 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 - name: Install docs extras
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-docs.txt run: pip install -r requirements-docs.txt

23
.github/workflows/deploy-docs.yml

@ -29,21 +29,20 @@ jobs:
run_id: ${{ github.event.workflow_run.id }} run_id: ${{ github.event.workflow_run.id }}
name: docs-site name: docs-site
path: ./site/ path: ./site/
- name: Deploy to Netlify - name: Deploy to Cloudflare Pages
if: steps.download.outputs.found_artifact == 'true' if: steps.download.outputs.found_artifact == 'true'
id: netlify id: deploy
uses: nwtgck/[email protected] uses: cloudflare/pages-action@v1
with: with:
publish-dir: './site' apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
production-deploy: ${{ github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'master' }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
github-token: ${{ secrets.FASTAPI_PREVIEW_DOCS_NETLIFY }} projectName: fastapitiangolo
enable-commit-comment: false directory: './site'
env: gitHubToken: ${{ secrets.GITHUB_TOKEN }}
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_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 ) }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
- name: Comment Deploy - name: Comment Deploy
if: steps.netlify.outputs.deploy-url != '' if: steps.deploy.outputs.url != ''
uses: ./.github/actions/comment-docs-preview-in-pr uses: ./.github/actions/comment-docs-preview-in-pr
with: with:
token: ${{ secrets.FASTAPI_PREVIEW_DOCS_COMMENT_DEPLOY }} token: ${{ secrets.FASTAPI_PREVIEW_DOCS_COMMENT_DEPLOY }}
deploy_url: "${{ steps.netlify.outputs.deploy-url }}" deploy_url: "${{ steps.deploy.outputs.url }}"

4
.github/workflows/issue-manager.yml

@ -19,6 +19,10 @@ jobs:
if: github.repository_owner == 'tiangolo' if: github.repository_owner == 'tiangolo'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: tiangolo/[email protected] - uses: tiangolo/[email protected]
with: with:
token: ${{ secrets.FASTAPI_ISSUE_MANAGER }} token: ${{ secrets.FASTAPI_ISSUE_MANAGER }}

4
.github/workflows/label-approved.yml

@ -9,6 +9,10 @@ jobs:
if: github.repository_owner == 'tiangolo' if: github.repository_owner == 'tiangolo'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: docker://tiangolo/label-approved:0.0.2 - uses: docker://tiangolo/label-approved:0.0.2
with: with:
token: ${{ secrets.FASTAPI_LABEL_APPROVED }} token: ${{ secrets.FASTAPI_LABEL_APPROVED }}

10
.github/workflows/latest-changes.yml

@ -14,20 +14,24 @@ on:
debug_enabled: debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false required: false
default: false default: 'false'
jobs: jobs:
latest-changes: latest-changes:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
# To allow latest-changes to commit to master # To allow latest-changes to commit to the main branch
token: ${{ secrets.FASTAPI_LATEST_CHANGES }} token: ${{ secrets.FASTAPI_LATEST_CHANGES }}
# Allow debugging with tmate # Allow debugging with tmate
- name: Setup tmate session - name: Setup tmate session
uses: mxschmitt/action-tmate@v3 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: with:
limit-access-to-actor: true limit-access-to-actor: true
- uses: docker://tiangolo/latest-changes:0.0.3 - uses: docker://tiangolo/latest-changes:0.0.3

15
.github/workflows/notify-translations.yml

@ -5,16 +5,29 @@ on:
types: types:
- labeled - labeled
- closed - 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: jobs:
notify-translations: notify-translations:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# Allow debugging with tmate # Allow debugging with tmate
- name: Setup tmate session - name: Setup tmate session
uses: mxschmitt/action-tmate@v3 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: with:
limit-access-to-actor: true limit-access-to-actor: true
- uses: ./.github/actions/notify-translations - uses: ./.github/actions/notify-translations

8
.github/workflows/people.yml

@ -8,13 +8,17 @@ on:
debug_enabled: debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false required: false
default: false default: 'false'
jobs: jobs:
fastapi-people: fastapi-people:
if: github.repository_owner == 'tiangolo' if: github.repository_owner == 'tiangolo'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# Ref: https://github.com/actions/runner/issues/2033 # Ref: https://github.com/actions/runner/issues/2033
- name: Fix git safe.directory in container - name: Fix git safe.directory in container
@ -22,7 +26,7 @@ jobs:
# Allow debugging with tmate # Allow debugging with tmate
- name: Setup tmate session - name: Setup tmate session
uses: mxschmitt/action-tmate@v3 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: with:
limit-access-to-actor: true limit-access-to-actor: true
- uses: ./.github/actions/people - uses: ./.github/actions/people

4
.github/workflows/smokeshow.yml

@ -14,6 +14,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
python-version: '3.9' python-version: '3.9'

20
.github/workflows/test.yml

@ -13,6 +13,10 @@ jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@ -25,7 +29,7 @@ jobs:
id: cache id: cache
with: with:
path: ${{ env.pythonLocation }} 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 - name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-tests.txt run: pip install -r requirements-tests.txt
@ -42,6 +46,10 @@ jobs:
pydantic-version: ["pydantic-v1", "pydantic-v2"] pydantic-version: ["pydantic-v1", "pydantic-v2"]
fail-fast: false fail-fast: false
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@ -54,7 +62,7 @@ jobs:
id: cache id: cache
with: with:
path: ${{ env.pythonLocation }} 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 - name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-tests.txt run: pip install -r requirements-tests.txt
@ -80,6 +88,10 @@ jobs:
needs: [test] needs: [test]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
@ -110,6 +122,10 @@ jobs:
- coverage-combine - coverage-combine
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Decide whether the needed jobs succeeded or failed - name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1 uses: re-actors/alls-green@release/v1
with: with:

2
README.md

@ -48,7 +48,7 @@ The key features are:
<a href="https://cryptapi.io/" target="_blank" title="CryptAPI: Your easy to use, secure and privacy oriented payment gateway."><img src="https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg"></a> <a href="https://cryptapi.io/" target="_blank" title="CryptAPI: Your easy to use, secure and privacy oriented payment gateway."><img src="https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg"></a>
<a href="https://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023" target="_blank" title="Build, run and scale your apps on a modern, reliable, and secure PaaS."><img src="https://fastapi.tiangolo.com/img/sponsors/platform-sh.png"></a> <a href="https://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023" target="_blank" title="Build, run and scale your apps on a modern, reliable, and secure PaaS."><img src="https://fastapi.tiangolo.com/img/sponsors/platform-sh.png"></a>
<a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge" target="_blank" title="Fern | SDKs and API docs"><img src="https://fastapi.tiangolo.com/img/sponsors/fern.png"></a> <a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge" target="_blank" title="Fern | SDKs and API docs"><img src="https://fastapi.tiangolo.com/img/sponsors/fern.svg"></a>
<a href="https://www.deta.sh/?ref=fastapi" target="_blank" title="The launchpad for all your (team's) ideas"><img src="https://fastapi.tiangolo.com/img/sponsors/deta.svg"></a> <a href="https://www.deta.sh/?ref=fastapi" target="_blank" title="The launchpad for all your (team's) ideas"><img src="https://fastapi.tiangolo.com/img/sponsors/deta.svg"></a>
<a href="https://training.talkpython.fm/fastapi-courses" target="_blank" title="FastAPI video courses on demand from people you trust"><img src="https://fastapi.tiangolo.com/img/sponsors/talkpython.png"></a> <a href="https://training.talkpython.fm/fastapi-courses" target="_blank" title="FastAPI video courses on demand from people you trust"><img src="https://fastapi.tiangolo.com/img/sponsors/talkpython.png"></a>
<a href="https://testdriven.io/courses/tdd-fastapi/" target="_blank" title="Learn to build high-quality web apps with best practices"><img src="https://fastapi.tiangolo.com/img/sponsors/testdriven.svg"></a> <a href="https://testdriven.io/courses/tdd-fastapi/" target="_blank" title="Learn to build high-quality web apps with best practices"><img src="https://fastapi.tiangolo.com/img/sponsors/testdriven.svg"></a>

4
docs/en/data/external_links.yml

@ -1,5 +1,9 @@
articles: articles:
english: 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: Raf Rasenberg
author_link: https://rafrasenberg.com/about/ author_link: https://rafrasenberg.com/about/
link: https://rafrasenberg.com/fastapi-lambda/ link: https://rafrasenberg.com/fastapi-lambda/

93
docs/en/data/github_sponsors.yml

@ -2,6 +2,9 @@ sponsors:
- - login: cryptapi - - login: cryptapi
avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4 avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4
url: https://github.com/cryptapi 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 - login: nanram22
avatarUrl: https://avatars.githubusercontent.com/u/116367316?v=4 avatarUrl: https://avatars.githubusercontent.com/u/116367316?v=4
url: https://github.com/nanram22 url: https://github.com/nanram22
@ -29,15 +32,18 @@ sponsors:
- login: VincentParedes - login: VincentParedes
avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4 avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4
url: https://github.com/VincentParedes 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 - - login: getsentry
avatarUrl: https://avatars.githubusercontent.com/u/1396951?v=4 avatarUrl: https://avatars.githubusercontent.com/u/1396951?v=4
url: https://github.com/getsentry 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 avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
url: https://github.com/takashi-yoneya 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 - login: xoflare
avatarUrl: https://avatars.githubusercontent.com/u/74335107?v=4 avatarUrl: https://avatars.githubusercontent.com/u/74335107?v=4
url: https://github.com/xoflare url: https://github.com/xoflare
@ -50,12 +56,12 @@ sponsors:
- login: BoostryJP - login: BoostryJP
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4 avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
url: https://github.com/BoostryJP 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 - - login: HiredScore
avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4 avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4
url: https://github.com/HiredScore 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 - login: Trivie
avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4 avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4
url: https://github.com/Trivie url: https://github.com/Trivie
@ -74,9 +80,6 @@ sponsors:
- login: RodneyU215 - login: RodneyU215
avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4 avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4
url: https://github.com/RodneyU215 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 - login: americanair
avatarUrl: https://avatars.githubusercontent.com/u/12281813?v=4 avatarUrl: https://avatars.githubusercontent.com/u/12281813?v=4
url: https://github.com/americanair url: https://github.com/americanair
@ -92,11 +95,17 @@ sponsors:
- - login: indeedeng - - login: indeedeng
avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4 avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4
url: https://github.com/indeedeng 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 - - login: Kludex
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex url: https://github.com/Kludex
- login: samuelcolvin - 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 url: https://github.com/samuelcolvin
- login: jefftriplett - login: jefftriplett
avatarUrl: https://avatars.githubusercontent.com/u/50527?u=af1ddfd50f6afd6d99f333ba2ac8d0a5b245ea74&v=4 avatarUrl: https://avatars.githubusercontent.com/u/50527?u=af1ddfd50f6afd6d99f333ba2ac8d0a5b245ea74&v=4
@ -104,9 +113,6 @@ sponsors:
- login: jstanden - login: jstanden
avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4 avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4
url: https://github.com/jstanden 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 - login: dekoza
avatarUrl: https://avatars.githubusercontent.com/u/210980?u=c03c78a8ae1039b500dfe343665536ebc51979b2&v=4 avatarUrl: https://avatars.githubusercontent.com/u/210980?u=c03c78a8ae1039b500dfe343665536ebc51979b2&v=4
url: https://github.com/dekoza url: https://github.com/dekoza
@ -149,6 +155,9 @@ sponsors:
- login: zsinx6 - login: zsinx6
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4 avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
url: https://github.com/zsinx6 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 - login: aacayaco
avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4 avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4
url: https://github.com/aacayaco url: https://github.com/aacayaco
@ -194,9 +203,6 @@ sponsors:
- login: Shackelford-Arden - login: Shackelford-Arden
avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4 avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4
url: https://github.com/Shackelford-Arden 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 - login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
url: https://github.com/wdwinslow url: https://github.com/wdwinslow
@ -236,9 +242,6 @@ sponsors:
- login: ygorpontelo - login: ygorpontelo
avatarUrl: https://avatars.githubusercontent.com/u/32963605?u=35f7103f9c4c4c2589ae5737ee882e9375ef072e&v=4 avatarUrl: https://avatars.githubusercontent.com/u/32963605?u=35f7103f9c4c4c2589ae5737ee882e9375ef072e&v=4
url: https://github.com/ygorpontelo 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 - login: ProteinQure
avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4 avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4
url: https://github.com/ProteinQure url: https://github.com/ProteinQure
@ -281,9 +284,6 @@ sponsors:
- login: DelfinaCare - login: DelfinaCare
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4 avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
url: https://github.com/DelfinaCare url: https://github.com/DelfinaCare
- login: khoadaniel
avatarUrl: https://avatars.githubusercontent.com/u/84840546?v=4
url: https://github.com/khoadaniel
- login: osawa-koki - login: osawa-koki
avatarUrl: https://avatars.githubusercontent.com/u/94336223?u=59c6fe6945bcbbaff87b2a794238671b060620d2&v=4 avatarUrl: https://avatars.githubusercontent.com/u/94336223?u=59c6fe6945bcbbaff87b2a794238671b060620d2&v=4
url: https://github.com/osawa-koki url: https://github.com/osawa-koki
@ -327,14 +327,11 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4 avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4
url: https://github.com/browniebroke url: https://github.com/browniebroke
- login: janfilips - 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 url: https://github.com/janfilips
- login: WillHogan - login: WillHogan
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4 avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4
url: https://github.com/WillHogan 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 - login: my3
avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4 avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4
url: https://github.com/my3 url: https://github.com/my3
@ -344,12 +341,6 @@ sponsors:
- login: cbonoz - login: cbonoz
avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4 avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4
url: https://github.com/cbonoz 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 - login: anthonycorletti
avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4 avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4
url: https://github.com/anthonycorletti url: https://github.com/anthonycorletti
@ -359,6 +350,9 @@ sponsors:
- login: Alisa-lisa - login: Alisa-lisa
avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4 avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4
url: https://github.com/Alisa-lisa url: https://github.com/Alisa-lisa
- login: piotrgredowski
avatarUrl: https://avatars.githubusercontent.com/u/4294480?v=4
url: https://github.com/piotrgredowski
- login: danielunderwood - login: danielunderwood
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4 avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
url: https://github.com/danielunderwood url: https://github.com/danielunderwood
@ -383,6 +377,9 @@ sponsors:
- login: mattwelke - login: mattwelke
avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=80f02a799323b1472b389b836d95957c93a6d856&v=4 avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=80f02a799323b1472b389b836d95957c93a6d856&v=4
url: https://github.com/mattwelke url: https://github.com/mattwelke
- login: harsh183
avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4
url: https://github.com/harsh183
- login: hcristea - login: hcristea
avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=61d7a4fcf846983a4606788eac25e1c6c1209ba8&v=4 avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=61d7a4fcf846983a4606788eac25e1c6c1209ba8&v=4
url: https://github.com/hcristea url: https://github.com/hcristea
@ -428,9 +425,6 @@ sponsors:
- login: shuheng-liu - login: shuheng-liu
avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4 avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4
url: https://github.com/shuheng-liu 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 - login: pers0n4
avatarUrl: https://avatars.githubusercontent.com/u/24864600?u=f211a13a7b572cbbd7779b9c8d8cb428cc7ba07e&v=4 avatarUrl: https://avatars.githubusercontent.com/u/24864600?u=f211a13a7b572cbbd7779b9c8d8cb428cc7ba07e&v=4
url: https://github.com/pers0n4 url: https://github.com/pers0n4
@ -458,9 +452,6 @@ sponsors:
- login: bnkc - login: bnkc
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=527044d90b5ebb7f8dad517db5da1f45253b774b&v=4 avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=527044d90b5ebb7f8dad517db5da1f45253b774b&v=4
url: https://github.com/bnkc 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 - login: declon
avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4 avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4
url: https://github.com/declon url: https://github.com/declon
@ -476,6 +467,9 @@ sponsors:
- login: ArtyomVancyan - login: ArtyomVancyan
avatarUrl: https://avatars.githubusercontent.com/u/44609997?v=4 avatarUrl: https://avatars.githubusercontent.com/u/44609997?v=4
url: https://github.com/ArtyomVancyan 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 - login: hgalytoby
avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=f4888c2c54929bd86eed0d3971d09fcb306e5088&v=4 avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=f4888c2c54929bd86eed0d3971d09fcb306e5088&v=4
url: https://github.com/hgalytoby url: https://github.com/hgalytoby
@ -485,27 +479,36 @@ sponsors:
- login: conservative-dude - login: conservative-dude
avatarUrl: https://avatars.githubusercontent.com/u/55538308?u=f250c44942ea6e73a6bd90739b381c470c192c11&v=4 avatarUrl: https://avatars.githubusercontent.com/u/55538308?u=f250c44942ea6e73a6bd90739b381c470c192c11&v=4
url: https://github.com/conservative-dude 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 - login: 0417taehyun
avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4 avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4
url: https://github.com/0417taehyun url: https://github.com/0417taehyun
- - login: ssbarnea - - login: ssbarnea
avatarUrl: https://avatars.githubusercontent.com/u/102495?u=b4bf6818deefe59952ac22fec6ed8c76de1b8f7c&v=4 avatarUrl: https://avatars.githubusercontent.com/u/102495?u=b4bf6818deefe59952ac22fec6ed8c76de1b8f7c&v=4
url: https://github.com/ssbarnea url: https://github.com/ssbarnea
- login: tomast1337 - login: Patechoc
avatarUrl: https://avatars.githubusercontent.com/u/15125899?u=2c2f2907012d820499e2c43632389184923513fe&v=4 avatarUrl: https://avatars.githubusercontent.com/u/2376641?u=23b49e9eda04f078cb74fa3f93593aa6a57bb138&v=4
url: https://github.com/tomast1337 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 - login: sadikkuzu
avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=d179c06bb9f65c4167fcab118526819f8e0dac17&v=4 avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=d179c06bb9f65c4167fcab118526819f8e0dac17&v=4
url: https://github.com/sadikkuzu url: https://github.com/sadikkuzu
- login: ruizdiazever - login: ruizdiazever
avatarUrl: https://avatars.githubusercontent.com/u/29817086?u=2df54af55663d246e3a4dc8273711c37f1adb117&v=4 avatarUrl: https://avatars.githubusercontent.com/u/29817086?u=2df54af55663d246e3a4dc8273711c37f1adb117&v=4
url: https://github.com/ruizdiazever 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 - login: danburonline
avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4 avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4
url: https://github.com/danburonline 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 - login: rwxd
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4 avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4
url: https://github.com/rwxd url: https://github.com/rwxd
- login: ThomasPalma1
avatarUrl: https://avatars.githubusercontent.com/u/66331874?u=5763f7402d784ba189b60d704ff5849b4d0a63fb&v=4
url: https://github.com/ThomasPalma1

188
docs/en/data/people.yml

@ -1,16 +1,16 @@
maintainers: maintainers:
- login: tiangolo - login: tiangolo
answers: 1844 answers: 1849
prs: 430 prs: 466
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4
url: https://github.com/tiangolo url: https://github.com/tiangolo
experts: experts:
- login: Kludex - login: Kludex
count: 434 count: 463
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex url: https://github.com/Kludex
- login: dmontagu - login: dmontagu
count: 237 count: 239
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
url: https://github.com/dmontagu url: https://github.com/dmontagu
- login: Mause - login: Mause
@ -25,34 +25,34 @@ experts:
count: 193 count: 193
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT 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 - login: jgould22
count: 139 count: 157
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22 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 - login: phy25
count: 126 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 url: https://github.com/phy25
- login: iudeen - login: iudeen
count: 118 count: 121
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen url: https://github.com/iudeen
- login: raphaelauv - login: raphaelauv
count: 83 count: 83
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
url: https://github.com/raphaelauv 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 - login: ArcLightSlavik
count: 71 count: 71
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
url: https://github.com/ArcLightSlavik 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 - login: falkben
count: 57 count: 57
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=ad9838e089058c9e5a0bab94c0eec7cc181e0cd0&v=4 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=ad9838e089058c9e5a0bab94c0eec7cc181e0cd0&v=4
@ -61,10 +61,10 @@ experts:
count: 49 count: 49
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
url: https://github.com/sm-Fifteen url: https://github.com/sm-Fifteen
- login: adriangb - login: insomnes
count: 45 count: 45
avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4 avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
url: https://github.com/adriangb url: https://github.com/insomnes
- login: yinziyan1206 - login: yinziyan1206
count: 45 count: 45
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4 avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
@ -73,22 +73,22 @@ experts:
count: 45 count: 45
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
url: https://github.com/acidjunk 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 - login: Dustyposa
count: 45 count: 45
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
url: https://github.com/Dustyposa url: https://github.com/Dustyposa
- login: odiseo0 - login: adriangb
count: 43 count: 44
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=2da05dab6cc8e1ade557801634760a56e4101796&v=4 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4
url: https://github.com/odiseo0 url: https://github.com/adriangb
- login: frankie567 - login: frankie567
count: 43 count: 43
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
url: https://github.com/frankie567 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 - login: includeamin
count: 40 count: 40
avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
@ -97,14 +97,14 @@ experts:
count: 37 count: 37
avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4
url: https://github.com/STeveShary 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 - login: krishnardt
count: 35 count: 35
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
url: https://github.com/krishnardt 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 - login: panla
count: 32 count: 32
avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4
@ -121,38 +121,38 @@ experts:
count: 25 count: 25
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes 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 - login: SirTelemak
count: 23 count: 23
avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
url: https://github.com/SirTelemak 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 - login: rafsaf
count: 21 count: 21
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4 avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
url: https://github.com/rafsaf url: https://github.com/rafsaf
- login: chris-allnutt - login: n8sty
count: 20 count: 20
avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
url: https://github.com/chris-allnutt url: https://github.com/n8sty
- login: nsidnev - login: nsidnev
count: 20 count: 20
avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4 avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4
url: https://github.com/nsidnev 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 count: 18
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4
url: https://github.com/n8sty url: https://github.com/zoliknemet
- login: retnikt - login: retnikt
count: 18 count: 18
avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4
url: https://github.com/retnikt 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 - login: Hultner
count: 17 count: 17
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 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 avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
url: https://github.com/jorgerpo url: https://github.com/jorgerpo
last_month_active: 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 - login: Kludex
count: 13 count: 24
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex url: https://github.com/Kludex
- login: abhint - login: jgould22
count: 5 count: 17
avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=b5d219277b4d001ac26fb8be357fddd88c29d51b&v=4 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/abhint url: https://github.com/jgould22
- login: chrisK824
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4
url: https://github.com/chrisK824
- login: arjwilliams - login: arjwilliams
count: 3 count: 8
avatarUrl: https://avatars.githubusercontent.com/u/22227620?v=4 avatarUrl: https://avatars.githubusercontent.com/u/22227620?v=4
url: https://github.com/arjwilliams 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 - login: Ahmed-Abdou14
count: 3 count: 4
avatarUrl: https://avatars.githubusercontent.com/u/104530599?u=d1e1c064d57c3ad5b6481716928da840f6d5a492&v=4 avatarUrl: https://avatars.githubusercontent.com/u/104530599?u=05365b155a1ff911532e8be316acfad2e0736f98&v=4
url: https://github.com/Ahmed-Abdou14 url: https://github.com/Ahmed-Abdou14
- login: esrefzeki - login: iudeen
count: 3 count: 3
avatarUrl: https://avatars.githubusercontent.com/u/54935247?u=193cf5a169ca05fc54995a4dceabc82c7dc6e5ea&v=4 avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/esrefzeki 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: top_contributors:
- login: waynerv - login: waynerv
count: 25 count: 25
@ -240,7 +232,7 @@ top_contributors:
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
url: https://github.com/tokusumi url: https://github.com/tokusumi
- login: Kludex - login: Kludex
count: 20 count: 21
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex url: https://github.com/Kludex
- login: jaystone776 - login: jaystone776
@ -264,7 +256,7 @@ top_contributors:
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
url: https://github.com/mariacamilagl url: https://github.com/mariacamilagl
- login: Smlep - login: Smlep
count: 10 count: 11
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
url: https://github.com/Smlep url: https://github.com/Smlep
- login: Serrones - login: Serrones
@ -287,6 +279,10 @@ top_contributors:
count: 7 count: 7
avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4 avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4
url: https://github.com/Alexandrhub 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 - login: batlopes
count: 6 count: 6
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4 avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
@ -297,7 +293,7 @@ top_contributors:
url: https://github.com/wshayes url: https://github.com/wshayes
- login: samuelcolvin - login: samuelcolvin
count: 5 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 url: https://github.com/samuelcolvin
- login: SwftAlpc - login: SwftAlpc
count: 5 count: 5
@ -311,10 +307,6 @@ top_contributors:
count: 5 count: 5
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4 avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4
url: https://github.com/ComicShrimp 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 - login: jekirl
count: 4 count: 4
avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4 avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4
@ -335,10 +327,18 @@ top_contributors:
count: 4 count: 4
avatarUrl: https://avatars.githubusercontent.com/u/3360631?u=5fa1f475ad784d64eb9666bdd43cc4d285dcc773&v=4 avatarUrl: https://avatars.githubusercontent.com/u/3360631?u=5fa1f475ad784d64eb9666bdd43cc4d285dcc773&v=4
url: https://github.com/hitrust 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 - login: lsglucas
count: 4 count: 4
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas 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 - login: axel584
count: 4 count: 4
avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4 avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4
@ -349,7 +349,7 @@ top_contributors:
url: https://github.com/ivan-abc url: https://github.com/ivan-abc
top_reviewers: top_reviewers:
- login: Kludex - login: Kludex
count: 122 count: 136
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex url: https://github.com/Kludex
- login: BilalAlpaslan - login: BilalAlpaslan
@ -357,7 +357,7 @@ top_reviewers:
avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
url: https://github.com/BilalAlpaslan url: https://github.com/BilalAlpaslan
- login: yezz123 - login: yezz123
count: 77 count: 78
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=d7062cbc6eb7671d5dc9cc0e32a24ae335e0f225&v=4 avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=d7062cbc6eb7671d5dc9cc0e32a24ae335e0f225&v=4
url: https://github.com/yezz123 url: https://github.com/yezz123
- login: tokusumi - login: tokusumi
@ -372,20 +372,20 @@ top_reviewers:
count: 47 count: 47
avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4 avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4
url: https://github.com/Laineyzhang55 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 - login: ycd
count: 45 count: 45
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
url: https://github.com/ycd 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 - login: cikay
count: 41 count: 41
avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4
url: https://github.com/cikay url: https://github.com/cikay
- login: Xewus - login: Xewus
count: 35 count: 38
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4 avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
url: https://github.com/Xewus url: https://github.com/Xewus
- login: JarroVGIT - login: JarroVGIT
@ -412,6 +412,10 @@ top_reviewers:
count: 26 count: 26
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas 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 - login: Ryandaydev
count: 24 count: 24
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=809f3d1074d04bbc28012a7f17f06ea56f5bd71a&v=4 avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=809f3d1074d04bbc28012a7f17f06ea56f5bd71a&v=4
@ -420,10 +424,6 @@ top_reviewers:
count: 23 count: 23
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
url: https://github.com/dmontagu 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 - login: rjNemo
count: 21 count: 21
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
@ -434,7 +434,7 @@ top_reviewers:
url: https://github.com/hard-coders url: https://github.com/hard-coders
- login: odiseo0 - login: odiseo0
count: 20 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 url: https://github.com/odiseo0
- login: 0417taehyun - login: 0417taehyun
count: 19 count: 19
@ -456,6 +456,10 @@ top_reviewers:
count: 16 count: 16
avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4 avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
url: https://github.com/SwftAlpc 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 - login: DevDae
count: 16 count: 16
avatarUrl: https://avatars.githubusercontent.com/u/87962045?u=08e10fa516e844934f4b3fc7c38b33c61697e4a1&v=4 avatarUrl: https://avatars.githubusercontent.com/u/87962045?u=08e10fa516e844934f4b3fc7c38b33c61697e4a1&v=4
@ -488,10 +492,6 @@ top_reviewers:
count: 12 count: 12
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4
url: https://github.com/RunningIkkyu 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 - login: ivan-abc
count: 12 count: 12
avatarUrl: https://avatars.githubusercontent.com/u/36765187?u=c6e0ba571c1ccb6db9d94e62e4b8b5eda811a870&v=4 avatarUrl: https://avatars.githubusercontent.com/u/36765187?u=c6e0ba571c1ccb6db9d94e62e4b8b5eda811a870&v=4
@ -500,6 +500,10 @@ top_reviewers:
count: 11 count: 11
avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=789927ee09cfabd752d3bd554fa6baf4850d2777&v=4 avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=789927ee09cfabd752d3bd554fa6baf4850d2777&v=4
url: https://github.com/solomein-sv 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 - login: mariacamilagl
count: 10 count: 10
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
@ -540,7 +544,3 @@ top_reviewers:
count: 9 count: 9
avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4 avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4
url: https://github.com/bezaca url: https://github.com/bezaca
- login: oandersonmagalhaes
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/83456692?v=4
url: https://github.com/oandersonmagalhaes

2
docs/en/data/sponsors.yml

@ -7,7 +7,7 @@ gold:
img: https://fastapi.tiangolo.com/img/sponsors/platform-sh.png 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 - url: https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge
title: Fern | SDKs and API docs 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: silver:
- url: https://www.deta.sh/?ref=fastapi - url: https://www.deta.sh/?ref=fastapi
title: The launchpad for all your (team's) ideas title: The launchpad for all your (team's) ideas

5
docs/en/docs/advanced/generate-clients.md

@ -12,6 +12,11 @@ A common tool is <a href="https://openapi-generator.tech/" class="external-link"
If you are building a **frontend**, a very interesting alternative is <a href="https://github.com/ferdikoomen/openapi-typescript-codegen" class="external-link" target="_blank">openapi-typescript-codegen</a>. If you are building a **frontend**, a very interesting alternative is <a href="https://github.com/ferdikoomen/openapi-typescript-codegen" class="external-link" target="_blank">openapi-typescript-codegen</a>.
Another option you could consider for several languages is <a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=docs-generate-clients" class="external-link" target="_blank">Fern</a>.
!!! info
<a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=docs-generate-clients" class="external-link" target="_blank">Fern</a> is also a FastAPI sponsor. 😎🎉
## Generate a TypeScript Frontend Client ## Generate a TypeScript Frontend Client
Let's start with a simple FastAPI application: Let's start with a simple FastAPI application:

2
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**). 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 <a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=docs-alternatives" class="external-link" target="_blank">Fern</a> which is also a FastAPI sponsor. 😎🎉
### Flask REST frameworks ### 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. 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.

2
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. That way, you don't have to "install" your local version to be able to test every change.
!!! note "Technical Details" !!! 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. 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.

1
docs/en/docs/img/sponsors/fern-banner.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

1
docs/en/docs/img/sponsors/fern.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 349 KiB

46
docs/en/docs/release-notes.md

@ -2,8 +2,52 @@
## Latest Changes ## 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). * 🌐 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 ## 0.100.1
### Fixes ### Fixes
@ -66,7 +110,7 @@ A command line tool that will **process your code** and update most of the thing
### Pydantic v1 ### 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. 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.

2
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: 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!} {!../../../docs_src/bigger_applications/app/main.py!}
``` ```

2
docs/en/overrides/main.html

@ -37,7 +37,7 @@
<div class="item"> <div class="item">
<a title="Fern | SDKs and API docs" style="display: block; position: relative;" href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=top-banner" target="_blank"> <a title="Fern | SDKs and API docs" style="display: block; position: relative;" href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=top-banner" target="_blank">
<span class="sponsor-badge">sponsor</span> <span class="sponsor-badge">sponsor</span>
<img class="sponsor-image" src="/img/sponsors/fern-banner.png" /> <img class="sponsor-image" src="/img/sponsors/fern-banner.svg" />
</a> </a>
</div> </div>
</div> </div>

34
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 для целой группы *операций пути*.

101
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**.
И вы также увидите, как он автоматически интегрируется в систему интерактивной документации.

52
docs/ur/docs/benchmarks.md

@ -0,0 +1,52 @@
# بینچ مارکس
انڈیپنڈنٹ ٹیک امپور بینچ مارک **FASTAPI** Uvicorn کے تحت چلنے والی ایپلی کیشنز کو <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank"> ایک تیز رفتار Python فریم ورک میں سے ایک </a> ، صرف Starlette اور Uvicorn کے نیچے ( FASTAPI کے ذریعہ اندرونی طور پر استعمال کیا جاتا ہے ) (*)
لیکن جب بینچ مارک اور موازنہ کی جانچ پڑتال کرتے ہو تو آپ کو مندرجہ ذیل بات ذہن میں رکھنی چاہئے.
## بینچ مارک اور رفتار
جب آپ بینچ مارک کی جانچ کرتے ہیں تو ، مساوی کے مقابلے میں مختلف اقسام کے متعدد اوزار دیکھنا عام ہے.
خاص طور پر ، Uvicorn, Starlette اور FastAPI کو دیکھنے کے لئے ( بہت سے دوسرے ٹولز ) کے ساتھ موازنہ کیا گیا.
ٹول کے ذریعہ حل ہونے والا آسان مسئلہ ، اس کی بہتر کارکردگی ہوگی. اور زیادہ تر بینچ مارک ٹول کے ذریعہ فراہم کردہ اضافی خصوصیات کی جانچ نہیں کرتے ہیں.
درجہ بندی کی طرح ہے:
<ul style="direction: rtl;">
<li><div style="text-align: right;">ASGI :<b>Uvicorn</b> سرور</div></li>
<ul>
<li><div style="text-align: right;"><b>Starlette</b>: (Uvicorn استعمال کرتا ہے) ایک ویب مائیکرو فریم ورک </div></li>
<ul>
<li><div style="text-align: right;"><b>FastAPI</b>: (Starlette کا استعمال کرتا ہے) ایک API مائکرو فریم ورک جس میں APIs بنانے کے لیے کئی اضافی خصوصیات ہیں، ڈیٹا کی توثیق وغیرہ کے ساتھ۔</div></li>
</ul>
</ul>
</ul>
<ul style="direction: rtl;">
<li><div style="text-align: right;"><b>Uvicorn</b>:</div></li>
<ul>
<li><div style="text-align: right;">بہترین کارکردگی ہوگی، کیونکہ اس میں سرور کے علاوہ زیادہ اضافی کوڈ نہیں ہے۔</div></li>
<li><div style="text-align: right;">آپ براہ راست Uvicorn میں درخواست نہیں لکھیں گے۔ اس کا مطلب یہ ہوگا کہ آپ کے کوڈ میں کم و بیش، کم از کم، Starlette (یا <b>FastAPI</b>) کی طرف سے فراہم کردہ تمام کوڈ شامل کرنا ہوں گے۔ اور اگر آپ نے ایسا کیا تو، آپ کی حتمی ایپلیکیشن کا وہی اوور ہیڈ ہوگا جیسا کہ ایک فریم ورک استعمال کرنے اور آپ کے ایپ کوڈ اور کیڑے کو کم سے کم کرنا۔</div></li>
<li><div style="text-align: right;">اگر آپ Uvicorn کا موازنہ کر رہے ہیں تو اس کا موازنہ Daphne، Hypercorn، uWSGI وغیرہ ایپلیکیشن سرورز سے کریں۔</div></li>
</ul>
</ul>
<ul style="direction: rtl;">
<li><div style="text-align: right;"><b>Starlette</b>:</div></li>
<ul>
<li><div style="text-align: right;">Uvicorn کے بعد اگلی بہترین کارکردگی ہوگی۔ درحقیقت، Starlette چلانے کے لیے Uvicorn کا استعمال کرتی ہے۔ لہذا، یہ شاید زیادہ کوڈ پر عمل درآمد کرکے Uvicorn سے "سست" ہوسکتا ہے۔</div></li>
<li><div style="text-align: right;">لیکن یہ آپ کو آسان ویب ایپلیکیشنز بنانے کے لیے ٹولز فراہم کرتا ہے، راستوں پر مبنی روٹنگ کے ساتھ، وغیرہ۔</div></li>
<li><div style="text-align: right;">اگر آپ سٹارلیٹ کا موازنہ کر رہے ہیں تو اس کا موازنہ Sanic، Flask، Django وغیرہ سے کریں۔ ویب فریم ورکس (یا مائیکرو فریم ورکس)</div></li>
</ul>
</ul>
<ul style="direction: rtl;">
<li><div style="text-align: right;"><b>FastAPI</b>:</div></li>
<ul>
<li><div style="text-align: right;">جس طرح سے Uvicorn Starlette کا استعمال کرتا ہے اور اس سے تیز نہیں ہو سکتا، Starlette <b>FastAPI</b> کا استعمال کرتا ہے، اس لیے یہ اس سے تیز نہیں ہو سکتا۔</div></li>
<li><div style="text-align: right;">Starlette FastAPI کے اوپری حصے میں مزید خصوصیات فراہم کرتا ہے۔ وہ خصوصیات جن کی آپ کو APIs بناتے وقت تقریباً ہمیشہ ضرورت ہوتی ہے، جیسے ڈیٹا کی توثیق اور سیریلائزیشن۔ اور اسے استعمال کرنے سے، آپ کو خودکار دستاویزات مفت میں مل جاتی ہیں (خودکار دستاویزات چلنے والی ایپلی کیشنز میں اوور ہیڈ کو بھی شامل نہیں کرتی ہیں، یہ اسٹارٹ اپ پر تیار ہوتی ہیں)۔</div></li>
<li><div style="text-align: right;">اگر آپ نے FastAPI کا استعمال نہیں کیا ہے اور Starlette کو براہ راست استعمال کیا ہے (یا کوئی دوسرا ٹول، جیسے Sanic، Flask، Responder، وغیرہ) آپ کو تمام ڈیٹا کی توثیق اور سیریلائزیشن کو خود نافذ کرنا ہوگا۔ لہذا، آپ کی حتمی ایپلیکیشن اب بھی وہی اوور ہیڈ ہوگی جیسا کہ اسے FastAPI کا استعمال کرتے ہوئے بنایا گیا تھا۔ اور بہت سے معاملات میں، یہ ڈیٹا کی توثیق اور سیریلائزیشن ایپلی کیشنز میں لکھے گئے کوڈ کی سب سے بڑی مقدار ہے۔</div></li>
<li><div style="text-align: right;">لہذا، FastAPI کا استعمال کرکے آپ ترقیاتی وقت، Bugs، کوڈ کی لائنوں کی بچت کر رہے ہیں، اور شاید آپ کو وہی کارکردگی (یا بہتر) ملے گی اگر آپ اسے استعمال نہیں کرتے (جیسا کہ آپ کو یہ سب اپنے کوڈ میں لاگو کرنا ہوگا۔ )</div></li>
<li><div style="text-align: right;">اگر آپ FastAPI کا موازنہ کر رہے ہیں، تو اس کا موازنہ ویب ایپلیکیشن فریم ورک (یا ٹولز کے سیٹ) سے کریں جو ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات فراہم کرتا ہے، جیسے Flask-apispec، NestJS، Molten، وغیرہ۔ مربوط خودکار ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات کے ساتھ فریم ورک۔</div></li>
</ul>
</ul>

1
docs/ur/mkdocs.yml

@ -0,0 +1 @@
INHERIT: ../en/mkdocs.yml

2
fastapi/__init__.py

@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production""" """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 from starlette import status as status

2
fastapi/concurrency.py

@ -19,7 +19,7 @@ async def contextmanager_in_threadpool(
) -> AsyncGenerator[_T, None]: ) -> AsyncGenerator[_T, None]:
# blocking __exit__ from running waiting on a free thread # blocking __exit__ from running waiting on a free thread
# can create race conditions/deadlocks if the context manager itself # 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 # 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 # since we're creating a new limiter for each call, any non-zero limit
# works (1 is arbitrary) # works (1 is arbitrary)

6
fastapi/params.py

@ -69,7 +69,7 @@ class Param(FieldInfo):
self.deprecated = deprecated self.deprecated = deprecated
if example is not _Unset: if example is not _Unset:
warnings.warn( warnings.warn(
"`example` has been depreacated, please use `examples` instead", "`example` has been deprecated, please use `examples` instead",
category=DeprecationWarning, category=DeprecationWarning,
stacklevel=4, stacklevel=4,
) )
@ -98,7 +98,7 @@ class Param(FieldInfo):
kwargs["examples"] = examples kwargs["examples"] = examples
if regex is not None: if regex is not None:
warnings.warn( warnings.warn(
"`regex` has been depreacated, please use `pattern` instead", "`regex` has been deprecated, please use `pattern` instead",
category=DeprecationWarning, category=DeprecationWarning,
stacklevel=4, stacklevel=4,
) )
@ -512,7 +512,7 @@ class Body(FieldInfo):
self.deprecated = deprecated self.deprecated = deprecated
if example is not _Unset: if example is not _Unset:
warnings.warn( warnings.warn(
"`example` has been depreacated, please use `examples` instead", "`example` has been deprecated, please use `examples` instead",
category=DeprecationWarning, category=DeprecationWarning,
stacklevel=4, stacklevel=4,
) )

8
fastapi/routing.py

@ -83,7 +83,7 @@ def _prepare_response_content(
if read_with_orm_mode: if read_with_orm_mode:
# Let from_orm extract the data from this model instead of converting # Let from_orm extract the data from this model instead of converting
# it now to a dict. # 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. # access instead of dict iteration, e.g. lazy relationships.
return res return res
return _model_dump( return _model_dump(
@ -448,9 +448,7 @@ class APIRoute(routing.Route):
self.response_field = create_response_field( self.response_field = create_response_field(
name=response_name, name=response_name,
type_=self.response_model, type_=self.response_model,
# TODO: This should actually set mode='serialization', just, that changes the schemas mode="serialization",
# mode="serialization",
mode="validation",
) )
# Create a clone of the field, so that a Pydantic submodel is not returned # 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 # 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 # that doesn't have the hashed_password. But because it's a subclass, it
# would pass the validation and be returned as is. # would pass the validation and be returned as is.
# By being a new field, no inheritance will be passed as is. A new model # 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 # TODO: remove when deprecating Pydantic v1
self.secure_cloned_response_field: Optional[ self.secure_cloned_response_field: Optional[
ModelField ModelField

2
pyproject.toml

@ -42,7 +42,7 @@ classifiers = [
] ]
dependencies = [ dependencies = [
"starlette>=0.27.0,<0.28.0", "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", "typing-extensions>=4.5.0",
] ]
dynamic = ["version"] dynamic = ["version"]

3
requirements-docs.txt

@ -1,6 +1,5 @@
-e . -e .
mkdocs==1.4.3 mkdocs-material==9.1.21
mkdocs-material==9.1.17
mdx-include >=1.4.1,<2.0.0 mdx-include >=1.4.1,<2.0.0
mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0 mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0
typer-cli >=0.0.13,<0.0.14 typer-cli >=0.0.13,<0.0.14

2
requirements-tests.txt

@ -2,7 +2,7 @@
pydantic-settings >=2.0.0 pydantic-settings >=2.0.0
pytest >=7.1.3,<8.0.0 pytest >=7.1.3,<8.0.0
coverage[toml] >= 6.5.0,< 8.0 coverage[toml] >= 6.5.0,< 8.0
mypy ==1.4.0 mypy ==1.4.1
ruff ==0.0.275 ruff ==0.0.275
black == 23.3.0 black == 23.3.0
httpx >=0.23.0,<0.25.0 httpx >=0.23.0,<0.25.0

77
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",
}
}
},
}

10
tests/test_filter_pydantic_sub_model_pv2.py

@ -1,7 +1,7 @@
from typing import Optional from typing import Optional
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import HasRepr, IsDict, IsOneOf
from fastapi import Depends, FastAPI from fastapi import Depends, FastAPI
from fastapi.exceptions import ResponseValidationError from fastapi.exceptions import ResponseValidationError
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
@ -66,7 +66,7 @@ def test_validator_is_cloned(client: TestClient):
"loc": ("response", "name"), "loc": ("response", "name"),
"msg": "Value error, name must end in A", "msg": "Value error, name must end in A",
"input": "modelX", "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"), "url": match_pydantic_error_url("value_error"),
} }
) )
@ -139,7 +139,11 @@ def test_openapi_schema(client: TestClient):
}, },
"ModelA": { "ModelA": {
"title": "ModelA", "title": "ModelA",
"required": ["name", "foo"], "required": IsOneOf(
["name", "description", "foo"],
# TODO remove when deprecating Pydantic v1
["name", "foo"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

5
tests/test_jsonable_encoder.py

@ -247,8 +247,9 @@ def test_encode_model_with_pure_path():
class Config: class Config:
arbitrary_types_allowed = True arbitrary_types_allowed = True
obj = ModelWithPath(path=PurePath("/foo", "bar")) test_path = PurePath("/foo", "bar")
assert jsonable_encoder(obj) == {"path": "/foo/bar"} obj = ModelWithPath(path=test_path)
assert jsonable_encoder(obj) == {"path": str(test_path)}
def test_encode_model_with_pure_posix_path(): def test_encode_model_with_pure_posix_path():

34
tests/test_multi_body_errors.py

@ -51,7 +51,7 @@ def test_jsonable_encoder_requiring_error():
"loc": ["body", 0, "age"], "loc": ["body", 0, "age"],
"msg": "Input should be greater than 0", "msg": "Input should be greater than 0",
"input": -1.0, "input": -1.0,
"ctx": {"gt": 0.0}, "ctx": {"gt": "0"},
"url": match_pydantic_error_url("greater_than"), "url": match_pydantic_error_url("greater_than"),
} }
] ]
@ -84,9 +84,23 @@ def test_put_incorrect_body_multiple():
"input": {"age": "five"}, "input": {"age": "five"},
"url": match_pydantic_error_url("missing"), "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", "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", "msg": "Input should be a valid decimal",
"input": "five", "input": "five",
}, },
@ -97,9 +111,23 @@ def test_put_incorrect_body_multiple():
"input": {"age": "six"}, "input": {"age": "six"},
"url": match_pydantic_error_url("missing"), "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", "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", "msg": "Input should be a valid decimal",
"input": "six", "input": "six",
}, },

210
tests/test_tutorial/test_body_updates/test_tutorial001.py

@ -1,7 +1,8 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
def get_client(): def get_client():
@ -36,7 +37,181 @@ def test_put(client: TestClient):
} }
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -124,36 +299,9 @@ def test_openapi_schema(client: TestClient):
"title": "Item", "title": "Item",
"type": "object", "type": "object",
"properties": { "properties": {
"name": IsDict( "name": {"title": "Name", "type": "string"},
{ "description": {"title": "Description", "type": "string"},
"title": "Name", "price": {"title": "Price", "type": "number"},
"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"}
),
"tax": {"title": "Tax", "type": "number", "default": 10.5}, "tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": { "tags": {
"title": "Tags", "title": "Tags",

211
tests/test_tutorial/test_body_updates/test_tutorial001_py310.py

@ -1,8 +1,7 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
@ -41,7 +40,182 @@ def test_put(client: TestClient):
@needs_py310 @needs_py310
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -129,36 +303,9 @@ def test_openapi_schema(client: TestClient):
"title": "Item", "title": "Item",
"type": "object", "type": "object",
"properties": { "properties": {
"name": IsDict( "name": {"title": "Name", "type": "string"},
{ "description": {"title": "Description", "type": "string"},
"title": "Name", "price": {"title": "Price", "type": "number"},
"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"}
),
"tax": {"title": "Tax", "type": "number", "default": 10.5}, "tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": { "tags": {
"title": "Tags", "title": "Tags",

211
tests/test_tutorial/test_body_updates/test_tutorial001_py39.py

@ -1,8 +1,7 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
@ -41,7 +40,182 @@ def test_put(client: TestClient):
@needs_py39 @needs_py39
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -129,36 +303,9 @@ def test_openapi_schema(client: TestClient):
"title": "Item", "title": "Item",
"type": "object", "type": "object",
"properties": { "properties": {
"name": IsDict( "name": {"title": "Name", "type": "string"},
{ "description": {"title": "Description", "type": "string"},
"title": "Name", "price": {"title": "Price", "type": "number"},
"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"}
),
"tax": {"title": "Tax", "type": "number", "default": 10.5}, "tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": { "tags": {
"title": "Tags", "title": "Tags",

12
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 fastapi.testclient import TestClient
from docs_src.dataclasses.tutorial002 import app from docs_src.dataclasses.tutorial002 import app
@ -21,8 +21,7 @@ def test_get_item():
def test_openapi_schema(): def test_openapi_schema():
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200 assert response.status_code == 200
data = response.json() assert response.json() == {
assert data == {
"openapi": "3.1.0", "openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"}, "info": {"title": "FastAPI", "version": "0.1.0"},
"paths": { "paths": {
@ -47,7 +46,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "price", "tags", "description", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
@ -57,7 +60,6 @@ def test_openapi_schema():
"title": "Tags", "title": "Tags",
"type": "array", "type": "array",
"items": {"type": "string"}, "items": {"type": "string"},
"default": [],
} }
) )
| IsDict( | IsDict(

185
tests/test_tutorial/test_dataclasses/test_tutorial003.py

@ -1,8 +1,9 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.dataclasses.tutorial003 import app from docs_src.dataclasses.tutorial003 import app
from ...utils import needs_pydanticv1, needs_pydanticv2
client = TestClient(app) client = TestClient(app)
@ -52,6 +53,7 @@ def test_get_authors():
] ]
@needs_pydanticv2
def test_openapi_schema(): def test_openapi_schema():
response = client.get("/openapi.json") response = client.get("/openapi.json")
assert response.status_code == 200 assert response.status_code == 200
@ -77,7 +79,7 @@ def test_openapi_schema():
"schema": { "schema": {
"title": "Items", "title": "Items",
"type": "array", "type": "array",
"items": {"$ref": "#/components/schemas/Item"}, "items": {"$ref": "#/components/schemas/ItemInput"},
} }
} }
}, },
@ -132,26 +134,164 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Author": { "Author": {
"title": "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"], "required": ["name"],
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"items": IsDict( "description": {
{ "title": "Description",
"title": "Items", "anyOf": [{"type": "string"}, {"type": "null"}],
"type": "array", },
"items": {"$ref": "#/components/schemas/Item"}, },
"default": [], },
} "ItemOutput": {
) "title": "Item",
| IsDict( "required": ["name", "description"],
# TODO: remove when deprecating Pydantic v1 "type": "object",
{ "properties": {
"title": "Items", "name": {"title": "Name", "type": "string"},
"type": "array", "description": {
"items": {"$ref": "#/components/schemas/Item"}, "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": { "HTTPValidationError": {
@ -171,16 +311,7 @@ def test_openapi_schema():
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
}, },
}, },
"ValidationError": { "ValidationError": {

13
tests/test_tutorial/test_extra_models/test_tutorial003.py

@ -1,3 +1,4 @@
from dirty_equals import IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.extra_models.tutorial003 import app from docs_src.extra_models.tutorial003 import app
@ -76,7 +77,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"PlaneItem": { "PlaneItem": {
"title": "PlaneItem", "title": "PlaneItem",
"required": ["description", "size"], "required": IsOneOf(
["description", "type", "size"],
# TODO: remove when deprecating Pydantic v1
["description", "size"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"description": {"title": "Description", "type": "string"}, "description": {"title": "Description", "type": "string"},
@ -86,7 +91,11 @@ def test_openapi_schema():
}, },
"CarItem": { "CarItem": {
"title": "CarItem", "title": "CarItem",
"required": ["description"], "required": IsOneOf(
["description", "type"],
# TODO: remove when deprecating Pydantic v1
["description"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"description": {"title": "Description", "type": "string"}, "description": {"title": "Description", "type": "string"},

13
tests/test_tutorial/test_extra_models/test_tutorial003_py310.py

@ -1,4 +1,5 @@
import pytest import pytest
from dirty_equals import IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -86,7 +87,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"PlaneItem": { "PlaneItem": {
"title": "PlaneItem", "title": "PlaneItem",
"required": ["description", "size"], "required": IsOneOf(
["description", "type", "size"],
# TODO: remove when deprecating Pydantic v1
["description", "size"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"description": {"title": "Description", "type": "string"}, "description": {"title": "Description", "type": "string"},
@ -96,7 +101,11 @@ def test_openapi_schema(client: TestClient):
}, },
"CarItem": { "CarItem": {
"title": "CarItem", "title": "CarItem",
"required": ["description"], "required": IsOneOf(
["description", "type"],
# TODO: remove when deprecating Pydantic v1
["description"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"description": {"title": "Description", "type": "string"}, "description": {"title": "Description", "type": "string"},

155
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 fastapi.testclient import TestClient
from docs_src.path_operation_advanced_configuration.tutorial004 import app from docs_src.path_operation_advanced_configuration.tutorial004 import app
from ...utils import needs_pydanticv1, needs_pydanticv2
client = TestClient(app) client = TestClient(app)
@ -18,7 +19,137 @@ def test_query_params_str_validations():
} }
@needs_pydanticv2
def test_openapi_schema(): 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") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -69,27 +200,9 @@ def test_openapi_schema():
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": {"title": "Price", "type": "number"}, "price": {"title": "Price", "type": "number"},
"tax": IsDict( "tax": {"title": "Tax", "type": "number"},
{
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Tax", "type": "number"}
),
"tags": { "tags": {
"title": "Tags", "title": "Tags",
"uniqueItems": True, "uniqueItems": True,

155
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 fastapi.testclient import TestClient
from docs_src.path_operation_configuration.tutorial005 import app from docs_src.path_operation_configuration.tutorial005 import app
from ...utils import needs_pydanticv1, needs_pydanticv2
client = TestClient(app) client = TestClient(app)
@ -18,7 +19,137 @@ def test_query_params_str_validations():
} }
@needs_pydanticv2
def test_openapi_schema(): 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") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -69,27 +200,9 @@ def test_openapi_schema():
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": {"title": "Price", "type": "number"}, "price": {"title": "Price", "type": "number"},
"tax": IsDict( "tax": {"title": "Tax", "type": "number"},
{
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Tax", "type": "number"}
),
"tags": { "tags": {
"title": "Tags", "title": "Tags",
"uniqueItems": True, "uniqueItems": True,

156
tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py

@ -1,8 +1,7 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
@ -27,7 +26,138 @@ def test_query_params_str_validations(client: TestClient):
@needs_py310 @needs_py310
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -78,27 +208,9 @@ def test_openapi_schema(client: TestClient):
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": {"title": "Price", "type": "number"}, "price": {"title": "Price", "type": "number"},
"tax": IsDict( "tax": {"title": "Tax", "type": "number"},
{
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Tax", "type": "number"}
),
"tags": { "tags": {
"title": "Tags", "title": "Tags",
"uniqueItems": True, "uniqueItems": True,

156
tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py

@ -1,8 +1,7 @@
import pytest import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39, needs_pydanticv1, needs_pydanticv2
@pytest.fixture(name="client") @pytest.fixture(name="client")
@ -27,7 +26,138 @@ def test_query_params_str_validations(client: TestClient):
@needs_py39 @needs_py39
@needs_pydanticv2
def test_openapi_schema(client: TestClient): 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") response = client.get("/openapi.json")
assert response.status_code == 200, response.text assert response.status_code == 200, response.text
assert response.json() == { assert response.json() == {
@ -78,27 +208,9 @@ def test_openapi_schema(client: TestClient):
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},
"description": IsDict( "description": {"title": "Description", "type": "string"},
{
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Description", "type": "string"}
),
"price": {"title": "Price", "type": "number"}, "price": {"title": "Price", "type": "number"},
"tax": IsDict( "tax": {"title": "Tax", "type": "number"},
{
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Tax", "type": "number"}
),
"tags": { "tags": {
"title": "Tags", "title": "Tags",
"uniqueItems": True, "uniqueItems": True,

8
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 fastapi.testclient import TestClient
from docs_src.response_model.tutorial003 import app from docs_src.response_model.tutorial003 import app
@ -70,7 +70,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"UserOut": { "UserOut": {
"title": "UserOut", "title": "UserOut",
"required": ["username", "email"], "required": IsOneOf(
["username", "email", "full_name"],
# TODO: remove when deprecating Pydantic v1
["username", "email"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
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 fastapi.testclient import TestClient
from docs_src.response_model.tutorial003_01 import app from docs_src.response_model.tutorial003_01 import app
@ -70,7 +70,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"BaseUser": { "BaseUser": {
"title": "BaseUser", "title": "BaseUser",
"required": ["username", "email"], "required": IsOneOf(
["username", "email", "full_name"],
# TODO: remove when deprecating Pydantic v1
["username", "email"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -79,7 +79,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"BaseUser": { "BaseUser": {
"title": "BaseUser", "title": "BaseUser",
"required": ["username", "email"], "required": IsOneOf(
["username", "email", "full_name"],
# TODO: remove when deprecating Pydantic v1
["username", "email"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial003_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -79,7 +79,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"UserOut": { "UserOut": {
"title": "UserOut", "title": "UserOut",
"required": ["username", "email"], "required": IsOneOf(
["username", "email", "full_name"],
# TODO: remove when deprecating Pydantic v1
["username", "email"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial004.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from docs_src.response_model.tutorial004 import app from docs_src.response_model.tutorial004 import app
@ -79,7 +79,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax", "tags"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial004_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -87,7 +87,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax", "tags"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial004_py39.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39
@ -87,7 +87,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax", "tags"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
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 fastapi.testclient import TestClient
from docs_src.response_model.tutorial005 import app from docs_src.response_model.tutorial005 import app
@ -102,7 +102,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial005_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -112,7 +112,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
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 fastapi.testclient import TestClient
from docs_src.response_model.tutorial006 import app from docs_src.response_model.tutorial006 import app
@ -102,7 +102,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
tests/test_tutorial/test_response_model/test_tutorial006_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -112,7 +112,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"Item": { "Item": {
"title": "Item", "title": "Item",
"required": ["name", "price"], "required": IsOneOf(
["name", "description", "price", "tax"],
# TODO: remove when deprecating Pydantic v1
["name", "price"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"name": {"title": "Name", "type": "string"}, "name": {"title": "Name", "type": "string"},

8
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 fastapi.testclient import TestClient
from docs_src.security.tutorial005 import ( from docs_src.security.tutorial005 import (
@ -267,7 +267,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
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 fastapi.testclient import TestClient
from docs_src.security.tutorial005_an import ( from docs_src.security.tutorial005_an import (
@ -267,7 +267,11 @@ def test_openapi_schema():
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005_an_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005_an_py39.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005_py310.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py310 from ...utils import needs_py310
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

8
tests/test_tutorial/test_security/test_tutorial005_py39.py

@ -1,5 +1,5 @@
import pytest import pytest
from dirty_equals import IsDict from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from ...utils import needs_py39 from ...utils import needs_py39
@ -295,7 +295,11 @@ def test_openapi_schema(client: TestClient):
"schemas": { "schemas": {
"User": { "User": {
"title": "User", "title": "User",
"required": ["username"], "required": IsOneOf(
["username", "email", "full_name", "disabled"],
# TODO: remove when deprecating Pydantic v1
["username"],
),
"type": "object", "type": "object",
"properties": { "properties": {
"username": {"title": "Username", "type": "string"}, "username": {"title": "Username", "type": "string"},

Loading…
Cancel
Save