From 2b1e5b9f829143eb232f585a18801f0f770bdd99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 16 May 2021 20:27:45 +0200 Subject: [PATCH 001/814] =?UTF-8?q?=F0=9F=91=B7=20Upgrade=20Issue=20Manage?= =?UTF-8?q?r=20GitHub=20Action=20(#3236)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/issue-manager.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/issue-manager.yml b/.github/workflows/issue-manager.yml index 712930e0b..e2fb4f7a4 100644 --- a/.github/workflows/issue-manager.yml +++ b/.github/workflows/issue-manager.yml @@ -6,23 +6,25 @@ on: issue_comment: types: - created - - edited issues: types: - labeled + pull_request_target: + types: + - labeled + workflow_dispatch: jobs: issue-manager: runs-on: ubuntu-latest steps: - - uses: tiangolo/issue-manager@0.2.0 + - uses: tiangolo/issue-manager@0.4.0 with: token: ${{ secrets.GITHUB_TOKEN }} config: > { "answered": { - "users": ["tiangolo", "dmontagu"], "delay": 864000, - "message": "Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues." + "message": "Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs." } } From aece74982d7c9c1acac98e2c872c4cb885677fc7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 16 May 2021 18:28:24 +0000 Subject: [PATCH 002/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 25c8d03ca..e8d5698de 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Upgrade Issue Manager GitHub Action. PR [#3236](https://github.com/tiangolo/fastapi/pull/3236) by [@tiangolo](https://github.com/tiangolo). ## 0.65.1 From d5b09cd95824a1bd1c5595c9a5e020a1d44ce6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 25 May 2021 17:05:04 +0200 Subject: [PATCH 003/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20new=20banner=20spo?= =?UTF-8?q?nsor=20badge=20for=20FastAPI=20courses=20bundle=20(#3288)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/css/custom.css | 5 +++++ .../docs/img/sponsors/fastapi-bundle-banner.png | Bin 0 -> 10577 bytes docs/en/overrides/main.html | 10 ++++++++-- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 docs/en/docs/img/sponsors/fastapi-bundle-banner.png diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css index 35ff9ef70..9449f0a79 100644 --- a/docs/en/docs/css/custom.css +++ b/docs/en/docs/css/custom.css @@ -89,6 +89,11 @@ a.announce-link:hover { z-index: 10; } +.announce-wrapper .sponsor-image { + display: block; + border-radius: 20px; +} + .announce-wrapper>div { min-height: 40px; display: flex; diff --git a/docs/en/docs/img/sponsors/fastapi-bundle-banner.png b/docs/en/docs/img/sponsors/fastapi-bundle-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..43a8cceec35448f58198e63615f58abae2f23269 GIT binary patch literal 10577 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 Am;e9( literal 0 HcmV?d00001 diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 25e973b81..e0783675b 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -16,9 +16,15 @@ From 3afce2c4b87ba821f6282a763384a321076dbd61 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 25 May 2021 15:06:28 +0000 Subject: [PATCH 005/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e8d5698de..03a276b83 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add new banner sponsor badge for FastAPI courses bundle. PR [#3288](https://github.com/tiangolo/fastapi/pull/3288) by [@tiangolo](https://github.com/tiangolo). * 👷 Upgrade Issue Manager GitHub Action. PR [#3236](https://github.com/tiangolo/fastapi/pull/3236) by [@tiangolo](https://github.com/tiangolo). ## 0.65.1 From 60918d25a1f28411638a258c4d99b147ddc555d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 26 May 2021 11:26:06 +0200 Subject: [PATCH 006/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20new=20gold=20spons?= =?UTF-8?q?or=20Jina=20=F0=9F=8E=89=20(#3291)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/en/data/sponsors.yml | 3 + docs/en/docs/img/sponsors/jina-banner.svg | 233 +++ docs/en/docs/img/sponsors/jina.svg | 1981 +++++++++++++++++++++ docs/en/overrides/main.html | 6 + 5 files changed, 2224 insertions(+) create mode 100644 docs/en/docs/img/sponsors/jina-banner.svg create mode 100644 docs/en/docs/img/sponsors/jina.svg diff --git a/README.md b/README.md index 19dba3ffc..0fb7cc704 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 5f56d9667..49df39c99 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -2,6 +2,9 @@ gold: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas img: https://fastapi.tiangolo.com/img/sponsors/deta.svg + - url: https://bit.ly/2QSouzH + title: "Jina: build neural search-as-a-service for any kind of data in just minutes." + img: https://fastapi.tiangolo.com/img/sponsors/jina.svg silver: - url: https://www.investsuite.com/jobs title: Wealthtech jobs with FastAPI diff --git a/docs/en/docs/img/sponsors/jina-banner.svg b/docs/en/docs/img/sponsors/jina-banner.svg new file mode 100644 index 000000000..ebde273ee --- /dev/null +++ b/docs/en/docs/img/sponsors/jina-banner.svg @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/docs/img/sponsors/jina.svg b/docs/en/docs/img/sponsors/jina.svg new file mode 100644 index 000000000..3dda4fe3c --- /dev/null +++ b/docs/en/docs/img/sponsors/jina.svg @@ -0,0 +1,1981 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index e0783675b..601d44afb 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -27,6 +27,12 @@ + {% endblock %} From 40bb0c5f362665cee32a14ee1ff9c8b2f110684c Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 26 May 2021 09:26:47 +0000 Subject: [PATCH 007/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 03a276b83..7c18831f9 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add new gold sponsor Jina 🎉. PR [#3291](https://github.com/tiangolo/fastapi/pull/3291) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new banner sponsor badge for FastAPI courses bundle. PR [#3288](https://github.com/tiangolo/fastapi/pull/3288) by [@tiangolo](https://github.com/tiangolo). * 👷 Upgrade Issue Manager GitHub Action. PR [#3236](https://github.com/tiangolo/fastapi/pull/3236) by [@tiangolo](https://github.com/tiangolo). From 36772548b7fe7556cfcb37679b80485301174856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 7 Jun 2021 10:52:44 +0200 Subject: [PATCH 008/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20sponsors=20badg?= =?UTF-8?q?e,=20course=20bundle=20(#3340)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔧 Update sponsors badge, course bundle * 🍱 Update course bundle SVG sizes --- .../img/sponsors/fastapi-bundle-banner.png | Bin 10577 -> 0 bytes .../sponsors/fastapi-course-bundle-banner.svg | 293 ++++++++++++++++++ docs/en/overrides/main.html | 4 +- 3 files changed, 295 insertions(+), 2 deletions(-) delete mode 100644 docs/en/docs/img/sponsors/fastapi-bundle-banner.png create mode 100644 docs/en/docs/img/sponsors/fastapi-course-bundle-banner.svg diff --git a/docs/en/docs/img/sponsors/fastapi-bundle-banner.png b/docs/en/docs/img/sponsors/fastapi-bundle-banner.png deleted file mode 100644 index 43a8cceec35448f58198e63615f58abae2f23269..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10577 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 Am;e9( diff --git a/docs/en/docs/img/sponsors/fastapi-course-bundle-banner.svg b/docs/en/docs/img/sponsors/fastapi-course-bundle-banner.svg new file mode 100644 index 000000000..5dd89b212 --- /dev/null +++ b/docs/en/docs/img/sponsors/fastapi-course-bundle-banner.svg @@ -0,0 +1,293 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 601d44afb..8e698bffd 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -22,9 +22,9 @@
From 90120dd6e83d997fa2f7f54119a2e0cf906b1ded Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 7 Jun 2021 08:53:24 +0000 Subject: [PATCH 009/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7c18831f9..588ca1661 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update sponsors badge, course bundle. PR [#3340](https://github.com/tiangolo/fastapi/pull/3340) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new gold sponsor Jina 🎉. PR [#3291](https://github.com/tiangolo/fastapi/pull/3291) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new banner sponsor badge for FastAPI courses bundle. PR [#3288](https://github.com/tiangolo/fastapi/pull/3288) by [@tiangolo](https://github.com/tiangolo). * 👷 Upgrade Issue Manager GitHub Action. PR [#3236](https://github.com/tiangolo/fastapi/pull/3236) by [@tiangolo](https://github.com/tiangolo). From fa7e3c996edf2d5482fff8f9d890ac2390dede4d Mon Sep 17 00:00:00 2001 From: Patrick Wang <1263870+patrickkwang@users.noreply.github.com> Date: Mon, 7 Jun 2021 06:46:18 -0400 Subject: [PATCH 010/814] =?UTF-8?q?=F0=9F=90=9B=20Check=20Content-Type=20r?= =?UTF-8?q?equest=20header=20before=20assuming=20JSON=20(#2118)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrick Wang Co-authored-by: Sebastián Ramírez --- fastapi/routing.py | 19 +++- .../test_body/test_tutorial001.py | 88 ++++++++++++++++--- .../test_tutorial001.py | 1 + 3 files changed, 94 insertions(+), 14 deletions(-) diff --git a/fastapi/routing.py b/fastapi/routing.py index ac5e19d99..9b51f03ca 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -1,4 +1,5 @@ import asyncio +import email.message import enum import inspect import json @@ -36,7 +37,7 @@ from fastapi.utils import ( ) from pydantic import BaseModel from pydantic.error_wrappers import ErrorWrapper, ValidationError -from pydantic.fields import ModelField +from pydantic.fields import ModelField, Undefined from starlette import routing from starlette.concurrency import run_in_threadpool from starlette.exceptions import HTTPException @@ -174,14 +175,26 @@ def get_request_handler( async def app(request: Request) -> Response: try: - body = None + body: Any = None if body_field: if is_body_form: body = await request.form() else: body_bytes = await request.body() if body_bytes: - body = await request.json() + json_body: Any = Undefined + content_type_value = request.headers.get("content-type") + if content_type_value: + message = email.message.Message() + message["content-type"] = content_type_value + if message.get_content_maintype() == "application": + subtype = message.get_content_subtype() + if subtype == "json" or subtype.endswith("+json"): + json_body = await request.json() + if json_body != Undefined: + body = json_body + else: + body = body_bytes except json.JSONDecodeError as e: raise RequestValidationError([ErrorWrapper(e, ("body", e.pos))], body=e.doc) except Exception as e: diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py index 38c6dbe87..c90240ae4 100644 --- a/tests/test_tutorial/test_body/test_tutorial001.py +++ b/tests/test_tutorial/test_body/test_tutorial001.py @@ -173,25 +173,91 @@ def test_post_body(path, body, expected_status, expected_response): def test_post_broken_body(): + response = client.post( + "/items/", + headers={"content-type": "application/json"}, + data="{some broken json}", + ) + assert response.status_code == 422, response.text + assert response.json() == { + "detail": [ + { + "loc": ["body", 1], + "msg": "Expecting property name enclosed in double quotes: line 1 column 2 (char 1)", + "type": "value_error.jsondecode", + "ctx": { + "msg": "Expecting property name enclosed in double quotes", + "doc": "{some broken json}", + "pos": 1, + "lineno": 1, + "colno": 2, + }, + } + ] + } + + +def test_post_form_for_json(): response = client.post("/items/", data={"name": "Foo", "price": 50.5}) assert response.status_code == 422, response.text assert response.json() == { "detail": [ { - "ctx": { - "colno": 1, - "doc": "name=Foo&price=50.5", - "lineno": 1, - "msg": "Expecting value", - "pos": 0, - }, - "loc": ["body", 0], - "msg": "Expecting value: line 1 column 1 (char 0)", - "type": "value_error.jsondecode", + "loc": ["body"], + "msg": "value is not a valid dict", + "type": "type_error.dict", } ] } + + +def test_explicit_content_type(): + response = client.post( + "/items/", + data='{"name": "Foo", "price": 50.5}', + headers={"Content-Type": "application/json"}, + ) + assert response.status_code == 200, response.text + + +def test_geo_json(): + response = client.post( + "/items/", + data='{"name": "Foo", "price": 50.5}', + headers={"Content-Type": "application/geo+json"}, + ) + assert response.status_code == 200, response.text + + +def test_wrong_headers(): + data = '{"name": "Foo", "price": 50.5}' + invalid_dict = { + "detail": [ + { + "loc": ["body"], + "msg": "value is not a valid dict", + "type": "type_error.dict", + } + ] + } + + response = client.post("/items/", data=data, headers={"Content-Type": "text/plain"}) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + + response = client.post( + "/items/", data=data, headers={"Content-Type": "application/geo+json-seq"} + ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + response = client.post( + "/items/", data=data, headers={"Content-Type": "application/not-really-json"} + ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + + +def test_other_exceptions(): with patch("json.loads", side_effect=Exception): response = client.post("/items/", json={"test": "test2"}) assert response.status_code == 400, response.text - assert response.json() == {"detail": "There was an error parsing the body"} diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py index cc85a8a82..3eb5822e2 100644 --- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py +++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py @@ -25,6 +25,7 @@ def test_gzip_request(compress): if compress: data = gzip.compress(data) headers["Content-Encoding"] = "gzip" + headers["Content-Type"] = "application/json" response = client.post("/sum", data=data, headers=headers) assert response.json() == {"sum": n} From 38b785813f175bef80e3e2f5274077f46d898186 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 7 Jun 2021 10:46:59 +0000 Subject: [PATCH 011/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 588ca1661..235cfdb9a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Check Content-Type request header before assuming JSON. PR [#2118](https://github.com/tiangolo/fastapi/pull/2118) by [@patrickkwang](https://github.com/patrickkwang). * 🔧 Update sponsors badge, course bundle. PR [#3340](https://github.com/tiangolo/fastapi/pull/3340) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new gold sponsor Jina 🎉. PR [#3291](https://github.com/tiangolo/fastapi/pull/3291) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new banner sponsor badge for FastAPI courses bundle. PR [#3288](https://github.com/tiangolo/fastapi/pull/3288) by [@tiangolo](https://github.com/tiangolo). From 377234ad8ed7b15667662250166c1bac6327c879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 7 Jun 2021 14:55:40 +0200 Subject: [PATCH 012/814] =?UTF-8?q?=F0=9F=94=92=20Create=20Security=20Poli?= =?UTF-8?q?cy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SECURITY.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..322f95f62 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,31 @@ +# Security Policy + +Security is very important for FastAPI and its community. 🔒 + +Learn more about it below. 👇 + +## Versions + +The latest versions of FastAPI are supported. + +You are encouraged to [write tests](https://fastapi.tiangolo.com/tutorial/testing/) for your application and update your FastAPI version frequently after ensuring that your tests are passing. This way you will benefit from the latest features, bug fixes, and **security fixes**. + +You can learn more about [FastAPI versions and how to pin and upgrade them](https://fastapi.tiangolo.com/deployment/versions/) for your project in the docs. + +## Reporting a Vulnerability + +If you think you found a vulnerability, and even if you are not sure about it, please report it right away by sending an email to: security@tiangolo.com. Please try to be as explicit as possible, describing all the steps and example code to reproduce the security issue. + +I (the author, [@tiangolo](https://twitter.com/tiangolo)) will review it thoroughly and get back to you. + +## Public Discussions + +Please restrain from publicly discussing a potential security vulnerability. 🙊 + +It's better to discuss privately and try to find a solution first, to limit the potential impact as much as possible. + +--- + +Thanks for your help! + +The FastAPI community and I thank you for that. 🙇 From aabe2c7d66ef4add9d4f89c13483260e40e95b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 9 Jun 2021 10:16:25 +0200 Subject: [PATCH 013/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 235cfdb9a..5e77d87db 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,25 @@ ## Latest Changes -* 🐛 Check Content-Type request header before assuming JSON. PR [#2118](https://github.com/tiangolo/fastapi/pull/2118) by [@patrickkwang](https://github.com/patrickkwang). + +### Security fixes + +* 🔒 Check Content-Type request header before assuming JSON. Initial PR [#2118](https://github.com/tiangolo/fastapi/pull/2118) by [@patrickkwang](https://github.com/patrickkwang). + +This change fixes a [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) security vulnerability when using cookies for authentication in path operations with JSON payloads sent by browsers. + +In versions lower than `0.65.2`, FastAPI would try to read the request payload as JSON even if the `content-type` header sent was not set to `application/json` or a compatible JSON media type (e.g. `application/geo+json`). + +So, a request with a content type of `text/plain` containing JSON data would be accepted and the JSON data would be extracted. + +But requests with content type `text/plain` are exempt from [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) preflights, for being considered [Simple requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests). So, the browser would execute them right away including cookies, and the text content could be a JSON string that would be parsed and accepted by the FastAPI application. + +See [CVE-2021-32677](https://github.com/tiangolo/fastapi/security/advisories/GHSA-8h2j-cgx8-6xv7) for more details. + +Thanks to [Dima Boger](https://twitter.com/b0g3r) for the security report! 🙇🔒 + +### Internal + * 🔧 Update sponsors badge, course bundle. PR [#3340](https://github.com/tiangolo/fastapi/pull/3340) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new gold sponsor Jina 🎉. PR [#3291](https://github.com/tiangolo/fastapi/pull/3291) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new banner sponsor badge for FastAPI courses bundle. PR [#3288](https://github.com/tiangolo/fastapi/pull/3288) by [@tiangolo](https://github.com/tiangolo). From 4d91f978d265a5050baeb3d4b3618c2f5cb7995a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 9 Jun 2021 10:17:27 +0200 Subject: [PATCH 014/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.65?= =?UTF-8?q?.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 ++ fastapi/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5e77d87db..bd7e2b270 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -3,6 +3,8 @@ ## Latest Changes +## 0.65.2 + ### Security fixes * 🔒 Check Content-Type request header before assuming JSON. Initial PR [#2118](https://github.com/tiangolo/fastapi/pull/2118) by [@patrickkwang](https://github.com/patrickkwang). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 80f61d9f4..d04f2ea96 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.65.1" +__version__ = "0.65.2" from starlette import status as status From fc6827d68af53c1c58fc2183ffd1d9dc93b8fef1 Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Tue, 29 Jun 2021 20:24:19 +0800 Subject: [PATCH 015/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20Tutorial=20-=20Request=20-=20Files=20(#3244)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Xie Wei --- docs/zh/docs/tutorial/request-files.md | 153 +++++++++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 154 insertions(+) create mode 100644 docs/zh/docs/tutorial/request-files.md diff --git a/docs/zh/docs/tutorial/request-files.md b/docs/zh/docs/tutorial/request-files.md new file mode 100644 index 000000000..26ece0d90 --- /dev/null +++ b/docs/zh/docs/tutorial/request-files.md @@ -0,0 +1,153 @@ +# 请求文件 + +`File` 用于定义客户端的上传文件。 + +!!! info "说明" + + 因为上传文件以「表单数据」形式发送。 + + 所以接收上传文件,要预先安装 `python-multipart`。 + + 例如: `pip install python-multipart`。 + +## 导入 `File` + +从 `fastapi` 导入 `File` 和 `UploadFile`: + +```Python hl_lines="1" +{!../../../docs_src/request_files/tutorial001.py!} +``` + +## 定义 `File` 参数 + +创建文件(`File`)参数的方式与 `Body` 和 `Form` 一样: + +```Python hl_lines="7" +{!../../../docs_src/request_files/tutorial001.py!} +``` + +!!! info "说明" + + `File` 是直接继承自 `Form` 的类。 + + 注意,从 `fastapi` 导入的 `Query`、`Path`、`File` 等项,实际上是返回特定类的函数。 + +!!! tip "提示" + + 声明文件体必须使用 `File`,否则,FastAPI 会把该参数当作查询参数或请求体(JSON)参数。 + +文件作为「表单数据」上传。 + +如果把*路径操作函数*参数的类型声明为 `bytes`,**FastAPI** 将以 `bytes` 形式读取和接收文件内容。 + +这种方式把文件的所有内容都存储在内存里,适用于小型文件。 + +不过,很多情况下,`UploadFile` 更好用。 + +## 含 `UploadFile` 的 `File` 参数 + +定义 `File` 参数时使用 `UploadFile`: + +```Python hl_lines="12" +{!../../../docs_src/request_files/tutorial001.py!} +``` + +`UploadFile` 与 `bytes` 相比有更多优势: + +* 使用 `spooled` 文件: + * 存储在内存的文件超出最大上限时,FastAPI 会把文件存入磁盘; +* 这种方式更适于处理图像、视频、二进制文件等大型文件,好处是不会占用所有内存; +* 可获取上传文件的元数据; +* 自带 file-like `async` 接口; +* 暴露的 Python `SpooledTemporaryFile` 对象,可直接传递给其他预期「file-like」对象的库。 + +### `UploadFile` + +`UploadFile` 的属性如下: + +* `filename`:上传文件名字符串(`str`),例如, `myimage.jpg`; +* `content_type`:内容类型(MIME 类型 / 媒体类型)字符串(`str`),例如,`image/jpeg`; +* `file`: `SpooledTemporaryFile`file-like 对象)。其实就是 Python文件,可直接传递给其他预期 `file-like` 对象的函数或支持库。 + +`UploadFile` 支持以下 `async` 方法,(使用内部 `SpooledTemporaryFile`)可调用相应的文件方法。 + +* `write(data)`:把 `data` (`str` 或 `bytes`)写入文件; +* `read(size)`:按指定数量的字节或字符(`size` (`int`))读取文件内容; +* `seek(offset)`:移动至文件 `offset` (`int`)字节处的位置; + * 例如,`await myfile.seek(0) ` 移动到文件开头; + * 执行 `await myfile.read()` 后,需再次读取已读取内容时,这种方法特别好用; +* `close()`:关闭文件。 + +因为上述方法都是 `async` 方法,要搭配「await」使用。 + +例如,在 `async` *路径操作函数* 内,要用以下方式读取文件内容: + +```Python +contents = await myfile.read() +``` + +在普通 `def` *路径操作函数* 内,则可以直接访问 `UploadFile.file`,例如: + +```Python +contents = myfile.file.read() +``` + +!!! note "`async` 技术细节" + + 使用 `async` 方法时,**FastAPI** 在线程池中执行文件方法,并 `awiat` 操作完成。 + +!!! note "Starlette 技术细节" + + **FastAPI** 的 `UploadFile` 直接继承自 **Starlette** 的 `UploadFile`,但添加了一些必要功能,使之与 **Pydantic** 及 FastAPI 的其它部件兼容。 + +## 什么是 「表单数据」 + +与 JSON 不同,HTML 表单(`
`)向服务器发送数据通常使用「特殊」的编码。 + +**FastAPI** 要确保从正确的位置读取数据,而不是读取 JSON。 + +!!! note "技术细节" + + 不包含文件时,表单数据一般用 `application/x-www-form-urlencoded`「媒体类型」编码。 + + 但表单包含文件时,编码为 `multipart/form-data`。使用了 `File`,**FastAPI** 就知道要从请求体的正确位置获取文件。 + + 编码和表单字段详见 MDN Web 文档的 POST 小节。 + +!!! warning "警告" + + 可在一个*路径操作*中声明多个 `File` 和 `Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。因为此时请求体的编码是 `multipart/form-data`,不是 `application/json`。 + + 这不是 **FastAPI** 的问题,而是 HTTP 协议的规定。 + +## 多文件上传 + +FastAPI 支持同时上传多个文件。 + +可用同一个「表单字段」发送含多个文件的「表单数据」。 + +上传多个文件时,要声明含 `bytes` 或 `UploadFile` 的列表(`List`): + +```Python hl_lines="10 15" +{!../../../docs_src/request_files/tutorial002.py!} +``` + +接收的也是含 `bytes` 或 `UploadFile` 的列表(`list`)。 + +!!! note "笔记" + + 注意,截至 2019 年 4 月 14 日,Swagger UI 不支持在同一个表单字段中上传多个文件。详见 #4276#3641. + + 不过,**FastAPI** 已通过 OpenAPI 标准与之兼容。 + + 因此,只要 Swagger UI 或任何其他支持 OpenAPI 的工具支持多文件上传,都将与 **FastAPI** 兼容。 + +!!! note "技术细节" + + 也可以使用 `from starlette.responses import HTMLResponse`。 + + `fastapi.responses` 其实与 `starlette.responses` 相同,只是为了方便开发者调用。实际上,大多数 **FastAPI** 的响应都直接从 Starlette 调用。 + +## 小结 + +本节介绍了如何用 `File` 把上传文件声明为(表单数据的)输入参数。 \ No newline at end of file diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index b88f04382..8551e6443 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -72,6 +72,7 @@ nav: - tutorial/schema-extra-example.md - tutorial/extra-data-types.md - tutorial/cookie-params.md + - tutorial/request-files.md - 安全性: - tutorial/security/index.md - tutorial/security/get-current-user.md From 246e80512d565a82f259d00e596d558ea385df12 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Jun 2021 12:24:59 +0000 Subject: [PATCH 016/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bd7e2b270..27f32a09f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for Tutorial - Request - Files. PR [#3244](https://github.com/tiangolo/fastapi/pull/3244) by [@jaystone776](https://github.com/jaystone776). ## 0.65.2 From 97d8d4016b91abf404a2f0b338896ce57bcda5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 29 Jun 2021 23:22:23 +0200 Subject: [PATCH 017/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20docs=20developmen?= =?UTF-8?q?t=20dependency=20on=20`typer-cli`=20to=20>=3D0.0.12=20to=20fix?= =?UTF-8?q?=20conflicts=20(#3429)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-docs.yml | 2 +- pyproject.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index ad20f45b4..e62264458 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -26,7 +26,7 @@ jobs: run: python3.7 -m pip install flit - name: Install docs extras if: steps.cache.outputs.cache-hit != 'true' - run: python3.7 -m flit install --extras doc + run: python3.7 -m flit install --deps production --extras doc - name: Install Material for MkDocs Insiders if: github.event.pull_request.head.repo.fork == false && steps.cache.outputs.cache-hit != 'true' run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git diff --git a/pyproject.toml b/pyproject.toml index f376dcdff..25440bde4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,10 +66,10 @@ test = [ ] doc = [ "mkdocs >=1.1.2,<2.0.0", - "mkdocs-material >=6.1.4,<7.0.0", - "markdown-include >=0.5.1,<0.6.0", + "mkdocs-material >=7.1.9,<8.0.0", + "markdown-include >=0.6.0,<0.7.0", "mkdocs-markdownextradata-plugin >=0.1.7,<0.2.0", - "typer-cli >=0.0.9,<0.0.10", + "typer-cli >=0.0.12,<0.0.13", "pyyaml >=5.3.1,<6.0.0" ] dev = [ From 26a36f79fa3e1a4534e29066fa4fa20fe762206c Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Jun 2021 21:23:00 +0000 Subject: [PATCH 018/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 27f32a09f..ae7a8ea45 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade docs development dependency on `typer-cli` to >=0.0.12 to fix conflicts. PR [#3429](https://github.com/tiangolo/fastapi/pull/3429) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Chinese translation for Tutorial - Request - Files. PR [#3244](https://github.com/tiangolo/fastapi/pull/3244) by [@jaystone776](https://github.com/jaystone776). ## 0.65.2 From 77c1988a8b826aeb02be362a7a88391315bbf606 Mon Sep 17 00:00:00 2001 From: Fabio Serrao Date: Fri, 2 Jul 2021 10:42:29 -0300 Subject: [PATCH 019/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20Development=20Contributing=20(#1364)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/pt/docs/contributing.md | 511 +++++++++++++++++++++++++++++++++++ 1 file changed, 511 insertions(+) create mode 100644 docs/pt/docs/contributing.md diff --git a/docs/pt/docs/contributing.md b/docs/pt/docs/contributing.md new file mode 100644 index 000000000..327b8b607 --- /dev/null +++ b/docs/pt/docs/contributing.md @@ -0,0 +1,511 @@ +# Desenvolvimento - Contribuindo + +Primeiramente, você deveria ver os meios básicos para [ajudar FastAPI e pedir ajuda](help-fastapi.md){.internal-link target=_blank}. + +## Desenvolvendo + +Se você já clonou o repositório e precisa mergulhar no código, aqui estão algumas orientações para configurar seu ambiente. + +### Ambiente virtual com `venv` + +Você pode criar um ambiente virtual em um diretório utilizando o módulo `venv` do Python: + +
+ +```console +$ python -m venv env +``` + +
+ +Isso criará o diretório `./env/` com os binários Python e então você será capaz de instalar pacotes nesse ambiente isolado. + +### Ativar o ambiente + +Ative o novo ambiente com: + +=== "Linux, macOS" + +
+ + ```console + $ source ./env/bin/activate + ``` + +
+ +=== "Windows PowerShell" + +
+ + ```console + $ .\env\Scripts\Activate.ps1 + ``` + +
+ +=== "Windows Bash" + + Ou se você usa Bash para Windows (por exemplo Git Bash): + +
+ + ```console + $ source ./env/Scripts/activate + ``` + +
+ +Para verificar se funcionou, use: + +=== "Linux, macOS, Windows Bash" + +
+ + ```console + $ which pip + + some/directory/fastapi/env/bin/pip + ``` + +
+ +=== "Windows PowerShell" + +
+ + ```console + $ Get-Command pip + + some/directory/fastapi/env/bin/pip + ``` + +
+ +Se ele exibir o binário `pip` em `env/bin/pip` então funcionou. 🎉 + + + +!!! tip + Toda vez que você instalar um novo pacote com `pip` nesse ambiente, ative o ambiente novamente. + + Isso garante que se você usar um programa instalado por aquele pacote (como `flit`), você utilizará aquele de seu ambiente local e não outro que possa estar instalado globalmente. + +### Flit + +**FastAPI** utiliza Flit para construir, empacotar e publicar o projeto. + +Após ativar o ambiente como descrito acima, instale o `flit`: + +
+ +```console +$ pip install flit + +---> 100% +``` + +
+ +Ative novamente o ambiente para ter certeza que você esteja utilizando o `flit` que você acabou de instalar (e não um global). + +E agora use `flit` para instalar as dependências de desenvolvimento: + +=== "Linux, macOS" + +
+ + ```console + $ flit install --deps develop --symlink + + ---> 100% + ``` + +
+ +=== "Windows" + + Se você está no Windows, use `--pth-file` ao invés de `--symlink`: + +
+ + ```console + $ flit install --deps develop --pth-file + + ---> 100% + ``` + +
+ +Isso irá instalar todas as dependências e seu FastAPI local em seu ambiente local. + +#### Usando seu FastAPI local + +Se você cria um arquivo Python que importa e usa FastAPI, e roda com Python de seu ambiente local, ele irá utilizar o código fonte de seu FastAPI local. + +E se você atualizar o código fonte do FastAPI local, como ele é instalado com `--symlink` (ou `--pth-file` no Windows), quando você rodar aquele arquivo Python novamente, ele irá utilizar a nova versão do FastAPI que você acabou de editar. + +Desse modo, você não tem que "instalar" sua versão local para ser capaz de testar cada mudança. + +### Formato + +Tem um arquivo que você pode rodar que irá formatar e limpar todo o seu código: + +
+ +```console +$ bash scripts/format.sh +``` + +
+ +Ele irá organizar também todos os seus imports. + +Para que ele organize os imports corretamente, você precisa ter o FastAPI instalado localmente em seu ambiente, com o comando na seção acima usando `--symlink` (ou `--pth-file` no Windows). + +### Formato dos imports + +Tem outro _script_ que formata todos os imports e garante que você não tenha imports não utilizados: + +
+ +```console +$ bash scripts/format-imports.sh +``` + +
+ +Como ele roda um comando após o outro, modificando e revertendo muitos arquivos, ele demora um pouco para concluir, então pode ser um pouco mais fácil utilizar `scripts/format.sh` frequentemente e `scripts/format-imports.sh` somente após "commitar uma branch". + +## Documentação + +Primeiro, tenha certeza de configurar seu ambiente como descrito acima, isso irá instalar todas as requisições. + +A documentação usa MkDocs. + +E existem ferramentas/_scripts_ extras para controlar as traduções em `./scripts/docs.py`. + +!!! tip + Você não precisa ver o código em `./scripts/docs.py`, você apenas o utiliza na linha de comando. + +Toda a documentação está no formato Markdown no diretório `./docs/pt/`. + +Muitos dos tutoriais tem blocos de código. + +Na maioria dos casos, esse blocos de código são aplicações completas que podem ser rodadas do jeito que estão apresentados. + +De fato, esses blocos de código não estão escritos dentro do Markdown, eles são arquivos Python dentro do diretório `./docs_src/`. + +E esses arquivos Python são incluídos/injetados na documentação quando se gera o site. + +### Testes para Documentação + +A maioria dos testes na verdade rodam encima dos arquivos fonte na documentação. + +Isso ajuda a garantir: + +* Que a documentação esteja atualizada. +* Que os exemplos da documentação possam ser rodadas do jeito que estão apresentadas. +* A maior parte dos recursos é coberta pela documentação, garantida por cobertura de testes. + +Durante o desenvolvimento local, existe um _script_ que constrói o site e procura por quaisquer mudanças, carregando na hora: + +
+ +```console +$ python ./scripts/docs.py live + +[INFO] Serving on http://127.0.0.1:8008 +[INFO] Start watching changes +[INFO] Start detecting changes +``` + +
+ +Isso irá servir a documentação em `http://127.0.0.1:8008`. + +Desse jeito, você poderá editar a documentação/arquivos fonte e ver as mudanças na hora. + +#### Typer CLI (opcional) + +As instruções aqui mostram como utilizar _scripts_ em `./scripts/docs.py` com o programa `python` diretamente. + +Mas você pode usar também Typer CLI, e você terá auto-completação para comandos no seu terminal após instalar o _completion_. + +Se você instalou Typer CLI, você pode instalar _completion_ com: + +
+ +```console +$ typer --install-completion + +zsh completion installed in /home/user/.bashrc. +Completion will take effect once you restart the terminal. +``` + +
+ +### Aplicações e documentação ao mesmo tempo + +Se você rodar os exemplos com, por exemplo: + +
+ +```console +$ uvicorn tutorial001:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +como Uvicorn utiliza por padrão a porta `8000`, a documentação na porta `8008` não dará conflito. + +### Traduções + +Ajuda com traduções É MUITO apreciada! E essa tarefa não pode ser concluída sem a ajuda da comunidade. 🌎 🚀 + +Aqui estão os passos para ajudar com as traduções. + +#### Dicas e orientações + +* Verifique sempre os _pull requests_ existentes para a sua linguagem e faça revisões das alterações e aprove elas. + +!!! tip + Você pode adicionar comentários com sugestões de alterações para _pull requests_ existentes. + + Verifique as documentações sobre adicionar revisão ao _pull request_ para aprovação ou solicitação de alterações. + +* Verifique em _issues_ para ver se existe alguém coordenando traduções para a sua linguagem. + +* Adicione um único _pull request_ por página traduzida. Isso tornará muito mais fácil a revisão para as outras pessoas. + +Para as linguagens que eu não falo, vou esperar por várias pessoas revisarem a tradução antes de _mergear_. + +* Você pode verificar também se há traduções para sua linguagem e adicionar revisão para elas, isso irá me ajudar a saber que a tradução está correta e eu possa _mergear_. + +* Utilize os mesmos exemplos Python e somente traduza o texto na documentação. Você não tem que alterar nada no código para que funcione. + +* Utilize as mesmas imagens, nomes de arquivo e links. Você não tem que alterar nada disso para que funcione. + +* Para verificar o código de duas letras para a linguagem que você quer traduzir, você pode usar a Lista de códigos ISO 639-1. + +#### Linguagem existente + +Vamos dizer que você queira traduzir uma página para uma linguagem que já tenha traduções para algumas páginas, como o Espanhol. + +No caso do Espanhol, o código de duas letras é `es`. Então, o diretório para traduções em Espanhol está localizada em `docs/es/`. + +!!! tip + A principal ("oficial") linguagem é o Inglês, localizado em `docs/en/`. + +Agora rode o _servidor ao vivo_ para as documentações em Espanhol: + +
+ +```console +// Use o comando "live" e passe o código da linguagem como um argumento de linha de comando +$ python ./scripts/docs.py live es + +[INFO] Serving on http://127.0.0.1:8008 +[INFO] Start watching changes +[INFO] Start detecting changes +``` + +
+ +Agora você pode ir em http://127.0.0.1:8008 e ver suas mudanças ao vivo. + +Se você procurar no site da documentação do FastAPI, você verá que toda linguagem tem todas as páginas. Mas algumas páginas não estão traduzidas e tem notificação sobre a falta da tradução. + +Mas quando você rodar localmente como descrito acima, você somente verá as páginas que já estão traduzidas. + +Agora vamos dizer que você queira adicionar uma tradução para a seção [Recursos](features.md){.internal-link target=_blank}. + +* Copie o arquivo em: + +``` +docs/en/docs/features.md +``` + +* Cole ele exatamente no mesmo local mas para a linguagem que você quer traduzir, por exemplo: + +``` +docs/es/docs/features.md +``` + +!!! tip + Observe que a única mudança na rota é o código da linguagem, de `en` para `es`. + +* Agora abra o arquivo de configuração MkDocs para Inglês em: + +``` +docs/en/docs/mkdocs.yml +``` + +* Procure o lugar onde `docs/features.md` está localizado no arquivo de configuração. Algum lugar como: + +```YAML hl_lines="8" +site_name: FastAPI +# Mais coisas +nav: +- FastAPI: index.md +- Languages: + - en: / + - es: /es/ +- features.md +``` + +* Abra o arquivo de configuração MkDocs para a linguagem que você está editando, por exemplo: + +``` +docs/es/docs/mkdocs.yml +``` + +* Adicione no mesmo local que está no arquivo em Inglês, por exemplo: + +```YAML hl_lines="8" +site_name: FastAPI +# Mais coisas +nav: +- FastAPI: index.md +- Languages: + - en: / + - es: /es/ +- features.md +``` + +Tenha certeza que se existem outras entradas, a nova entrada com sua tradução esteja exatamente na mesma ordem como na versão em Inglês. + +Se você for no seu navegador verá que agora a documentação mostra sua nova seção. 🎉 + +Agora você poderá traduzir tudo e ver como está toda vez que salva o arquivo. + +#### Nova linguagem + +Vamos dizer que você queira adicionar traduções para uma linguagem que ainda não foi traduzida, nem sequer uma página. + +Vamos dizer que você queira adicionar tradução para Haitiano, e ainda não tenha na documentação. + +Verificando o link acima, o código para "Haitiano" é `ht`. + +O próximo passo é rodar o _script_ para gerar um novo diretório de tradução: + +
+ +```console +// Use o comando new-lang, passe o código da linguagem como um argumento de linha de comando +$ python ./scripts/docs.py new-lang ht + +Successfully initialized: docs/ht +Updating ht +Updating en +``` + +
+ +Agora você pode verificar em seu editor de código o mais novo diretório criado `docs/ht/`. + +!!! tip + Crie um primeiro _pull request_ com apenas isso, para iniciar a configuração da nova linguagem, antes de adicionar traduções. + + Desse modo outros poderão ajudar com outras páginas enquanto você trabalha na primeira. 🚀 + +Inicie traduzindo a página principal, `docs/ht/index.md`. + +Então você pode continuar com as instruções anteriores, para uma "Linguagem Existente". + +##### Nova linguagem não suportada + +Se quando rodar o _script_ do _servidor ao vivo_ você pega um erro sobre linguagem não suportada, alguma coisa como: + +``` + raise TemplateNotFound(template) +jinja2.exceptions.TemplateNotFound: partials/language/xx.html +``` + +Isso significa que o tema não suporta essa linguagem (nesse caso, com um código falso de duas letras `xx`). + +Mas não se preocupe, você pode configurar o tema de linguagem para Inglês e então traduzir o conteúdo da documentação. + +Se você precisar fazer isso, edite o `mkdocs.yml` para sua nova linguagem, teremos algo como: + +```YAML hl_lines="5" +site_name: FastAPI +# Mais coisas +theme: + # Mais coisas + language: xx +``` + +Altere essa linguagem de `xx` (do seu código de linguagem) para `en`. + +Então você poderá iniciar novamente o _servidor ao vivo_. + +#### Pré-visualize o resultado + +Quando você usa o _script_ em `./scripts/docs.py` com o comando `live` ele somente exibe os arquivos e traduções disponíveis para a linguagem atual. + +Mas uma vez que você tenha concluído, você poderá testar tudo como se parecesse _online_. + +Para fazer isso, primeiro construa toda a documentação: + +
+ +```console +// Use o comando "build-all", isso leverá um tempinho +$ python ./scripts/docs.py build-all + +Updating es +Updating en +Building docs for: en +Building docs for: es +Successfully built docs for: es +Copying en index.md to README.md +``` + +
+ +Isso gera toda a documentação em `./docs_build/` para cada linguagem. Isso inclui a adição de quaisquer arquivos com tradução faltando, com uma nota dizendo que "esse arquivo ainda não tem tradução". Mas você não tem que fazer nada com esse diretório. + +Então ele constrói todos aqueles _sites_ independentes MkDocs para cada linguagem, combina eles, e gera a saída final em `./site/`. + +Então você poderá "servir" eles com o comando `serve`: + +
+ +```console +// Use o comando "serve" após rodar "build-all" +$ python ./scripts/docs.py serve + +Warning: this is a very simple server. For development, use mkdocs serve instead. +This is here only to preview a site with translations already built. +Make sure you run the build-all command first. +Serving at: http://127.0.0.1:8008 +``` + +
+ +## Testes + +Tem um _script_ que você pode rodar localmente para testar todo o código e gerar relatórios de cobertura em HTML: + +
+ +```console +$ bash scripts/test-cov-html.sh +``` + +
+ +Esse comando gera um diretório `./htmlcov/`, se você abrir o arquivo `./htmlcov/index.html` no seu navegador, poderá explorar interativamente as regiões de código que estão cobertas pelos testes, e observar se existe alguma região faltando. + +### Testes no seu editor + +Se você quer usar os testes integrados em seu editor adicione `./docs_src` na sua variável `PYTHONPATH`. + +Por exemplo, no VS Code você pode criar um arquivo `.env` com: + +```env +PYTHONPATH=./docs_src +``` From bd143ffa5aa281a47dc1843baf2762cf3d0302d4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 13:43:04 +0000 Subject: [PATCH 020/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ae7a8ea45..ec1f5ac58 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for Development Contributing. PR [#1364](https://github.com/tiangolo/fastapi/pull/1364) by [@Serrones](https://github.com/Serrones). * ⬆ Upgrade docs development dependency on `typer-cli` to >=0.0.12 to fix conflicts. PR [#3429](https://github.com/tiangolo/fastapi/pull/3429) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Chinese translation for Tutorial - Request - Files. PR [#3244](https://github.com/tiangolo/fastapi/pull/3244) by [@jaystone776](https://github.com/jaystone776). From a0b20062306f4e76bea520623782975b1bfba831 Mon Sep 17 00:00:00 2001 From: BoYanZh Date: Fri, 2 Jul 2021 22:02:45 +0800 Subject: [PATCH 021/814] =?UTF-8?q?=F0=9F=8C=90=20Fix=20Chinese=20translat?= =?UTF-8?q?ion=20code=20snippet=20mismatch=20in=20Tutorial=20-=20Python=20?= =?UTF-8?q?Types=20Intro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zh/docs/python-types.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/zh/docs/python-types.md b/docs/zh/docs/python-types.md index e8c07f4c3..67a1612f0 100644 --- a/docs/zh/docs/python-types.md +++ b/docs/zh/docs/python-types.md @@ -222,13 +222,13 @@ John Doe 假设你有一个名为 `Person` 的类,拥有 name 属性: ```Python hl_lines="1-3" -{!../../../docs_src/python_types/tutorial009.py!} +{!../../../docs_src/python_types/tutorial010.py!} ``` 接下来,你可以将一个变量声明为 `Person` 类型: ```Python hl_lines="6" -{!../../../docs_src/python_types/tutorial009.py!} +{!../../../docs_src/python_types/tutorial010.py!} ``` 然后,你将再次获得所有的编辑器支持: From b27758fe13190da83fbf7235e739e0aa58bc17f2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:03:22 +0000 Subject: [PATCH 022/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ec1f5ac58..6821f7c55 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix Chinese translation code snippet mismatch in Tutorial - Python Types Intro. PR [#2573](https://github.com/tiangolo/fastapi/pull/2573) by [@BoYanZh](https://github.com/BoYanZh). * 🌐 Add Portuguese translation for Development Contributing. PR [#1364](https://github.com/tiangolo/fastapi/pull/1364) by [@Serrones](https://github.com/Serrones). * ⬆ Upgrade docs development dependency on `typer-cli` to >=0.0.12 to fix conflicts. PR [#3429](https://github.com/tiangolo/fastapi/pull/3429) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Chinese translation for Tutorial - Request - Files. PR [#3244](https://github.com/tiangolo/fastapi/pull/3244) by [@jaystone776](https://github.com/jaystone776). From 18b24df9c820799adf5f3ab26c2253a073936718 Mon Sep 17 00:00:00 2001 From: Ruidy Date: Fri, 2 Jul 2021 16:06:10 +0200 Subject: [PATCH 023/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20Alternatives,=20Inspiration=20and=20Comparisons=20(#?= =?UTF-8?q?3020)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérôme Fink Co-authored-by: Sam Courtemanche --- docs/fr/docs/alternatives.md | 446 +++++++++++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 447 insertions(+) create mode 100644 docs/fr/docs/alternatives.md diff --git a/docs/fr/docs/alternatives.md b/docs/fr/docs/alternatives.md new file mode 100644 index 000000000..bf3e7bc3c --- /dev/null +++ b/docs/fr/docs/alternatives.md @@ -0,0 +1,446 @@ +# Alternatives, inspiration et comparaisons + +Ce qui a inspiré **FastAPI**, comment il se compare à d'autres solutions et ce qu'il en a appris. + +## Intro + +**FastAPI** n'existerait pas sans les précédentes contributions d'autres projets. + +De nombreux outils ont été créés auparavant et ont contribué à inspirer sa création. + +J'ai évité la création d'un nouveau framework pendant plusieurs années. J'ai d'abord essayé de combler toutes les +fonctionnalités couvertes par **FastAPI** en utilisant de nombreux frameworks, plug-ins et outils différents. + +Mais à un moment donné il n'y avait pas d'autre option que de créer quelque chose qui offrait toutes ces +fonctionnalités, en reprenant et en combinant de la meilleure façon possible les meilleures idées des outils +précédents, en utilisant des fonctionnalités du langage qui n'étaient même pas disponibles auparavant (type hints depuis Python 3.6+). + +## Outils précédents + +### Django + +C'est le framework Python le plus populaire et il bénéficie d'une grande confiance. Il est utilisé pour construire +des systèmes tel qu'Instagram. + +Il est relativement fortement couplé aux bases de données relationnelles (comme MySQL ou PostgreSQL), de sorte qu'il +n'est pas très facile d'utiliser une base de données NoSQL (comme Couchbase, MongoDB, Cassandra, etc.) comme principal moyen de +stockage. + +Il a été créé pour générer le HTML en backend, pas pour créer des API consommées par un frontend moderne (comme React, Vue.js et Angular) ou par d'autres systèmes (comme les appareils IoT) communiquant avec lui. + +### Django REST Framework + +Django REST framework a été conçu comme une boîte à outils flexible permettant de construire des API Web à partir de Django, afin d'améliorer ses capacités en matière d'API. + +Il est utilisé par de nombreuses entreprises, dont Mozilla, Red Hat et Eventbrite. + +Il s'agissait de l'un des premiers exemples de **documentation automatique pour API**, et c'est précisément l'une des +premières idées qui a inspiré "la recherche de" **FastAPI**. + +!!! note +Django REST framework a été créé par Tom Christie. Le créateur de Starlette et Uvicorn, sur lesquels **FastAPI** est basé. + +!!! check "A inspiré **FastAPI** à" +Avoir une interface de documentation automatique de l'API. + +### Flask + +Flask est un "micro-framework", il ne comprend pas d'intégrations de bases de données ni beaucoup de choses qui sont fournies par défaut dans Django. + +Cette simplicité et cette flexibilité permettent d'utiliser des bases de données NoSQL comme principal système de stockage de données. + +Comme il est très simple, son apprentissage est relativement intuitif, bien que la documentation soit quelque peu +technique par moments. + +Il est aussi couramment utilisé pour d'autres applications qui n'ont pas nécessairement besoin d'une base de données, de gestion des utilisateurs ou de l'une des nombreuses fonctionnalités préinstallées dans Django. Bien que beaucoup de ces fonctionnalités puissent être ajoutées avec des plug-ins. + +Ce découplage des parties, et le fait d'être un "micro-framework" qui puisse être étendu pour couvrir exactement ce +qui est nécessaire, était une caractéristique clé que je voulais conserver. + +Compte tenu de la simplicité de Flask, il semblait bien adapté à la création d'API. La prochaine chose à trouver était un "Django REST Framework" pour Flask. + +!!! check "A inspiré **FastAPI** à" +Être un micro-framework. Il est donc facile de combiner les outils et les pièces nécessaires. + +Proposer un système de routage simple et facile à utiliser. + +### Requests + +**FastAPI** n'est pas réellement une alternative à **Requests**. Leur cadre est très différent. + +Il serait en fait plus courant d'utiliser Requests _à l'intérieur_ d'une application FastAPI. + +Mais quand même, FastAPI s'est inspiré de Requests. + +**Requests** est une bibliothèque pour _interagir_ avec les API (en tant que client), tandis que **FastAPI** est une bibliothèque pour _créer_ des API (en tant que serveur). + +Ils sont, plus ou moins, aux extrémités opposées, se complétant l'un l'autre. + +Requests a un design très simple et intuitif, il est très facile à utiliser, avec des valeurs par défaut raisonnables, tout en étant très puissant et personnalisable. + +C'est pourquoi, comme le dit le site officiel : + +> Requests est l'un des packages Python les plus téléchargés de tous les temps + +La façon dont vous l'utilisez est très simple. Par exemple, pour faire une requête `GET`, vous devez écrire : + +```Python +response = requests.get("http://example.com/some/url") +``` + +En contrepartie l'API _des opérations de chemin_ de FastAPI pourrait ressembler à ceci : + +```Python hl_lines="1" +@app.get("/some/url") +def read_url(): + return {"message": "Hello World"} +``` + +Notez les similitudes entre `requests.get(...)` et `@app.get(...)`. + +!!! check "A inspiré **FastAPI** à" +_ Avoir une API simple et intuitive. +_ Utiliser les noms de méthodes HTTP (opérations) directement, de manière simple et intuitive. \* Avoir des valeurs par défaut raisonnables, mais des personnalisations puissantes. + +### Swagger / OpenAPI + +La principale fonctionnalité que j'ai emprunté à Django REST Framework était la documentation automatique des API. + +Puis j'ai découvert qu'il existait une norme pour documenter les API, en utilisant JSON (ou YAML, une extension de JSON) appelée Swagger. + +Il existait déjà une interface utilisateur Web pour les API Swagger. Donc, être capable de générer une documentation +Swagger pour une API permettrait d'utiliser cette interface utilisateur web automatiquement. + +À un moment donné, Swagger a été cédé à la Fondation Linux, puis a été rebaptisé OpenAPI. + +C'est pourquoi, lorsqu'on parle de la version 2.0, il est courant de dire "Swagger", et pour la version 3+ "OpenAPI". + +!!! check "A inspiré **FastAPI** à" +Adopter et utiliser une norme ouverte pour les spécifications des API, au lieu d'un schéma personnalisé. + + Intégrer des outils d'interface utilisateur basés sur des normes : + + * Swagger UI + * ReDoc + + Ces deux-là ont été choisis parce qu'ils sont populaires et stables, mais en faisant une recherche rapide, vous pourriez trouver des dizaines d'alternatives supplémentaires pour OpenAPI (que vous pouvez utiliser avec **FastAPI**). + +### Frameworks REST pour Flask + +Il y a plusieurs frameworks REST pour Flask, mais après avoir investi du temps et du travail pour les étudier, j'ai +découvert que le développement de beaucoup d'entre eux sont suspendus ou abandonnés, avec plusieurs problèmes +permanents qui les rendent inadaptés. + +### Marshmallow + +L'une des principales fonctionnalités nécessaires aux systèmes API est la "sérialisation" des données, qui consiste à prendre les données du code (Python) et à +les convertir en quelque chose qui peut être envoyé sur le réseau. Par exemple, convertir un objet contenant des +données provenant d'une base de données en un objet JSON. Convertir des objets `datetime` en strings, etc. + +La validation des données est une autre fonctionnalité importante dont ont besoin les API. Elle permet de s'assurer +que les données sont valides, compte tenu de certains paramètres. Par exemple, qu'un champ est un `int`, et non un +string. +Ceci est particulièrement utile pour les données entrantes. + +Sans un système de validation des données, vous devriez effectuer toutes les vérifications à la main, dans le code. + +Ces fonctionnalités sont ce pourquoi Marshmallow a été construit. C'est une excellente bibliothèque, et je l'ai déjà beaucoup utilisée. + +Mais elle a été créée avant que les type hints n'existent en Python. Ainsi, pour définir chaque schéma, vous devez utiliser des utilitaires et des classes spécifiques fournies par Marshmallow. + +!!! check "A inspiré **FastAPI** à" +Utilisez du code pour définir des "schémas" qui fournissent automatiquement les types de données et la validation. + +### Webargs + +Une autre grande fonctionnalité requise par les API est le parsing des données provenant des requêtes entrantes. + +Webargs est un outil qui a été créé pour fournir cela par-dessus plusieurs frameworks, dont Flask. + +Il utilise Marshmallow pour effectuer la validation des données. Et il a été créé par les mêmes développeurs. + +C'est un outil formidable et je l'ai beaucoup utilisé aussi, avant d'avoir **FastAPI**. + +!!! info +Webargs a été créé par les développeurs de Marshmallow. + +!!! check "A inspiré **FastAPI** à" +Disposer d'une validation automatique des données des requêtes entrantes. + +### APISpec + +Marshmallow et Webargs fournissent la validation, l'analyse et la sérialisation en tant que plug-ins. + +Mais la documentation fait toujours défaut. C'est alors qu'APISpec a été créé. + +Il s'agit d'un plug-in pour de nombreux frameworks (et il existe également un plug-in pour Starlette). + +Le principe est le suivant : vous écrivez la définition du schéma au format YAML dans la docstring de chaque fonction gérant une route. + +Et il génère des schémas OpenAPI. + +C'est ainsi que cela fonctionne dans Flask, Starlette, Responder, etc. + +Mais alors, nous avons à nouveau le problème d'avoir une micro-syntaxe, dans une docstring Python (un gros morceau de YAML). + +L'éditeur ne peut guère aider en la matière. Et si nous modifions les paramètres ou les schémas Marshmallow et que nous oublions de modifier également cette docstring YAML, le schéma généré deviendrait obsolète. + +!!! info +APISpec a été créé par les développeurs de Marshmallow. + +!!! check "A inspiré **FastAPI** à" +Supporter la norme ouverte pour les API, OpenAPI. + +### Flask-apispec + +C'est un plug-in pour Flask, qui relie Webargs, Marshmallow et APISpec. + +Il utilise les informations de Webargs et Marshmallow pour générer automatiquement des schémas OpenAPI, en utilisant APISpec. + +C'est un excellent outil, très sous-estimé. Il devrait être beaucoup plus populaire que de nombreux plug-ins Flask. C'est peut-être dû au fait que sa documentation est trop concise et abstraite. + +Cela a permis de ne pas avoir à écrire YAML (une autre syntaxe) à l'intérieur des docstrings Python. + +Cette combinaison de Flask, Flask-apispec avec Marshmallow et Webargs était ma stack backend préférée jusqu'à la création de **FastAPI**. + +Son utilisation a conduit à la création de plusieurs générateurs Flask full-stack. Ce sont les principales stacks que +j'ai (ainsi que plusieurs équipes externes) utilisées jusqu'à présent : + +- https://github.com/tiangolo/full-stack +- https://github.com/tiangolo/full-stack-flask-couchbase +- https://github.com/tiangolo/full-stack-flask-couchdb + +Ces mêmes générateurs full-stack ont servi de base aux [Générateurs de projets pour **FastAPI**](project-generation.md){.internal-link target=\_blank}. + +!!! info +Flask-apispec a été créé par les développeurs de Marshmallow. + +!!! check "A inspiré **FastAPI** à" +Générer le schéma OpenAPI automatiquement, à partir du même code qui définit la sérialisation et la validation. + +### NestJS (et Angular) + +Ce n'est même pas du Python, NestJS est un framework JavaScript (TypeScript) NodeJS inspiré d'Angular. + +Il réalise quelque chose de similaire à ce qui peut être fait avec Flask-apispec. + +Il possède un système d'injection de dépendances intégré, inspiré d'Angular 2. Il nécessite de pré-enregistrer les "injectables" (comme tous les autres systèmes d'injection de dépendances que je connais), donc, cela ajoute à la verbosité et à la répétition du code. + +Comme les paramètres sont décrits avec des types TypeScript (similaires aux type hints de Python), la prise en charge +par l'éditeur est assez bonne. + +Mais comme les données TypeScript ne sont pas préservées après la compilation en JavaScript, il ne peut pas compter sur les types pour définir la validation, la sérialisation et la documentation en même temps. En raison de cela et de certaines décisions de conception, pour obtenir la validation, la sérialisation et la génération automatique de schémas, il est nécessaire d'ajouter des décorateurs à de nombreux endroits. Cela devient donc assez verbeux. + +Il ne peut pas très bien gérer les modèles imbriqués. Ainsi, si le corps JSON de la requête est un objet JSON comportant des champs internes qui sont à leur tour des objets JSON imbriqués, il ne peut pas être correctement documenté et validé. + +!!! check "A inspiré **FastAPI** à" +Utiliser les types Python pour bénéficier d'un excellent support de l'éditeur. + + Disposer d'un puissant système d'injection de dépendances. Trouver un moyen de minimiser la répétition du code. + +### Sanic + +C'était l'un des premiers frameworks Python extrêmement rapides basés sur `asyncio`. Il a été conçu pour être très similaire à Flask. + +!!! note "Détails techniques" +Il utilisait `uvloop` au lieu du système par défaut de Python `asyncio`. C'est ce qui l'a rendu si rapide. + + Il a clairement inspiré Uvicorn et Starlette, qui sont actuellement plus rapides que Sanic dans les benchmarks. + +!!! check "A inspiré **FastAPI** à" +Trouvez un moyen d'avoir une performance folle. + + C'est pourquoi **FastAPI** est basé sur Starlette, car il s'agit du framework le plus rapide disponible (testé par des benchmarks tiers). + +### Falcon + +Falcon est un autre framework Python haute performance, il est conçu pour être minimal, et est utilisé comme fondation pour d'autres frameworks comme Hug. + +Il utilise le standard précédent pour les frameworks web Python (WSGI) qui est synchrone, donc il ne peut pas gérer les WebSockets et d'autres cas d'utilisation. Néanmoins, il offre de très bonnes performances. + +Il est conçu pour avoir des fonctions qui reçoivent deux paramètres, une "requête" et une "réponse". Ensuite, vous +"lisez" des parties de la requête et "écrivez" des parties dans la réponse. En raison de cette conception, il n'est +pas possible de déclarer des paramètres de requête et des corps avec des indications de type Python standard comme paramètres de fonction. + +Ainsi, la validation, la sérialisation et la documentation des données doivent être effectuées dans le code, et non pas automatiquement. Ou bien elles doivent être implémentées comme un framework au-dessus de Falcon, comme Hug. Cette même distinction se retrouve dans d'autres frameworks qui s'inspirent de la conception de Falcon, qui consiste à avoir un objet de requête et un objet de réponse comme paramètres. + +!!! check "A inspiré **FastAPI** à" +Trouver des moyens d'obtenir de bonnes performances. + + Avec Hug (puisque Hug est basé sur Falcon), **FastAPI** a inspiré la déclaration d'un paramètre `response` dans les fonctions. + + Bien que dans FastAPI, il est facultatif, et est utilisé principalement pour définir les en-têtes, les cookies, et les codes de statut alternatifs. + +### Molten + +J'ai découvert Molten lors des premières étapes de développement de **FastAPI**. Et il a des idées assez similaires : + +- Basé sur les type hints Python. +- Validation et documentation via ces types. +- Système d'injection de dépendances. + +Il n'utilise pas une librairie tiers de validation, sérialisation et de documentation tel que Pydantic, il utilise son propre système. Ainsi, ces définitions de types de données ne sont pas réutilisables aussi facilement. + +Il nécessite une configuration un peu plus verbeuse. Et comme il est basé sur WSGI (au lieu dASGI), il n'est pas +conçu pour profiter des hautes performances fournies par des outils comme Uvicorn, Starlette et Sanic. + +Le système d'injection de dépendances exige le pré-enregistrement des dépendances et les dépendances sont résolues sur la base des types déclarés. Ainsi, il n'est pas possible de déclarer plus d'un "composant" qui fournit un certain type. + +Les routes sont déclarées à un seul endroit, en utilisant des fonctions déclarées à d'autres endroits (au lieu +d'utiliser des décorateurs qui peuvent être placés juste au-dessus de la fonction qui gère l'endpoint). Cette +méthode est plus proche de celle de Django que de celle de Flask (et Starlette). Il sépare dans le code des choses +qui sont relativement fortement couplées. + +!!! check "A inspiré **FastAPI** à" +Définir des validations supplémentaires pour les types de données utilisant la valeur "par défaut" des attributs du modèle. Ceci améliore le support de l'éditeur, et n'était pas disponible dans Pydantic auparavant. + + Cela a en fait inspiré la mise à jour de certaines parties de Pydantic, afin de supporter le même style de déclaration de validation (toute cette fonctionnalité est maintenant déjà disponible dans Pydantic). + +### Hug + +Hug a été l'un des premiers frameworks à implémenter la déclaration des types de paramètres d'API en utilisant les type hints Python. C'était une excellente idée qui a inspiré d'autres outils à faire de même. + +Il utilisait des types personnalisés dans ses déclarations au lieu des types Python standard, mais c'était tout de même un énorme pas en avant. + +Il a également été l'un des premiers frameworks à générer un schéma personnalisé déclarant l'ensemble de l'API en JSON. + +Il n'était pas basé sur une norme comme OpenAPI et JSON Schema. Il ne serait donc pas simple de l'intégrer à d'autres outils, comme Swagger UI. Mais encore une fois, c'était une idée très innovante. + +Il présente une caractéristique intéressante et peu commune : à l'aide du même framework, il est possible de créer des +API et des CLI. + +Comme il est basé sur l'ancienne norme pour les frameworks web Python synchrones (WSGI), il ne peut pas gérer les Websockets et autres, bien qu'il soit également très performant. + +!!! info +Hug a été créé par Timothy Crosley, le créateur de `isort`, un excellent outil pour trier automatiquement les imports dans les fichiers Python. + +!!! check "A inspiré **FastAPI** à" +Hug a inspiré certaines parties d'APIStar, et était l'un des outils que je trouvais les plus prometteurs, à côté d'APIStar. + + Hug a contribué à inspirer **FastAPI** pour utiliser les type hints Python + pour déclarer les paramètres, et pour générer automatiquement un schéma définissant l'API. + + Hug a inspiré **FastAPI** pour déclarer un paramètre `response` dans les fonctions pour définir les en-têtes et les cookies. + +### APIStar (<= 0.5) + +Juste avant de décider de développer **FastAPI**, j'ai trouvé le serveur **APIStar**. Il contenait presque tout ce +que je recherchais et avait un beau design. + +C'était l'une des premières implémentations d'un framework utilisant les type hints Python pour déclarer les paramètres +et les requêtes que j'ai vues (avant NestJS et Molten). Je l'ai trouvé plus ou moins en même temps que Hug. Mais APIStar utilisait le standard OpenAPI. + +Il disposait de la validation automatique, sérialisation des données et d'une génération de schéma OpenAPI basée sur les mêmes type hints à plusieurs endroits. + +La définition du schéma de corps de requête n'utilisait pas les mêmes type hints Python que Pydantic, il était un peu plus proche de Marshmallow, donc le support de l'éditeur n'était pas aussi bon, mais APIStar était quand même la meilleure option disponible. + +Il avait les meilleures performances d'après les benchmarks de l'époque (seulement surpassé par Starlette). + +Au départ, il ne disposait pas d'une interface web de documentation automatique de l'API, mais je savais que je pouvais lui ajouter une interface Swagger. + +Il avait un système d'injection de dépendances. Il nécessitait un pré-enregistrement des composants, comme d'autres outils discutés ci-dessus. Mais c'était quand même une excellente fonctionnalité. + +Je n'ai jamais pu l'utiliser dans un projet complet, car il n'avait pas d'intégration de sécurité, et je ne pouvais donc pas remplacer toutes les fonctionnalités que j'avais avec les générateurs complets basés sur Flask-apispec. J'avais dans mon backlog de projets de créer une pull request pour ajouter cette fonctionnalité. + +Mais ensuite, le projet a changé d'orientation. + +Il ne s'agissait plus d'un framework web API, le créateur devant se concentrer sur Starlette. + +Maintenant, APIStar est un ensemble d'outils pour valider les spécifications OpenAPI, et non un framework web. + +!!! info +APIStar a été créé par Tom Christie. Le même gars qui a créé : + + * Django REST Framework + * Starlette (sur lequel **FastAPI** est basé) + * Uvicorn (utilisé par Starlette et **FastAPI**) + +!!! check "A inspiré **FastAPI** à" +Exister. + + L'idée de déclarer plusieurs choses (validation des données, sérialisation et documentation) avec les mêmes types Python, tout en offrant un excellent support pour les éditeurs, était pour moi une idée brillante. + + Et après avoir longtemps cherché un framework similaire et testé de nombreuses alternatives, APIStar était la meilleure option disponible. + + Puis APIStar a cessé d'exister en tant que serveur et Starlette a été créé, et a constitué une meilleure base pour un tel système. Ce fut l'inspiration finale pour construire **FastAPI**. + + Je considère **FastAPI** comme un "successeur spirituel" d'APIStar, tout en améliorant et en augmentant les fonctionnalités, le système de typage et d'autres parties, sur la base des enseignements tirés de tous ces outils précédents. + +## Utilisés par **FastAPI** + +### Pydantic + +Pydantic est une bibliothèque permettant de définir la validation, la sérialisation et la documentation des données (à l'aide de JSON Schema) en se basant sur les Python type hints. + +Cela le rend extrêmement intuitif. + +Il est comparable à Marshmallow. Bien qu'il soit plus rapide que Marshmallow dans les benchmarks. Et comme il est +basé sur les mêmes type hints Python, le support de l'éditeur est grand. + +!!! check "**FastAPI** l'utilise pour" +Gérer toute la validation des données, leur sérialisation et la documentation automatique du modèle (basée sur le schéma JSON). + + **FastAPI** prend ensuite ces données JSON Schema et les place dans OpenAPI, en plus de toutes les autres choses qu'il fait. + +### Starlette + +Starlette est un framework/toolkit léger ASGI, qui est idéal pour construire des services asyncio performants. + +Il est très simple et intuitif. Il est conçu pour être facilement extensible et avoir des composants modulaires. + +Il offre : + +- Des performances vraiment impressionnantes. +- Le support des WebSockets. +- Le support de GraphQL. +- Les tâches d'arrière-plan. +- Les événements de démarrage et d'arrêt. +- Un client de test basé sur request. +- CORS, GZip, fichiers statiques, streaming des réponses. +- Le support des sessions et des cookies. +- Une couverture de test à 100 %. +- 100 % de la base de code avec des annotations de type. +- Zéro forte dépendance à d'autres packages. + +Starlette est actuellement le framework Python le plus rapide testé. Seulement dépassé par Uvicorn, qui n'est pas un framework, mais un serveur. + +Starlette fournit toutes les fonctionnalités de base d'un micro-framework web. + +Mais il ne fournit pas de validation automatique des données, de sérialisation ou de documentation. + +C'est l'une des principales choses que **FastAPI** ajoute par-dessus, le tout basé sur les type hints Python (en utilisant Pydantic). Cela, plus le système d'injection de dépendances, les utilitaires de sécurité, la génération de schémas OpenAPI, etc. + +!!! note "Détails techniques" +ASGI est une nouvelle "norme" développée par les membres de l'équipe principale de Django. Il ne s'agit pas encore d'une "norme Python" (un PEP), bien qu'ils soient en train de le faire. + + Néanmoins, il est déjà utilisé comme "standard" par plusieurs outils. Cela améliore grandement l'interopérabilité, puisque vous pouvez remplacer Uvicorn par n'importe quel autre serveur ASGI (comme Daphne ou Hypercorn), ou vous pouvez ajouter des outils compatibles ASGI, comme `python-socketio`. + +!!! check "**FastAPI** l'utilise pour" +Gérer toutes les parties web de base. Ajouter des fonctionnalités par-dessus. + + La classe `FastAPI` elle-même hérite directement de la classe `Starlette`. + + Ainsi, tout ce que vous pouvez faire avec Starlette, vous pouvez le faire directement avec **FastAPI**, car il s'agit en fait de Starlette sous stéroïdes. + +### Uvicorn + +Uvicorn est un serveur ASGI rapide comme l'éclair, basé sur uvloop et httptools. + +Il ne s'agit pas d'un framework web, mais d'un serveur. Par exemple, il ne fournit pas d'outils pour le routing. C'est +quelque chose qu'un framework comme Starlette (ou **FastAPI**) fournirait par-dessus. + +C'est le serveur recommandé pour Starlette et **FastAPI**. + +!!! check "**FastAPI** le recommande comme" +Le serveur web principal pour exécuter les applications **FastAPI**. + + Vous pouvez le combiner avec Gunicorn, pour avoir un serveur multi-processus asynchrone. + + Pour plus de détails, consultez la section [Déploiement](deployment/index.md){.internal-link target=_blank}. + +## Benchmarks et vitesse + +Pour comprendre, comparer et voir la différence entre Uvicorn, Starlette et FastAPI, consultez la section sur les [Benchmarks](benchmarks.md){.internal-link target=\_blank}. diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index f1c66c759..c5860a4ba 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -55,6 +55,7 @@ nav: - fastapi-people.md - Tutoriel - Guide utilisateur: - tutorial/background-tasks.md +- alternatives.md markdown_extensions: - toc: permalink: true From 3127bc4e05b72e39d1681735ec1ee49844b7dc88 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:06:45 +0000 Subject: [PATCH 024/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6821f7c55..a769f0a52 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for Alternatives, Inspiration and Comparisons. PR [#3020](https://github.com/tiangolo/fastapi/pull/3020) by [@rjNemo](https://github.com/rjNemo). * 🌐 Fix Chinese translation code snippet mismatch in Tutorial - Python Types Intro. PR [#2573](https://github.com/tiangolo/fastapi/pull/2573) by [@BoYanZh](https://github.com/BoYanZh). * 🌐 Add Portuguese translation for Development Contributing. PR [#1364](https://github.com/tiangolo/fastapi/pull/1364) by [@Serrones](https://github.com/Serrones). * ⬆ Upgrade docs development dependency on `typer-cli` to >=0.0.12 to fix conflicts. PR [#3429](https://github.com/tiangolo/fastapi/pull/3429) by [@tiangolo](https://github.com/tiangolo). From acda3f06b0a884965fb4196dbf029b1043a770ed Mon Sep 17 00:00:00 2001 From: Sam Courtemanche Date: Fri, 2 Jul 2021 16:12:05 +0200 Subject: [PATCH 025/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20External=20Links=20(#3103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/fr/docs/external-links.md | 82 ++++++++++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 83 insertions(+) create mode 100644 docs/fr/docs/external-links.md diff --git a/docs/fr/docs/external-links.md b/docs/fr/docs/external-links.md new file mode 100644 index 000000000..002e6d2b2 --- /dev/null +++ b/docs/fr/docs/external-links.md @@ -0,0 +1,82 @@ +# Articles et liens externes + +**FastAPI** possède une grande communauté en constante extension. + +Il existe de nombreux articles, outils et projets liés à **FastAPI**. + +Voici une liste incomplète de certains d'entre eux. + +!!! tip "Astuce" + Si vous avez un article, projet, outil, ou quoi que ce soit lié à **FastAPI** qui n'est actuellement pas listé ici, créez une Pull Request l'ajoutant. + +## Articles + +### Anglais + +{% if external_links %} +{% for article in external_links.articles.english %} + +* {{ article.title }} par {{ article.author }}. +{% endfor %} +{% endif %} + +### Japonais + +{% if external_links %} +{% for article in external_links.articles.japanese %} + +* {{ article.title }} par {{ article.author }}. +{% endfor %} +{% endif %} + +### Vietnamien + +{% if external_links %} +{% for article in external_links.articles.vietnamese %} + +* {{ article.title }} par {{ article.author }}. +{% endfor %} +{% endif %} + +### Russe + +{% if external_links %} +{% for article in external_links.articles.russian %} + +* {{ article.title }} par {{ article.author }}. +{% endfor %} +{% endif %} + +### Allemand + +{% if external_links %} +{% for article in external_links.articles.german %} + +* {{ article.title }} par {{ article.author }}. +{% endfor %} +{% endif %} + +## Podcasts + +{% if external_links %} +{% for article in external_links.podcasts.english %} + +* {{ article.title }} par {{ article.author }}. +{% endfor %} +{% endif %} + +## Conférences + +{% if external_links %} +{% for article in external_links.talks.english %} + +* {{ article.title }} par {{ article.author }}. +{% endfor %} +{% endif %} + +## Projets + +Les projets Github avec le topic `fastapi` les plus récents : + +
+
diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index c5860a4ba..c0bbb2ac3 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -56,6 +56,7 @@ nav: - Tutoriel - Guide utilisateur: - tutorial/background-tasks.md - alternatives.md +- external-links.md markdown_extensions: - toc: permalink: true From 0abb743e9c4994e5fdd5abc346967675c4b319c8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:12:43 +0000 Subject: [PATCH 026/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a769f0a52..e312fb315 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for External Links. PR [#3103](https://github.com/tiangolo/fastapi/pull/3103) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for Alternatives, Inspiration and Comparisons. PR [#3020](https://github.com/tiangolo/fastapi/pull/3020) by [@rjNemo](https://github.com/rjNemo). * 🌐 Fix Chinese translation code snippet mismatch in Tutorial - Python Types Intro. PR [#2573](https://github.com/tiangolo/fastapi/pull/2573) by [@BoYanZh](https://github.com/BoYanZh). * 🌐 Add Portuguese translation for Development Contributing. PR [#1364](https://github.com/tiangolo/fastapi/pull/1364) by [@Serrones](https://github.com/Serrones). From a694be81ae2f2d4b6657fd33b62bc631acbc3f04 Mon Sep 17 00:00:00 2001 From: Sam Courtemanche Date: Fri, 2 Jul 2021 16:13:52 +0200 Subject: [PATCH 027/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20Python=20Types=20Intro=20(#3185)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/fr/docs/python-types.md | 314 +++++++++++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 315 insertions(+) create mode 100644 docs/fr/docs/python-types.md diff --git a/docs/fr/docs/python-types.md b/docs/fr/docs/python-types.md new file mode 100644 index 000000000..4008ed96f --- /dev/null +++ b/docs/fr/docs/python-types.md @@ -0,0 +1,314 @@ +# Introduction aux Types Python + +Python supporte des annotations de type (ou *type hints*) optionnelles. + +Ces annotations de type constituent une syntaxe spéciale qui permet de déclarer le type d'une variable. + +En déclarant les types de vos variables, cela permet aux différents outils comme les éditeurs de texte d'offrir un meilleur support. + +Ce chapitre n'est qu'un **tutoriel rapide / rappel** sur les annotations de type Python. +Seulement le minimum nécessaire pour les utiliser avec **FastAPI** sera couvert... ce qui est en réalité très peu. + +**FastAPI** est totalement basé sur ces annotations de type, qui lui donnent de nombreux avantages. + +Mais même si vous n'utilisez pas ou n'utiliserez jamais **FastAPI**, vous pourriez bénéficier d'apprendre quelques choses sur ces dernières. + +!!! note + Si vous êtes un expert Python, et que vous savez déjà **tout** sur les annotations de type, passez au chapitre suivant. + +## Motivations + +Prenons un exemple simple : + +```Python +{!../../../docs_src/python_types/tutorial001.py!} +``` + +Exécuter ce programe affiche : + +``` +John Doe +``` + +La fonction : + +* Prend un `first_name` et un `last_name`. +* Convertit la première lettre de chaque paramètre en majuscules grâce à `title()`. +* Concatène les résultats avec un espace entre les deux. + +```Python hl_lines="2" +{!../../../docs_src/python_types/tutorial001.py!} +``` + +### Limitations + +C'est un programme très simple. + +Mais maintenant imaginez que vous l'écriviez de zéro. + +À un certain point vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts. + +Mais vous aviez besoin de "cette méthode qui convertit la première lettre en majuscule". + +Était-ce `upper` ? `uppercase` ? `first_uppercase` ? `capitalize` ? + +Vous essayez donc d'utiliser le vieil ami du programmeur, l'auto-complétion de l'éditeur. + +Vous écrivez le premier paramètre, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'auto-complétion. + +Mais malheureusement, rien d'utile n'en résulte : + + + +### Ajouter des types + +Modifions une seule ligne de la version précédente. + +Nous allons changer seulement cet extrait, les paramètres de la fonction, de : + + +```Python + first_name, last_name +``` + +à : + +```Python + first_name: str, last_name: str +``` + +C'est tout. + +Ce sont des annotations de types : + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial002.py!} +``` + +À ne pas confondre avec la déclaration de valeurs par défaut comme ici : + +```Python + first_name="john", last_name="doe" +``` + +C'est une chose différente. + +On utilise un deux-points (`:`), et pas un égal (`=`). + +Et ajouter des annotations de types ne crée normalement pas de différence avec le comportement qui aurait eu lieu si elles n'étaient pas là. + +Maintenant, imaginez que vous êtes en train de créer cette fonction, mais avec des annotations de type cette fois. + +Au même moment que durant l'exemple précédent, vous essayez de déclencher l'auto-complétion et vous voyez : + + + +Vous pouvez donc dérouler les options jusqu'à trouver la méthode à laquelle vous pensiez. + + + +## Plus de motivations + +Cette fonction possède déjà des annotations de type : + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial003.py!} +``` + +Comme l'éditeur connaît le type des variables, vous n'avez pas seulement l'auto-complétion, mais aussi de la détection d'erreurs : + + + +Maintenant que vous avez connaissance du problème, convertissez `age` en chaine de caractères grâce à `str(age)` : + +```Python hl_lines="2" +{!../../../docs_src/python_types/tutorial004.py!} +``` + +## Déclarer des types + +Vous venez de voir là où les types sont généralement déclarés : dans les paramètres de fonctions. + +C'est aussi ici que vous les utiliseriez avec **FastAPI**. + +### Types simples + +Vous pouvez déclarer tous les types de Python, pas seulement `str`. + +Comme par exemple : + +* `int` +* `float` +* `bool` +* `bytes` + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial005.py!} +``` + +### Types génériques avec des paramètres de types + +Il existe certaines structures de données qui contiennent d'autres valeurs, comme `dict`, `list`, `set` et `tuple`. Et les valeurs internes peuvent elles aussi avoir leurs propres types. + +Pour déclarer ces types et les types internes, on utilise le module standard de Python `typing`. + +Il existe spécialement pour supporter ces annotations de types. + +#### `List` + +Par exemple, définissons une variable comme `list` de `str`. + +Importez `List` (avec un `L` majuscule) depuis `typing`. + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial006.py!} +``` + +Déclarez la variable, en utilisant la syntaxe des deux-points (`:`). + +Et comme type, mettez `List`. + +Les listes étant un type contenant des types internes, mettez ces derniers entre crochets (`[`, `]`) : + +```Python hl_lines="4" +{!../../../docs_src/python_types/tutorial006.py!} +``` + +!!! tip "Astuce" + Ces types internes entre crochets sont appelés des "paramètres de type". + + Ici, `str` est un paramètre de type passé à `List`. + +Ce qui signifie : "la variable `items` est une `list`, et chacun de ses éléments a pour type `str`. + +En faisant cela, votre éditeur pourra vous aider, même pendant que vous traitez des éléments de la liste. + + + +Sans types, c'est presque impossible à réaliser. + +Vous remarquerez que la variable `item` n'est qu'un des éléments de la list `items`. + +Et pourtant, l'éditeur sait qu'elle est de type `str` et pourra donc vous aider à l'utiliser. + +#### `Tuple` et `Set` + +C'est le même fonctionnement pour déclarer un `tuple` ou un `set` : + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial007.py!} +``` + +Dans cet exemple : + +* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un deuxième `int`, et un `str`. +* La variable `items_s` est un `set`, et chacun de ses éléments est de type `bytes`. + +#### `Dict` + +Pour définir un `dict`, il faut lui passer 2 paramètres, séparés par une virgule (`,`). + +Le premier paramètre de type est pour les clés et le second pour les valeurs du dictionnaire (`dict`). + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial008.py!} +``` + +Dans cet exemple : + +* La variable `prices` est de type `dict` : + * Les clés de ce dictionnaire sont de type `str`. + * Les valeurs de ce dictionnaire sont de type `float`. + +#### `Optional` + +Vous pouvez aussi utiliser `Optional` pour déclarer qu'une variable a un type, comme `str` mais qu'il est "optionnel" signifiant qu'il pourrait aussi être `None`. + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial009.py!} +``` + +Utiliser `Optional[str]` plutôt que `str` permettra à l'éditeur de vous aider à détecter les erreurs où vous supposeriez qu'une valeur est toujours de type `str`, alors qu'elle pourrait aussi être `None`. + +#### Types génériques + +Les types qui peuvent contenir des paramètres de types entre crochets, comme : + +* `List` +* `Tuple` +* `Set` +* `Dict` +* `Optional` +* ...et d'autres. + +sont appelés des **types génériques** ou **Generics**. + +### Classes en tant que types + +Vous pouvez aussi déclarer une classe comme type d'une variable. + +Disons que vous avez une classe `Person`, avec une variable `name` : + +```Python hl_lines="1-3" +{!../../../docs_src/python_types/tutorial010.py!} +``` + +Vous pouvez ensuite déclarer une variable de type `Person` : + +```Python hl_lines="6" +{!../../../docs_src/python_types/tutorial010.py!} +``` + +Et vous aurez accès, encore une fois, au support complet offert par l'éditeur : + + + +## Les modèles Pydantic + +Pydantic est une bibliothèque Python pour effectuer de la validation de données. + +Vous déclarez la forme de la donnée avec des classes et des attributs. + +Chaque attribut possède un type. + +Puis vous créez une instance de cette classe avec certaines valeurs et **Pydantic** validera les valeurs, les convertira dans le type adéquat (si c'est nécessaire et possible) et vous donnera un objet avec toute la donnée. + +Ainsi, votre éditeur vous offrira un support adapté pour l'objet résultant. + +Extrait de la documentation officielle de **Pydantic** : + +```Python +{!../../../docs_src/python_types/tutorial011.py!} +``` + +!!! info + Pour en savoir plus à propos de Pydantic, allez jeter un coup d'oeil à sa documentation. + +**FastAPI** est basé entièrement sur **Pydantic**. + +Vous verrez bien plus d'exemples de son utilisation dans [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}. + +## Les annotations de type dans **FastAPI** + +**FastAPI** utilise ces annotations pour faire différentes choses. + +Avec **FastAPI**, vous déclarez des paramètres grâce aux annotations de types et vous obtenez : + +* **du support de l'éditeur** +* **de la vérification de types** + +...et **FastAPI** utilise ces mêmes déclarations pour : + +* **Définir les prérequis** : depuis les paramètres de chemins des requêtes, les entêtes, les corps, les dépendances, etc. +* **Convertir des données** : depuis la requête vers les types requis. +* **Valider des données** : venant de chaque requête : + * Générant automatiquement des **erreurs** renvoyées au client quand la donnée est invalide. +* **Documenter** l'API avec OpenAPI : + * ce qui ensuite utilisé par les interfaces utilisateur automatiques de documentation interactive. + +Tout cela peut paraître bien abstrait, mais ne vous inquiétez pas, vous verrez tout ça en pratique dans [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}. + +Ce qu'il faut retenir c'est qu'en utilisant les types standard de Python, à un seul endroit (plutôt que d'ajouter plus de classes, de décorateurs, etc.), **FastAPI** fera une grande partie du travail pour vous. + +!!! info + Si vous avez déjà lu le tutoriel et êtes revenus ici pour voir plus sur les types, une bonne ressource est la "cheat sheet" de `mypy`. diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index c0bbb2ac3..adb2ccc69 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -53,6 +53,7 @@ nav: - zh: /zh/ - features.md - fastapi-people.md +- python-types.md - Tutoriel - Guide utilisateur: - tutorial/background-tasks.md - alternatives.md From fdc7c96ecea669ebe3c2f60445f08b452cf923b4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:14:28 +0000 Subject: [PATCH 028/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e312fb315..dea293736 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for Python Types Intro. PR [#3185](https://github.com/tiangolo/fastapi/pull/3185) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for External Links. PR [#3103](https://github.com/tiangolo/fastapi/pull/3103) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for Alternatives, Inspiration and Comparisons. PR [#3020](https://github.com/tiangolo/fastapi/pull/3020) by [@rjNemo](https://github.com/rjNemo). * 🌐 Fix Chinese translation code snippet mismatch in Tutorial - Python Types Intro. PR [#2573](https://github.com/tiangolo/fastapi/pull/2573) by [@BoYanZh](https://github.com/BoYanZh). From 4473a9bcbf38e70321536b4ca7b71e45299ddcc2 Mon Sep 17 00:00:00 2001 From: Sam Courtemanche Date: Fri, 2 Jul 2021 16:18:06 +0200 Subject: [PATCH 029/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20Project=20Generation=20(#3197)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/fr/docs/project-generation.md | 84 ++++++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 85 insertions(+) create mode 100644 docs/fr/docs/project-generation.md diff --git a/docs/fr/docs/project-generation.md b/docs/fr/docs/project-generation.md new file mode 100644 index 000000000..c58d2cd2b --- /dev/null +++ b/docs/fr/docs/project-generation.md @@ -0,0 +1,84 @@ +# Génération de projets - Modèle + +Vous pouvez utiliser un générateur de projet pour commencer, qui réalisera pour vous la mise en place de bases côté architecture globale, sécurité, base de données et premières routes d'API. + +Un générateur de projet fera toujours une mise en place très subjective que vous devriez modifier et adapter suivant vos besoins, mais cela reste un bon point de départ pour vos projets. + +## Full Stack FastAPI PostgreSQL + +GitHub : https://github.com/tiangolo/full-stack-fastapi-postgresql + +### Full Stack FastAPI PostgreSQL - Fonctionnalités + +* Intégration **Docker** complète (basée sur Docker). +* Déploiement Docker en mode Swarm +* Intégration **Docker Compose** et optimisation pour développement local. +* Serveur web Python **prêt au déploiement** utilisant Uvicorn et Gunicorn. +* Backend Python **FastAPI** : + * **Rapide** : Très hautes performances, comparables à **NodeJS** ou **Go** (grâce à Starlette et Pydantic). + * **Intuitif** : Excellent support des éditeurs. Complétion partout. Moins de temps passé à déboguer. + * **Facile** : Fait pour être facile à utiliser et apprendre. Moins de temps passé à lire de la documentation. + * **Concis** : Minimise la duplication de code. Plusieurs fonctionnalités à chaque déclaration de paramètre. + * **Robuste** : Obtenez du code prêt pour être utilisé en production. Avec de la documentation automatique interactive. + * **Basé sur des normes** : Basé sur (et totalement compatible avec) les normes ouvertes pour les APIs : OpenAPI et JSON Schema. + * **Et bien d'autres fonctionnalités** comme la validation automatique, la sérialisation, l'authentification avec OAuth2 JWT tokens, etc. +* Hashage de **mots de passe sécurisé** par défaut. +* Authentification par **jetons JWT**. +* Modèles **SQLAlchemy** (indépendants des extensions Flask, afin qu'ils puissent être utilisés directement avec des *workers* Celery). +* Modèle de démarrages basiques pour les utilisateurs (à modifier et supprimer au besoin). +* Migrations **Alembic**. +* **CORS** (partage des ressources entre origines multiples, ou *Cross Origin Resource Sharing*). +* *Worker* **Celery** pouvant importer et utiliser les modèles et le code du reste du backend. +* Tests du backend REST basés sur **Pytest**, intégrés dans Docker, pour que vous puissiez tester toutes les interactions de l'API indépendamment de la base de données. Étant exécutés dans Docker, les tests peuvent utiliser un nouvel entrepôt de données créé de zéro à chaque fois (vous pouvez donc utiliser ElasticSearch, MongoDB, CouchDB, etc. et juste tester que l'API fonctionne). +* Intégration Python facile avec **Jupyter Kernels** pour le développement à distance ou intra-Docker avec des extensions comme Atom Hydrogen ou Visual Studio Code Jupyter. +* Frontend **Vue** : + * Généré avec Vue CLI. + * Gestion de l'**Authentification JWT**. + * Page de connexion. + * Après la connexion, page de tableau de bord principal. + * Tableau de bord principal avec création et modification d'utilisateurs. + * Modification de ses propres caractéristiques utilisateur. + * **Vuex**. + * **Vue-router**. + * **Vuetify** pour de magnifiques composants *material design*. + * **TypeScript**. + * Serveur Docker basé sur **Nginx** (configuré pour être facilement manipulé avec Vue-router). + * Utilisation de *Docker multi-stage building*, pour ne pas avoir besoin de sauvegarder ou *commit* du code compilé. + * Tests frontend exécutés à la compilation (pouvant être désactivés). + * Fait aussi modulable que possible, pour pouvoir fonctionner comme tel, tout en pouvant être utilisé qu'en partie grâce à Vue CLI. +* **PGAdmin** pour les bases de données PostgreSQL, facilement modifiable pour utiliser PHPMYAdmin ou MySQL. +* **Flower** pour la surveillance de tâches Celery. +* Équilibrage de charge entre le frontend et le backend avec **Traefik**, afin de pouvoir avoir les deux sur le même domaine, séparés par chemins, mais servis par différents conteneurs. +* Intégration Traefik, comprenant la génération automatique de certificat **HTTPS** Let's Encrypt. +* GitLab **CI** (intégration continue), comprenant des tests pour le frontend et le backend. + +## Full Stack FastAPI Couchbase + +GitHub : https://github.com/tiangolo/full-stack-fastapi-couchbase + +⚠️ **ATTENTION** ⚠️ + +Si vous démarrez un nouveau projet de zéro, allez voir les alternatives au début de cette page. + +Par exemple, le générateur de projet Full Stack FastAPI PostgreSQL peut être une meilleure alternative, étant activement maintenu et utilisé et comprenant toutes les nouvelles fonctionnalités et améliorations. + +Vous êtes toujours libre d'utiliser le générateur basé sur Couchbase si vous le voulez, cela devrait probablement fonctionner correctement, et si vous avez déjà un projet généré en utilisant ce dernier, cela devrait fonctionner aussi (et vous l'avez déjà probablement mis à jour suivant vos besoins). + +Vous pouvez en apprendre plus dans la documentation du dépôt GithHub. + +## Full Stack FastAPI MongoDB + +...viendra surement plus tard, suivant le temps que j'ai. 😅 🎉 + +## Modèles d'apprentissage automatique avec spaCy et FastAPI + +GitHub : https://github.com/microsoft/cookiecutter-spacy-fastapi + +## Modèles d'apprentissage automatique avec spaCy et FastAPI - Fonctionnalités + +* Intégration d'un modèle NER **spaCy**. +* Formatage de requête pour **Azure Cognitive Search**. +* Serveur Python web **prêt à utiliser en production** utilisant Uvicorn et Gunicorn. +* Déploiement CI/CD Kubernetes pour **Azure DevOps** (AKS). +* **Multilangues**. Choisissez facilement l'une des langues intégrées à spaCy durant la mise en place du projet. +* **Facilement généralisable** à d'autres bibliothèques similaires (Pytorch, Tensorflow), et non juste spaCy. diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index adb2ccc69..250af172a 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -56,6 +56,7 @@ nav: - python-types.md - Tutoriel - Guide utilisateur: - tutorial/background-tasks.md +- project-generation.md - alternatives.md - external-links.md markdown_extensions: From eb6f964ede1753a1cba475d0e2c014601fe5ea9d Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:18:44 +0000 Subject: [PATCH 030/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index dea293736..d541a6c20 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for Project Generation. PR [#3197](https://github.com/tiangolo/fastapi/pull/3197) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for Python Types Intro. PR [#3185](https://github.com/tiangolo/fastapi/pull/3185) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for External Links. PR [#3103](https://github.com/tiangolo/fastapi/pull/3103) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for Alternatives, Inspiration and Comparisons. PR [#3020](https://github.com/tiangolo/fastapi/pull/3020) by [@rjNemo](https://github.com/rjNemo). From 4bf9a520437a505c0ac68e73815bd0ce88a0f8bc Mon Sep 17 00:00:00 2001 From: Hareru <52149629+hareru@users.noreply.github.com> Date: Fri, 2 Jul 2021 22:20:36 +0800 Subject: [PATCH 031/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20FastAPI=20People=20(#3112)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Xie Wei Co-authored-by: Sebastián Ramírez --- docs/zh/docs/fastapi-people.md | 165 +++++++++++++++++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 166 insertions(+) create mode 100644 docs/zh/docs/fastapi-people.md diff --git a/docs/zh/docs/fastapi-people.md b/docs/zh/docs/fastapi-people.md new file mode 100644 index 000000000..080af2ee6 --- /dev/null +++ b/docs/zh/docs/fastapi-people.md @@ -0,0 +1,165 @@ +# FastAPI 社区 + +FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋友。 + +## 创建者 & 维护者 + +嘿! 👋 + +这就是我: + +{% if people %} +
+{% for user in people.maintainers %} + +
@{{ user.login }}
Answers: {{ user.answers }}
Pull Requests: {{ user.prs }}
+{% endfor %} + +
+{% endif %} + +我是 **FastAPI** 的创建者和维护者. 你能在 [帮助 FastAPI - 获取帮助 - 与作者联系](help-fastapi.md#connect-with-the-author){.internal-link target=_blank} 阅读有关此内容的更多信息。 + +...但是在这里我想向您展示社区。 + +--- + +**FastAPI** 得到了社区的大力支持。因此我想突出他们的贡献。 + +这些人: + +* [帮助他人解决 GitHub 的 issues](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}。 +* [创建 Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}。 +* 审核 Pull Requests, 对于 [翻译](contributing.md#translations){.internal-link target=_blank} 尤为重要。 + +向他们致以掌声。 👏 🙇 + +## 上个月最活跃的用户 + +上个月这些用户致力于 [帮助他人解决 GitHub 的 issues](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}。 + +{% if people %} +
+{% for user in people.last_month_active %} + +
@{{ user.login }}
Issues replied: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +## 专家组 + +以下是 **FastAPI 专家**。 🤓 + +这些用户一直以来致力于 [帮助他人解决 GitHub 的 issues](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}。 + +他们通过帮助许多人而被证明是专家。✨ + +{% if people %} +
+{% for user in people.experts %} + +
@{{ user.login }}
Issues replied: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +## 杰出贡献者 + +以下是 **杰出的贡献者**。 👷 + +这些用户 [创建了最多已被合并的 Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}。 + +他们贡献了源代码,文档,翻译等。 📦 + +{% if people %} +
+{% for user in people.top_contributors %} + +
@{{ user.login }}
Pull Requests: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +还有很多其他贡献者(超过100个),你可以在 FastAPI GitHub 贡献者页面 中看到他们。👷 + +## 杰出审核者 + +以下用户是「杰出的评审者」。 🕵️ + +### 翻译审核 + +我只会说少数几种语言(而且还不是很流利 😅)。所以,具备[能力去批准文档翻译](contributing.md#translations){.internal-link target=_blank} 是这些评审者们。如果没有它们,就不会有多语言文档。 + +--- + +**杰出的评审者** 🕵️ 评审了最多来自他人的 Pull Requests,他们保证了代码、文档尤其是 **翻译** 的质量。 + +{% if people %} +
+{% for user in people.top_reviewers %} + +
@{{ user.login }}
Reviews: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +## 赞助商 + +以下是 **赞助商** 。😎 + +他们主要通过GitHub Sponsors支持我在 **FastAPI** (和其他项目)的工作。 + +### 金牌赞助商 + +{% if sponsors %} {% for sponsor in sponsors.gold -%} + +{% endfor %} {% endif %} + +### 银牌赞助商 + +{% if sponsors %} {% for sponsor in sponsors.silver -%} + +{% endfor %} {% endif %} + +{% if people %} {% if people.sponsors_50 %} + +### 铜牌赞助商 + +
+{% for user in people.sponsors_50 %} + + +{% endfor %} + +
+ +{% endif %} {% endif %} + +### 个人赞助 + +{% if people %} +
+{% for user in people.sponsors %} + + +{% endfor %} + +
+{% endif %} + +## 关于数据 - 技术细节 + +该页面的目的是突出社区为帮助他人而付出的努力。 + +尤其是那些不引人注目且涉及更困难的任务,例如帮助他人解决问题或者评审翻译 Pull Requests。 + +该数据每月计算一次,您可以阅读 源代码。 + +这里也强调了赞助商的贡献。 + +我也保留更新算法,栏目,统计阈值等的权利(以防万一🤷)。 diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 8551e6443..cdcb6ea4d 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -52,6 +52,7 @@ nav: - uk: /uk/ - zh: /zh/ - features.md +- fastapi-people.md - python-types.md - 教程 - 用户指南: - tutorial/index.md From 098088c76342f163667a62cad0626fef3998150f Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:21:11 +0000 Subject: [PATCH 032/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d541a6c20..814fbf55d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for FastAPI People. PR [#3112](https://github.com/tiangolo/fastapi/pull/3112) by [@hareru](https://github.com/hareru). * 🌐 Add French translation for Project Generation. PR [#3197](https://github.com/tiangolo/fastapi/pull/3197) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for Python Types Intro. PR [#3185](https://github.com/tiangolo/fastapi/pull/3185) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for External Links. PR [#3103](https://github.com/tiangolo/fastapi/pull/3103) by [@Smlep](https://github.com/Smlep). From e6836781d5178c021e5e01127aa893c190af132a Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Fri, 2 Jul 2021 22:23:41 +0800 Subject: [PATCH 033/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20Tutorial=20-=20Body=20-=20Updates=20(#3237)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Xie Wei Co-authored-by: Sebastián Ramírez --- docs/zh/docs/tutorial/body-updates.md | 101 ++++++++++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 102 insertions(+) create mode 100644 docs/zh/docs/tutorial/body-updates.md diff --git a/docs/zh/docs/tutorial/body-updates.md b/docs/zh/docs/tutorial/body-updates.md new file mode 100644 index 000000000..176bb174e --- /dev/null +++ b/docs/zh/docs/tutorial/body-updates.md @@ -0,0 +1,101 @@ +# 请求体 - 更新数据 + +## 用 `PUT` 更新数据 + +更新数据请用 HTTP `PUT` 操作。 + +把输入数据转换为以 JSON 格式存储的数据(比如,使用 NoSQL 数据库时),可以使用 `jsonable_encoder`。例如,把 `datetime` 转换为 `str`。 + +```Python hl_lines="30-35" +{!../../../docs_src/body_updates/tutorial001.py!} +``` + +`PUT` 用于接收替换现有数据的数据。 + +### 关于更新数据的警告 + +用 `PUT` 把数据项 `bar` 更新为以下内容时: + +```Python +{ + "name": "Barz", + "price": 3, + "description": None, +} +``` + +因为上述数据未包含已存储的属性 `"tax": 20.2`,新的输入模型会把 `"tax": 10.5` 作为默认值。 + +因此,本次操作把 `tax` 的值「更新」为 `10.5`。 + +## 用 `PATCH` 进行部分更新 + +HTTP `PATCH` 操作用于更新 *部分* 数据。 + +即,只发送要更新的数据,其余数据保持不变。 + +!!! Note "笔记" + + `PATCH` 没有 `PUT` 知名,也怎么不常用。 + + 很多人甚至只用 `PUT` 实现部分更新。 + + **FastAPI** 对此没有任何限制,可以**随意**互换使用这两种操作。 + + 但本指南也会分别介绍这两种操作各自的用途。 + +### 使用 Pydantic 的 `exclude_unset` 参数 + +更新部分数据时,可以在 Pydantic 模型的 `.dict()` 中使用 `exclude_unset` 参数。 + +比如,`item.dict(exclude_unset=True)`。 + +这段代码生成的 `dict` 只包含创建 `item` 模型时显式设置的数据,而不包括默认值。 + +然后再用它生成一个只含已设置(在请求中所发送)数据,且省略了默认值的 `dict`: + +```Python hl_lines="34" +{!../../../docs_src/body_updates/tutorial002.py!} +``` + +### 使用 Pydantic 的 `update` 参数 + +接下来,用 `.copy()` 为已有模型创建调用 `update` 参数的副本,该参数为包含更新数据的 `dict`。 + +例如,`stored_item_model.copy(update=update_data)`: + +```Python hl_lines="35" +{!../../../docs_src/body_updates/tutorial002.py!} +``` + +### 更新部分数据小结 + +简而言之,更新部分数据应: + +* 使用 `PATCH` 而不是 `PUT` (可选,也可以用 `PUT`); +* 提取存储的数据; +* 把数据放入 Pydantic 模型; +* 生成不含输入模型默认值的 `dict` (使用 `exclude_unset` 参数); + * 只更新用户设置过的值,不用模型中的默认值覆盖已存储过的值。 +* 为已存储的模型创建副本,用接收的数据更新其属性 (使用 `update` 参数)。 +* 把模型副本转换为可存入数据库的形式(比如,使用 `jsonable_encoder`)。 + * 这种方式与 Pydantic 模型的 `.dict()` 方法类似,但能确保把值转换为适配 JSON 的数据类型,例如, 把 `datetime` 转换为 `str` 。 +* 把数据保存至数据库; +* 返回更新后的模型。 + +```Python hl_lines="30-37" +{!../../../docs_src/body_updates/tutorial002.py!} +``` + +!!! tip "提示" + + 实际上,HTTP `PUT` 也可以完成相同的操作。 + 但本节以 `PATCH` 为例的原因是,该操作就是为了这种用例创建的。 + +!!! note "笔记" + + 注意,输入模型仍需验证。 + + 因此,如果希望接收的部分更新数据可以省略其他所有属性,则要把模型中所有的属性标记为可选(使用默认值或 `None`)。 + + 为了区分用于**更新**所有可选值的模型与用于**创建**包含必选值的模型,请参照[更多模型](extra-models.md){.internal-link target=_blank} 一节中的思路。 diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index cdcb6ea4d..f63f341f0 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -74,6 +74,7 @@ nav: - tutorial/extra-data-types.md - tutorial/cookie-params.md - tutorial/request-files.md + - tutorial/body-updates.md - 安全性: - tutorial/security/index.md - tutorial/security/get-current-user.md From 8116d8158b48bd3316295cb949d9b02820a0d9c4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:24:16 +0000 Subject: [PATCH 034/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 814fbf55d..1120adf96 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for Tutorial - Body - Updates. PR [#3237](https://github.com/tiangolo/fastapi/pull/3237) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for FastAPI People. PR [#3112](https://github.com/tiangolo/fastapi/pull/3112) by [@hareru](https://github.com/hareru). * 🌐 Add French translation for Project Generation. PR [#3197](https://github.com/tiangolo/fastapi/pull/3197) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for Python Types Intro. PR [#3185](https://github.com/tiangolo/fastapi/pull/3185) by [@Smlep](https://github.com/Smlep). From 5e2f2d541dd78106652094e0dac0d6810fa73823 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 2 Jul 2021 16:27:02 +0200 Subject: [PATCH 035/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#3319)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/people.yml | 200 +++++++++++++++++++++++++++------------- 1 file changed, 135 insertions(+), 65 deletions(-) diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index fc5ed85fd..d1898a931 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,7 +1,7 @@ maintainers: - login: tiangolo - answers: 1221 - prs: 222 + answers: 1225 + prs: 230 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=05f95ca7fdead36edd9c86be46b4ef6c3c71f876&v=4 url: https://github.com/tiangolo experts: @@ -10,15 +10,15 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu - login: Kludex - count: 240 + count: 254 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: ycd - count: 211 + count: 214 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: Mause - count: 174 + count: 176 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause - login: euri10 @@ -29,20 +29,20 @@ experts: count: 130 avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 +- login: ArcLightSlavik + count: 58 + avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 + url: https://github.com/ArcLightSlavik - login: falkben count: 56 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 url: https://github.com/falkben -- login: ArcLightSlavik - count: 50 - avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=6e53b1a2f340d77429d435babcec107c7cc50972&v=4 - url: https://github.com/ArcLightSlavik - login: sm-Fifteen count: 46 avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 url: https://github.com/sm-Fifteen - login: raphaelauv - count: 41 + count: 44 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv - login: includeamin @@ -54,7 +54,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4 url: https://github.com/prostomarkeloff - login: Dustyposa - count: 31 + count: 32 avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 url: https://github.com/Dustyposa - login: krishnardt @@ -89,10 +89,18 @@ experts: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 url: https://github.com/chris-allnutt +- login: chbndrhnns + count: 20 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: retnikt count: 19 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 url: https://github.com/retnikt +- login: Hultner + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 + url: https://github.com/Hultner - login: jorgerpo count: 17 avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4 @@ -101,12 +109,8 @@ experts: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4 url: https://github.com/nkhitrov -- login: chbndrhnns - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns - login: waynerv - count: 14 + count: 15 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 url: https://github.com/waynerv - login: haizaar @@ -114,7 +118,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar - login: frankie567 - count: 11 + count: 12 avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=72adf1cb1d29787305c99700d669561952cea0af&v=4 url: https://github.com/frankie567 - login: zamiramir @@ -138,26 +142,50 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4 url: https://github.com/stefanondisponibile last_month_active: +- login: Hultner + count: 15 + avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 + url: https://github.com/Hultner - login: Kludex count: 13 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex -- login: ycd - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 - url: https://github.com/ycd +- login: ArcLightSlavik + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 + url: https://github.com/ArcLightSlavik - login: raphaelauv - count: 6 + count: 4 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv -- login: frankie567 - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=72adf1cb1d29787305c99700d669561952cea0af&v=4 - url: https://github.com/frankie567 -- login: insomnes +- login: chbndrhnns count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 - url: https://github.com/insomnes + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns +- login: dstlny + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=ed9c60d8ab5b4fea71640cdbccf0f83bdd6c43cb&v=4 + url: https://github.com/dstlny +- login: Mause + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 + url: https://github.com/Mause +- login: waynerv + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 + url: https://github.com/waynerv +- login: panla + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?v=4 + url: https://github.com/panla +- login: ricky-sb + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/10700079?v=4 + url: https://github.com/ricky-sb +- login: ycd + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 + url: https://github.com/ycd top_contributors: - login: waynerv count: 25 @@ -220,20 +248,20 @@ top_reviewers: count: 44 avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 url: https://github.com/tokusumi -- login: ycd - count: 39 - avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 - url: https://github.com/ycd - login: Laineyzhang55 - count: 34 + count: 42 avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4 url: https://github.com/Laineyzhang55 +- login: ycd + count: 40 + avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 + url: https://github.com/ycd - login: waynerv - count: 32 + count: 38 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 url: https://github.com/waynerv - login: AdrianDeAnda - count: 26 + count: 28 avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4 url: https://github.com/AdrianDeAnda - login: dmontagu @@ -252,6 +280,10 @@ top_reviewers: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4 url: https://github.com/SwftAlpc +- login: ArcLightSlavik + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 + url: https://github.com/ArcLightSlavik - login: pedabraham count: 15 avatarUrl: https://avatars.githubusercontent.com/u/16860088?u=abf922a7b920bf8fdb7867d8b43e091f1e796178&v=4 @@ -268,10 +300,6 @@ top_reviewers: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 url: https://github.com/RunningIkkyu -- login: ArcLightSlavik - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=6e53b1a2f340d77429d435babcec107c7cc50972&v=4 - url: https://github.com/ArcLightSlavik - login: hard-coders count: 12 avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 @@ -296,6 +324,10 @@ top_reviewers: count: 9 avatarUrl: https://avatars.githubusercontent.com/u/13096845?u=646eba44db720e37d0dbe8e98e77ab534ea78a20&v=4 url: https://github.com/PandaHun +- login: bezaca + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4 + url: https://github.com/bezaca - login: rjNemo count: 8 avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 @@ -316,14 +348,18 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv +- login: NastasiaSaby + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4 + url: https://github.com/NastasiaSaby +- login: Smlep + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 + url: https://github.com/Smlep - login: jovicon count: 6 avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 url: https://github.com/jovicon -- login: NastasiaSaby - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4 - url: https://github.com/NastasiaSaby - login: nimctl count: 5 avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4 @@ -340,6 +376,10 @@ top_reviewers: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/63564282?u=0078826509dbecb2fdb543f4e881c9cd06157893&v=4 url: https://github.com/SnkSynthesis +- login: anthonycepeda + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 + url: https://github.com/anthonycepeda - login: euri10 count: 4 avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4 @@ -370,15 +410,12 @@ sponsors: - login: grillazz avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=16d7d0ffa5dfb99f8834f8f76d90e138ba09b94a&v=4 url: https://github.com/grillazz -- login: CarlosDomingues - avatarUrl: https://avatars.githubusercontent.com/u/11181378?u=4c15832fa030a5f3fd024ca4912093b4b59a40bd&v=4 - url: https://github.com/CarlosDomingues - login: jmaralc avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4 url: https://github.com/jmaralc -- login: lucone83 - avatarUrl: https://avatars.githubusercontent.com/u/2812607?u=49c0c4454d4c98eacdcac0e33c1d83dc6fe5a37f&v=4 - url: https://github.com/lucone83 +- login: psgandalf + avatarUrl: https://avatars.githubusercontent.com/u/8134158?v=4 + url: https://github.com/psgandalf - login: samuelcolvin avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4 url: https://github.com/samuelcolvin @@ -395,7 +432,7 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 url: https://github.com/falkben - login: Mazyod - avatarUrl: https://avatars.githubusercontent.com/u/860511?u=a76c978bdf91c2b332ab8769935fa415d0a8091b&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/860511?v=4 url: https://github.com/Mazyod - login: ltieman avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4 @@ -430,15 +467,15 @@ sponsors: - login: dudil avatarUrl: https://avatars.githubusercontent.com/u/4785835?u=58b7ea39123e0507f3b2996448a27256b16fd697&v=4 url: https://github.com/dudil -- login: p141592 - avatarUrl: https://avatars.githubusercontent.com/u/5256328?u=07bc6374282ab3d08511afebaa5d511987d034f1&v=4 - url: https://github.com/p141592 - login: ennui93 avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4 url: https://github.com/ennui93 - login: sco1 avatarUrl: https://avatars.githubusercontent.com/u/5323929?u=2b8434060d0c9d93de80a2a945baed94a412c31e&v=4 url: https://github.com/sco1 +- login: MacroPower + avatarUrl: https://avatars.githubusercontent.com/u/5648814?u=b2730000c9f9a471282b9849d2cc85711d7973d4&v=4 + url: https://github.com/MacroPower - login: ginomempin avatarUrl: https://avatars.githubusercontent.com/u/6091865?v=4 url: https://github.com/ginomempin @@ -508,6 +545,9 @@ sponsors: - login: daddycocoaman avatarUrl: https://avatars.githubusercontent.com/u/21189155?u=756f6a17c71c538b11470f70839baacab43807ef&v=4 url: https://github.com/daddycocoaman +- login: Filimoa + avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4 + url: https://github.com/Filimoa - login: raminsj13 avatarUrl: https://avatars.githubusercontent.com/u/24259406?u=d51f2a526312ebba150a06936ed187ca0727d329&v=4 url: https://github.com/raminsj13 @@ -520,9 +560,6 @@ sponsors: - login: orihomie avatarUrl: https://avatars.githubusercontent.com/u/29889683?u=6bc2135a52fcb3a49e69e7d50190796618185fda&v=4 url: https://github.com/orihomie -- login: Huffon - avatarUrl: https://avatars.githubusercontent.com/u/31345506?u=c41bdf60facd004ec6364bf718ce16f8da2b884f&v=4 - url: https://github.com/Huffon - login: SaltyCoco avatarUrl: https://avatars.githubusercontent.com/u/31451104?u=6ee4e17c07d21b7054f54a12fa9cc377a1b24ff9&v=4 url: https://github.com/SaltyCoco @@ -586,9 +623,15 @@ sponsors: - login: lukin0110 avatarUrl: https://avatars.githubusercontent.com/u/992275?u=d20b7e18b213ae7004585b382eccb542db5ffe48&v=4 url: https://github.com/lukin0110 +- login: Pytlicek + avatarUrl: https://avatars.githubusercontent.com/u/1430522?v=4 + url: https://github.com/Pytlicek - login: okken avatarUrl: https://avatars.githubusercontent.com/u/1568356?u=0a991a21bdc62e2bea9ad311652f2c45f453dc84&v=4 url: https://github.com/okken +- login: leogregianin + avatarUrl: https://avatars.githubusercontent.com/u/1684053?u=94ddd387601bd1805034dbe83e6eba0491c15323&v=4 + url: https://github.com/leogregianin - login: cbonoz avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4 url: https://github.com/cbonoz @@ -602,7 +645,7 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4 url: https://github.com/igorcorrea - login: zsinx6 - avatarUrl: https://avatars.githubusercontent.com/u/3532625?v=4 + avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4 url: https://github.com/zsinx6 - login: pawamoy avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4 @@ -610,6 +653,12 @@ sponsors: - login: spyker77 avatarUrl: https://avatars.githubusercontent.com/u/4953435?u=568baae6469628e020fe0bab16e395b7ae10c7d3&v=4 url: https://github.com/spyker77 +- login: serfer2 + avatarUrl: https://avatars.githubusercontent.com/u/5196592?u=e8798d87120952ed41876778f0cc8a1ddb47f901&v=4 + url: https://github.com/serfer2 +- login: JonasKs + avatarUrl: https://avatars.githubusercontent.com/u/5310116?u=98a049f3e1491bffb91e1feb7e93def6881a9389&v=4 + url: https://github.com/JonasKs - login: iwpnd avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=b2286006daafff5f991557344fee20b5da59639a&v=4 url: https://github.com/iwpnd @@ -631,24 +680,30 @@ sponsors: - login: hard-coders avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 url: https://github.com/hard-coders +- login: pheanex + avatarUrl: https://avatars.githubusercontent.com/u/10408624?u=5b6bab6ee174aa6e991333e06eb29f628741013d&v=4 + url: https://github.com/pheanex +- login: wotori + avatarUrl: https://avatars.githubusercontent.com/u/10486621?u=0044c295b91694b8c9bccc0a805681f794250f7b&v=4 + url: https://github.com/wotori - login: JimFawkes avatarUrl: https://avatars.githubusercontent.com/u/12075115?u=dc58ecfd064d72887c34bf500ddfd52592509acd&v=4 url: https://github.com/JimFawkes -- login: logan-connolly - avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4 - url: https://github.com/logan-connolly - login: sebastianmarines - avatarUrl: https://avatars.githubusercontent.com/u/18373185?u=e0be7c230456a2bdc0825e3d6541ea8966e22028&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/18373185?u=3f74dbd238bd3ab40179323c5906bb162da5b5a7&v=4 url: https://github.com/sebastianmarines -- login: Filimoa - avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4 - url: https://github.com/Filimoa +- login: iPr0ger + avatarUrl: https://avatars.githubusercontent.com/u/19322290?v=4 + url: https://github.com/iPr0ger - login: ghandic avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 url: https://github.com/ghandic - login: MoronVV avatarUrl: https://avatars.githubusercontent.com/u/24293616?v=4 url: https://github.com/MoronVV +- login: AngusWG + avatarUrl: https://avatars.githubusercontent.com/u/26385612?u=f4d4c8bd2097cdd58eb9e385932b83c78777f3c0&v=4 + url: https://github.com/AngusWG - login: mertguvencli avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4 url: https://github.com/mertguvencli @@ -658,6 +713,12 @@ sponsors: - login: leynier avatarUrl: https://avatars.githubusercontent.com/u/36774373?u=60eee7ab14aada5aab8af6fbd11d14732750a7ab&v=4 url: https://github.com/leynier +- login: askurihin + avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4 + url: https://github.com/askurihin +- login: berrysauce + avatarUrl: https://avatars.githubusercontent.com/u/38889179?u=758ed15a5be8bbd03855f5a74f42c19f7946ee32&v=4 + url: https://github.com/berrysauce - login: JitPackJoyride avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=9638bfeacfa5940358188f8205ce662bba022b53&v=4 url: https://github.com/JitPackJoyride @@ -667,9 +728,18 @@ sponsors: - login: ilias-ant avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=064bf3a60fcb3c445ab038386321098920b3f4e4&v=4 url: https://github.com/ilias-ant +- login: kbhatiya999 + avatarUrl: https://avatars.githubusercontent.com/u/47816034?v=4 + url: https://github.com/kbhatiya999 - login: akanz1 avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4 url: https://github.com/akanz1 +- login: rychardvale + avatarUrl: https://avatars.githubusercontent.com/u/54805553?u=3d20ab05301d05f9ac3500fb79a2bfee3842b753&v=4 + url: https://github.com/rychardvale - login: athemeart avatarUrl: https://avatars.githubusercontent.com/u/61623624?v=4 url: https://github.com/athemeart +- login: Rhythmicc + avatarUrl: https://avatars.githubusercontent.com/u/29839231?u=2100781089a259707c475c4547bd7995b0fc18ee&v=4 + url: https://github.com/Rhythmicc From 662fc81544c445ce9b62e11114ac360d25ae927d Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:27:36 +0000 Subject: [PATCH 036/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1120adf96..20ed8683c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#3319](https://github.com/tiangolo/fastapi/pull/3319) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🌐 Add Chinese translation for Tutorial - Body - Updates. PR [#3237](https://github.com/tiangolo/fastapi/pull/3237) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for FastAPI People. PR [#3112](https://github.com/tiangolo/fastapi/pull/3112) by [@hareru](https://github.com/hareru). * 🌐 Add French translation for Project Generation. PR [#3197](https://github.com/tiangolo/fastapi/pull/3197) by [@Smlep](https://github.com/Smlep). From 811c3f873f18f19a10f9a2b9ec0c9fd2aa17a103 Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Fri, 2 Jul 2021 22:35:58 +0800 Subject: [PATCH 037/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20Tutorial=20-=20Form=20-=20Data=20(#3248)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/zh/docs/tutorial/request-forms.md | 63 ++++++++++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 64 insertions(+) create mode 100644 docs/zh/docs/tutorial/request-forms.md diff --git a/docs/zh/docs/tutorial/request-forms.md b/docs/zh/docs/tutorial/request-forms.md new file mode 100644 index 000000000..0840c9274 --- /dev/null +++ b/docs/zh/docs/tutorial/request-forms.md @@ -0,0 +1,63 @@ +# 表单数据 + +接收的不是 JSON,而是表单字段时,要使用 `Form`。 + +!!! info "说明" + + 要使用表单,需预先安装 `python-multipart`。 + + 例如,`pip install python-multipart`。 + +## 导入 `Form` + +从 `fastapi` 导入 `Form`: + +```Python hl_lines="1" +{!../../../docs_src/request_forms/tutorial001.py!} +``` + +## 定义 `Form` 参数 + +创建表单(`Form`)参数的方式与 `Body` 和 `Query` 一样: + +```Python hl_lines="7" +{!../../../docs_src/request_forms/tutorial001.py!} +``` + +例如,OAuth2 规范的 "密码流" 模式规定要通过表单字段发送 `username` 和 `password`。 + +该规范要求字段必须命名为 `username` 和 `password`,并通过表单字段发送,不能用 JSON。 + +使用 `Form` 可以声明与 `Body` (及 `Query`、`Path`、`Cookie`)相同的元数据和验证。 + +!!! info "说明" + + `Form` 是直接继承自 `Body` 的类。 + +!!! tip "提示" + + 声明表单体要显式使用 `Form` ,否则,FastAPI 会把该参数当作查询参数或请求体(JSON)参数。 + +## 关于 "表单字段" + +与 JSON 不同,HTML 表单(`
`)向服务器发送数据通常使用「特殊」的编码。 + +**FastAPI** 要确保从正确的位置读取数据,而不是读取 JSON。 + +!!! note "技术细节" + + 表单数据的「媒体类型」编码一般为 `application/x-www-form-urlencoded`。 + + 但包含文件的表单编码为 `multipart/form-data`。文件处理详见下节。 + + 编码和表单字段详见 MDN Web 文档的 POST小节。 + +!!! warning "警告" + + 可在一个*路径操作*中声明多个 `Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。因为此时请求体的编码是 `application/x-www-form-urlencoded`,不是 `application/json`。 + + 这不是 **FastAPI** 的问题,而是 HTTP 协议的规定。 + +## 小结 + +本节介绍了如何使用 `Form` 声明表单数据输入参数。 \ No newline at end of file diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index f63f341f0..1bceab212 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -73,6 +73,7 @@ nav: - tutorial/schema-extra-example.md - tutorial/extra-data-types.md - tutorial/cookie-params.md + - tutorial/request-forms.md - tutorial/request-files.md - tutorial/body-updates.md - 安全性: From e5d0b97dee8737d0ca3428c4ec03cd801d251685 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:36:34 +0000 Subject: [PATCH 038/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 20ed8683c..7f400fb56 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for Tutorial - Form - Data. PR [#3248](https://github.com/tiangolo/fastapi/pull/3248) by [@jaystone776](https://github.com/jaystone776). * 👥 Update FastAPI People. PR [#3319](https://github.com/tiangolo/fastapi/pull/3319) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🌐 Add Chinese translation for Tutorial - Body - Updates. PR [#3237](https://github.com/tiangolo/fastapi/pull/3237) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for FastAPI People. PR [#3112](https://github.com/tiangolo/fastapi/pull/3112) by [@hareru](https://github.com/hareru). From 0a84d48a8232243ca9ca23fefb16e603fe35c9a3 Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Fri, 2 Jul 2021 22:43:28 +0800 Subject: [PATCH 039/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20Tutorial=20-=20Handling=20-=20Errors=20(#3299)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/zh/docs/tutorial/handling-errors.md | 289 +++++++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 290 insertions(+) create mode 100644 docs/zh/docs/tutorial/handling-errors.md diff --git a/docs/zh/docs/tutorial/handling-errors.md b/docs/zh/docs/tutorial/handling-errors.md new file mode 100644 index 000000000..1126b7add --- /dev/null +++ b/docs/zh/docs/tutorial/handling-errors.md @@ -0,0 +1,289 @@ +# 处理错误 + +某些情况下,需要向客户端返回错误提示。 + +这里所谓的客户端包括前端浏览器、其他应用程序、物联网设备等。 + +需要向客户端返回错误提示的场景主要如下: + +- 客户端没有执行操作的权限 +- 客户端没有访问资源的权限 +- 客户端要访问的项目不存在 +- 等等 ... + +遇到这些情况时,通常要返回 **4XX**(400 至 499)**HTTP 状态码**。 + +**4XX** 状态码与表示请求成功的 **2XX**(200 至 299) HTTP 状态码类似。 + +只不过,**4XX** 状态码表示客户端发生的错误。 + +大家都知道**「404 Not Found」**错误,还有调侃这个错误的笑话吧? + +## 使用 `HTTPException` + +向客户端返回 HTTP 错误响应,可以使用 `HTTPException`。 + +### 导入 `HTTPException` + +```Python hl_lines="1" +{!../../../docs_src/handling_errors/tutorial001.py!} + +``` + +### 触发 `HTTPException` + +`HTTPException` 是额外包含了和 API 有关数据的常规 Python 异常。 + +因为是 Python 异常,所以不能 `return`,只能 `raise`。 + +如在调用*路径操作函数*里的工具函数时,触发了 `HTTPException`,FastAPI 就不再继续执行*路径操作函数*中的后续代码,而是立即终止请求,并把 `HTTPException` 的 HTTP 错误发送至客户端。 + +在介绍依赖项与安全的章节中,您可以了解更多用 `raise` 异常代替 `return` 值的优势。 + +本例中,客户端用 `ID` 请求的 `item` 不存在时,触发状态码为 `404` 的异常: + +```Python hl_lines="11" +{!../../../docs_src/handling_errors/tutorial001.py!} + +``` + +### 响应结果 + +请求为 `http://example.com/items/foo`(`item_id` 为 `「foo」`)时,客户端会接收到 HTTP 状态码 - 200 及如下 JSON 响应结果: + +```JSON +{ + "item": "The Foo Wrestlers" +} + +``` + +但如果客户端请求 `http://example.com/items/bar`(`item_id` `「bar」` 不存在时),则会接收到 HTTP 状态码 - 404(「未找到」错误)及如下 JSON 响应结果: + +```JSON +{ + "detail": "Item not found" +} + +``` + +!!! tip "提示" + + 触发 `HTTPException` 时,可以用参数 `detail` 传递任何能转换为 JSON 的值,不仅限于 `str`。 + + 还支持传递 `dict`、`list` 等数据结构。 + + **FastAPI** 能自动处理这些数据,并将之转换为 JSON。 + + +## 添加自定义响应头 + +有些场景下要为 HTTP 错误添加自定义响应头。例如,出于某些方面的安全需要。 + +一般情况下可能不会需要在代码中直接使用响应头。 + +但对于某些高级应用场景,还是需要添加自定义响应头: + +```Python hl_lines="14" +{!../../../docs_src/handling_errors/tutorial002.py!} + +``` + +## 安装自定义异常处理器 + +添加自定义处理器,要使用 [Starlette 的异常工具](https://www.starlette.io/exceptions/)。 + +假设要触发的自定义异常叫作 `UnicornException`。 + +且需要 FastAPI 实现全局处理该异常。 + +此时,可以用 `@app.exception_handler()` 添加自定义异常控制器: + +```Python hl_lines="5-7 13-18 24" +{!../../../docs_src/handling_errors/tutorial003.py!} + +``` + +请求 `/unicorns/yolo` 时,路径操作会触发 `UnicornException`。 + +但该异常将会被 `unicorn_exception_handler` 处理。 + +接收到的错误信息清晰明了,HTTP 状态码为 `418`,JSON 内容如下: + +```JSON +{"message": "Oops! yolo did something. There goes a rainbow..."} + +``` + +!!! note "技术细节" + + `from starlette.requests import Request` 和 `from starlette.responses import JSONResponse` 也可以用于导入 `Request` 和 `JSONResponse`。 + + **FastAPI** 提供了与 `starlette.responses` 相同的 `fastapi.responses` 作为快捷方式,但大部分响应操作都可以直接从 Starlette 导入。同理,`Request` 也是如此。 + + +## 覆盖默认异常处理器 + +**FastAPI** 自带了一些默认异常处理器。 + +触发 `HTTPException` 或请求无效数据时,这些处理器返回默认的 JSON 响应结果。 + +不过,也可以使用自定义处理器覆盖默认异常处理器。 + +### 覆盖请求验证异常 + +请求中包含无效数据时,**FastAPI** 内部会触发 `RequestValidationError`。 + +该异常也内置了默认异常处理器。 + +覆盖默认异常处理器时需要导入 `RequestValidationError`,并用 `@app.excption_handler(RequestValidationError)` 装饰异常处理器。 + +这样,异常处理器就可以接收 `Request` 与异常。 + +```Python hl_lines="2 14-16" +{!../../../docs_src/handling_errors/tutorial004.py!} + +``` + +访问 `/items/foo`,可以看到以下内容替换了默认 JSON 错误信息: + +```JSON +{ + "detail": [ + { + "loc": [ + "path", + "item_id" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ] +} + +``` + +以下是文本格式的错误信息: + +``` +1 validation error +path -> item_id + value is not a valid integer (type=type_error.integer) + +``` + +### `RequestValidationError` vs `ValidationError` + +!!! warning "警告" + + 如果您觉得现在还用不到以下技术细节,可以先跳过下面的内容。 + + +`RequestValidationError` 是 Pydantic 的 `ValidationError` 的子类。 + +**FastAPI** 调用的就是 `RequestValidationError` 类,因此,如果在 `response_model` 中使用 Pydantic 模型,且数据有错误时,在日志中就会看到这个错误。 + +但客户端或用户看不到这个错误。反之,客户端接收到的是 HTTP 状态码为 `500` 的「内部服务器错误」。 + +这是因为在*响应*或代码(不是在客户端的请求里)中出现的 Pydantic `ValidationError` 是代码的 bug。 + +修复错误时,客户端或用户不能访问错误的内部信息,否则会造成安全隐患。 + +### 覆盖 `HTTPException` 错误处理器 + +同理,也可以覆盖 `HTTPException` 处理器。 + +例如,只为错误返回纯文本响应,而不是返回 JSON 格式的内容: + +```Python hl_lines="3-4 9-11 22" +{!../../../docs_src/handling_errors/tutorial004.py!} + +``` + +!!! note "技术细节" + + 还可以使用 `from starlette.responses import PlainTextResponse`。 + + **FastAPI** 提供了与 `starlette.responses` 相同的 `fastapi.responses` 作为快捷方式,但大部分响应都可以直接从 Starlette 导入。 + + +### 使用 `RequestValidationError` 的请求体 + +`RequestValidationError` 包含其接收到的无效数据请求的 `body` 。 + +开发时,可以用这个请求体生成日志、调试错误,并返回给用户。 + +```Python hl_lines="14" +{!../../../docs_src/handling_errors/tutorial005.py!} + +``` + +现在试着发送一个无效的 `item`,例如: + +```JSON +{ + "title": "towel", + "size": "XL" +} + +``` + +收到的响应包含 `body` 信息,并说明数据是无效的: + +```JSON hl_lines="12-15" +{ + "detail": [ + { + "loc": [ + "body", + "size" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ], + "body": { + "title": "towel", + "size": "XL" + } +} + +``` + +### FastAPI `HTTPException` vs Starlette `HTTPException` + +**FastAPI** 也提供了自有的 `HTTPException`。 + +**FastAPI** 的 `HTTPException` 继承自 Starlette 的 `HTTPException` 错误类。 + +它们之间的唯一区别是,**FastAPI** 的 `HTTPException` 可以在响应中添加响应头。 + +OAuth 2.0 等安全工具需要在内部调用这些响应头。 + +因此你可以继续像平常一样在代码中触发 **FastAPI** 的 `HTTPException` 。 + +但注册异常处理器时,应该注册到来自 Starlette 的 `HTTPException`。 + +这样做是为了,当 Starlette 的内部代码、扩展或插件触发 Starlette `HTTPException` 时,处理程序能够捕获、并处理此异常。 + +注意,本例代码中同时使用了这两个 `HTTPException`,此时,要把 Starlette 的 `HTTPException` 命名为 `StarletteHTTPException`: + +```Python +from starlette.exceptions import HTTPException as StarletteHTTPException + +``` + +### 复用 **FastAPI** 异常处理器 + +FastAPI 支持先对异常进行某些处理,然后再使用 **FastAPI** 中处理该异常的默认异常处理器。 + +从 `fastapi.exception_handlers` 中导入要复用的默认异常处理器: + +```Python hl_lines="2-5 15 21" +{!../../../docs_src/handling_errors/tutorial006.py!} + +``` + +虽然,本例只是输出了夸大其词的错误信息。 + +但也足以说明,可以在处理异常之后再复用默认的异常处理器。 \ No newline at end of file diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 1bceab212..ed1142214 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -75,6 +75,7 @@ nav: - tutorial/cookie-params.md - tutorial/request-forms.md - tutorial/request-files.md + - tutorial/handling-errors.md - tutorial/body-updates.md - 安全性: - tutorial/security/index.md From dd7bbae837d3f5a620c07c0b712cb4310b90e727 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:44:04 +0000 Subject: [PATCH 040/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7f400fb56..6d1268f7e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for Tutorial - Handling - Errors. PR [#3299](https://github.com/tiangolo/fastapi/pull/3299) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for Tutorial - Form - Data. PR [#3248](https://github.com/tiangolo/fastapi/pull/3248) by [@jaystone776](https://github.com/jaystone776). * 👥 Update FastAPI People. PR [#3319](https://github.com/tiangolo/fastapi/pull/3319) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🌐 Add Chinese translation for Tutorial - Body - Updates. PR [#3237](https://github.com/tiangolo/fastapi/pull/3237) by [@jaystone776](https://github.com/jaystone776). From c00c2d1ecf3133a284ee55994633c4b341989bcb Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Fri, 2 Jul 2021 22:54:22 +0800 Subject: [PATCH 041/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20Tutorial=20-=20Request=20-=20Forms=20-=20and=20-=20?= =?UTF-8?q?Files=20(#3249)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../docs/tutorial/request-forms-and-files.md | 38 +++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 39 insertions(+) create mode 100644 docs/zh/docs/tutorial/request-forms-and-files.md diff --git a/docs/zh/docs/tutorial/request-forms-and-files.md b/docs/zh/docs/tutorial/request-forms-and-files.md new file mode 100644 index 000000000..a27ba93d5 --- /dev/null +++ b/docs/zh/docs/tutorial/request-forms-and-files.md @@ -0,0 +1,38 @@ +# 请求表单与文件 + +FastAPI 支持同时使用 `File` 和 `Form` 定义文件和表单字段。 + +!!! info "说明" + + 接收上传文件或表单数据,要预先安装 `python-multipart`。 + + 例如,`pip install python-multipart`。 + +## 导入 `File` 与 `Form` + +```Python hl_lines="1" +{!../../../docs_src/request_forms_and_files/tutorial001.py!} +``` + +## 定义 `File` 与 `Form` 参数 + +创建文件和表单参数的方式与 `Body` 和 `Query` 一样: + +```Python hl_lines="8" +{!../../../docs_src/request_forms_and_files/tutorial001.py!} +``` + +文件和表单字段作为表单数据上传与接收。 + +声明文件可以使用 `bytes` 或 `UploadFile` 。 + +!!! warning "警告" + + 可在一个*路径操作*中声明多个 `File` 与 `Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。因为此时请求体的编码为 `multipart/form-data`,不是 `application/json`。 + + 这不是 **FastAPI** 的问题,而是 HTTP 协议的规定。 + +## 小结 + +在同一个请求中接收数据和文件时,应同时使用 `File` 和 `Form`。 + diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index ed1142214..85e470e59 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -75,6 +75,7 @@ nav: - tutorial/cookie-params.md - tutorial/request-forms.md - tutorial/request-files.md + - tutorial/request-forms-and-files.md - tutorial/handling-errors.md - tutorial/body-updates.md - 安全性: From a9f2a25febd1edcb232646d0af51d102c60af443 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 14:54:56 +0000 Subject: [PATCH 042/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6d1268f7e..461c917d1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for Tutorial - Request - Forms - and - Files. PR [#3249](https://github.com/tiangolo/fastapi/pull/3249) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for Tutorial - Handling - Errors. PR [#3299](https://github.com/tiangolo/fastapi/pull/3299) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for Tutorial - Form - Data. PR [#3248](https://github.com/tiangolo/fastapi/pull/3248) by [@jaystone776](https://github.com/jaystone776). * 👥 Update FastAPI People. PR [#3319](https://github.com/tiangolo/fastapi/pull/3319) by [@github-actions[bot]](https://github.com/apps/github-actions). From 9c5b000956940f74847d9efda75dd9fb4cce4033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Victor=20Ribeiro=20Silva?= Date: Fri, 2 Jul 2021 12:00:11 -0300 Subject: [PATCH 043/814] =?UTF-8?q?=F0=9F=8C=90=20Portuguese=20translation?= =?UTF-8?q?=20of=20Tutorial=20-=20Body=20-=20Fields=20(#3420)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/body-fields.md | 48 ++++++++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 49 insertions(+) create mode 100644 docs/pt/docs/tutorial/body-fields.md diff --git a/docs/pt/docs/tutorial/body-fields.md b/docs/pt/docs/tutorial/body-fields.md new file mode 100644 index 000000000..8f3313ae9 --- /dev/null +++ b/docs/pt/docs/tutorial/body-fields.md @@ -0,0 +1,48 @@ +# Corpo - Campos + +Da mesma forma que você pode declarar validações adicionais e metadados nos parâmetros de *funções de operações de rota* com `Query`, `Path` e `Body`, você pode declarar validações e metadados dentro de modelos do Pydantic usando `Field` do Pydantic. + +## Importe `Field` + +Primeiro, você tem que importá-lo: + +```Python hl_lines="4" +{!../../../docs_src/body_fields/tutorial001.py!} +``` + +!!! warning "Aviso" + Note que `Field` é importado diretamente do `pydantic`, não do `fastapi` como todo o resto (`Query`, `Path`, `Body`, etc). + +## Declare atributos do modelo + +Você pode então utilizar `Field` com atributos do modelo: + +```Python hl_lines="11-14" +{!../../../docs_src/body_fields/tutorial001.py!} +``` + +`Field` funciona da mesma forma que `Query`, `Path` e `Body`, ele possui todos os mesmos parâmetros, etc. + +!!! note "Detalhes técnicos" + Na realidade, `Query`, `Path` e outros que você verá em seguida, criam objetos de subclasses de uma classe `Param` comum, que é ela mesma uma subclasse da classe `FieldInfo` do Pydantic. + + E `Field` do Pydantic retorna uma instância de `FieldInfo` também. + + `Body` também retorna objetos de uma subclasse de `FieldInfo` diretamente. E tem outras que você verá mais tarde que são subclasses da classe `Body`. + + Lembre-se que quando você importa `Query`, `Path`, e outros de `fastapi`, esse são na realidade funções que retornam classes especiais. + +!!! tip "Dica" + Note como cada atributo do modelo com um tipo, valor padrão e `Field` possuem a mesma estrutura que parâmetros de *funções de operações de rota*, com `Field` ao invés de `Path`, `Query` e `Body`. + +## Adicione informações extras + +Você pode declarar informação extra em `Field`, `Query`, `Body`, etc. E isso será incluído no JSON Schema gerado. + +Você irá aprender mais sobre adicionar informações extras posteriormente nessa documentação, quando estiver aprendendo a declarar exemplos. + +## Recapitulando + +Você pode usar `Field` do Pydantic para declarar validações extras e metadados para atributos do modelo. + +Você também pode usar os argumentos de palavras-chave extras para passar metadados do JSON Schema adicionais. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 230012d3b..6102a859d 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -55,6 +55,7 @@ nav: - Tutorial - Guia de Usuário: - tutorial/index.md - tutorial/first-steps.md + - tutorial/body-fields.md - alternatives.md - history-design-future.md - external-links.md From bd230fe4739d1c276d825879f5737fa2f8a663b7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 15:00:53 +0000 Subject: [PATCH 044/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 461c917d1..fba17035b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Portuguese translation of Tutorial - Body - Fields. PR [#3420](https://github.com/tiangolo/fastapi/pull/3420) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Add Chinese translation for Tutorial - Request - Forms - and - Files. PR [#3249](https://github.com/tiangolo/fastapi/pull/3249) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for Tutorial - Handling - Errors. PR [#3299](https://github.com/tiangolo/fastapi/pull/3299) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for Tutorial - Form - Data. PR [#3248](https://github.com/tiangolo/fastapi/pull/3248) by [@jaystone776](https://github.com/jaystone776). From 710a2f745cd972ca367ac17385443649c737e249 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 2 Jul 2021 17:17:49 +0200 Subject: [PATCH 045/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#3450)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions Co-authored-by: Sebastián Ramírez --- docs/en/data/people.yml | 215 +++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 104 deletions(-) diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index d1898a931..6356a5073 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,24 +1,24 @@ maintainers: - login: tiangolo answers: 1225 - prs: 230 + prs: 232 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=05f95ca7fdead36edd9c86be46b4ef6c3c71f876&v=4 url: https://github.com/tiangolo experts: +- login: Kludex + count: 267 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + url: https://github.com/Kludex - login: dmontagu count: 262 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu -- login: Kludex - count: 254 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 - url: https://github.com/Kludex - login: ycd - count: 214 + count: 216 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: Mause - count: 176 + count: 182 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause - login: euri10 @@ -30,21 +30,21 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 - login: ArcLightSlavik - count: 58 + count: 64 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik - login: falkben count: 56 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 url: https://github.com/falkben +- login: raphaelauv + count: 47 + avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 + url: https://github.com/raphaelauv - login: sm-Fifteen count: 46 avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 url: https://github.com/sm-Fifteen -- login: raphaelauv - count: 44 - avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 - url: https://github.com/raphaelauv - login: includeamin count: 38 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 @@ -77,6 +77,10 @@ experts: count: 24 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak +- login: chbndrhnns + count: 22 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: acnebs count: 22 avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=bfd127b3e6200f4d00afd714f0fc95c2512df19b&v=4 @@ -85,14 +89,14 @@ experts: count: 22 avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4 url: https://github.com/nsidnev +- login: frankie567 + count: 21 + avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=72adf1cb1d29787305c99700d669561952cea0af&v=4 + url: https://github.com/frankie567 - login: chris-allnutt count: 21 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 url: https://github.com/chris-allnutt -- login: chbndrhnns - count: 20 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns - login: retnikt count: 19 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 @@ -117,10 +121,10 @@ experts: count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar -- login: frankie567 - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=72adf1cb1d29787305c99700d669561952cea0af&v=4 - url: https://github.com/frankie567 +- login: acidjunk + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 + url: https://github.com/acidjunk - login: zamiramir count: 11 avatarUrl: https://avatars.githubusercontent.com/u/40475662?u=e58ef61034e8d0d6a312cc956fb09b9c3332b449&v=4 @@ -142,50 +146,38 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4 url: https://github.com/stefanondisponibile last_month_active: -- login: Hultner - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 - url: https://github.com/Hultner - login: Kludex - count: 13 + count: 12 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex -- login: ArcLightSlavik - count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 - url: https://github.com/ArcLightSlavik -- login: raphaelauv - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 - url: https://github.com/raphaelauv -- login: chbndrhnns - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns -- login: dstlny - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=ed9c60d8ab5b4fea71640cdbccf0f83bdd6c43cb&v=4 - url: https://github.com/dstlny +- login: frankie567 + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=72adf1cb1d29787305c99700d669561952cea0af&v=4 + url: https://github.com/frankie567 - login: Mause - count: 3 + count: 6 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause -- login: waynerv - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 - url: https://github.com/waynerv -- login: panla - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?v=4 - url: https://github.com/panla +- login: ArcLightSlavik + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 + url: https://github.com/ArcLightSlavik +- login: gyKa + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/1000842?v=4 + url: https://github.com/gyKa - login: ricky-sb count: 3 avatarUrl: https://avatars.githubusercontent.com/u/10700079?v=4 url: https://github.com/ricky-sb -- login: ycd +- login: captainCapitalism count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 - url: https://github.com/ycd + avatarUrl: https://avatars.githubusercontent.com/u/32553875?v=4 + url: https://github.com/captainCapitalism +- login: acidjunk + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 + url: https://github.com/acidjunk top_contributors: - login: waynerv count: 25 @@ -212,7 +204,7 @@ top_contributors: avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 url: https://github.com/RunningIkkyu - login: Serrones - count: 6 + count: 7 avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 url: https://github.com/Serrones - login: hard-coders @@ -239,9 +231,13 @@ top_contributors: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=5a44657c0544111ee3c132d9bb9951c2804f7969&v=4 url: https://github.com/komtaki +- login: Smlep + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 + url: https://github.com/Smlep top_reviewers: - login: Kludex - count: 75 + count: 80 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: tokusumi @@ -253,7 +249,7 @@ top_reviewers: avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4 url: https://github.com/Laineyzhang55 - login: ycd - count: 40 + count: 41 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: waynerv @@ -272,6 +268,14 @@ top_reviewers: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=5a44657c0544111ee3c132d9bb9951c2804f7969&v=4 url: https://github.com/komtaki +- login: ArcLightSlavik + count: 20 + avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 + url: https://github.com/ArcLightSlavik +- login: cassiobotaro + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 + url: https://github.com/cassiobotaro - login: yanever count: 16 avatarUrl: https://avatars.githubusercontent.com/u/21978760?v=4 @@ -280,10 +284,6 @@ top_reviewers: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4 url: https://github.com/SwftAlpc -- login: ArcLightSlavik - count: 16 - avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 - url: https://github.com/ArcLightSlavik - login: pedabraham count: 15 avatarUrl: https://avatars.githubusercontent.com/u/16860088?u=abf922a7b920bf8fdb7867d8b43e091f1e796178&v=4 @@ -292,10 +292,6 @@ top_reviewers: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4 url: https://github.com/delhi09 -- login: cassiobotaro - count: 14 - avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 - url: https://github.com/cassiobotaro - login: RunningIkkyu count: 12 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 @@ -328,6 +324,10 @@ top_reviewers: count: 9 avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4 url: https://github.com/bezaca +- login: lsglucas + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 + url: https://github.com/lsglucas - login: rjNemo count: 8 avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 @@ -360,14 +360,14 @@ top_reviewers: count: 6 avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 url: https://github.com/jovicon +- login: Mause + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 + url: https://github.com/Mause - login: nimctl count: 5 avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4 url: https://github.com/nimctl -- login: Mause - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 - url: https://github.com/Mause - login: juntatalor count: 5 avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4 @@ -396,6 +396,10 @@ top_reviewers: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/31370133?v=4 url: https://github.com/Zxilly +- login: Bluenix2 + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/38372706?u=c9d28aff15958d6ebf1971148bfb3154ff943c4f&v=4 + url: https://github.com/Bluenix2 sponsors_50: - login: johnadjei avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4 @@ -403,6 +407,9 @@ sponsors_50: - login: wdwinslow avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 url: https://github.com/wdwinslow +- login: bingwu-chime + avatarUrl: https://avatars.githubusercontent.com/u/67026650?u=603a6b345f25c20c6706a8a6c7f71ae688d649a5&v=4 + url: https://github.com/bingwu-chime sponsors: - login: kamalgill avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4 @@ -410,6 +417,9 @@ sponsors: - login: grillazz avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=16d7d0ffa5dfb99f8834f8f76d90e138ba09b94a&v=4 url: https://github.com/grillazz +- login: tizz98 + avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4 + url: https://github.com/tizz98 - login: jmaralc avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4 url: https://github.com/jmaralc @@ -431,6 +441,9 @@ sponsors: - login: falkben avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 url: https://github.com/falkben +- login: jqueguiner + avatarUrl: https://avatars.githubusercontent.com/u/690878?u=e4835b2a985a0f2d52018e4926cb5a58c26a62e8&v=4 + url: https://github.com/jqueguiner - login: Mazyod avatarUrl: https://avatars.githubusercontent.com/u/860511?v=4 url: https://github.com/Mazyod @@ -452,9 +465,9 @@ sponsors: - login: madisonmay avatarUrl: https://avatars.githubusercontent.com/u/2645393?u=f22b93c6ea345a4d26a90a3834dfc7f0789fcb63&v=4 url: https://github.com/madisonmay -- login: jorgecarleitao - avatarUrl: https://avatars.githubusercontent.com/u/2772607?u=6ba4aa5ded7b492043ba76f3f900e3b4cc102b57&v=4 - url: https://github.com/jorgecarleitao +- login: saivarunk + avatarUrl: https://avatars.githubusercontent.com/u/2976867?u=71f4385e781e9a9e871a52f2d4686f9a8d69ba2f&v=4 + url: https://github.com/saivarunk - login: andre1sk avatarUrl: https://avatars.githubusercontent.com/u/3148093?v=4 url: https://github.com/andre1sk @@ -479,6 +492,9 @@ sponsors: - login: ginomempin avatarUrl: https://avatars.githubusercontent.com/u/6091865?v=4 url: https://github.com/ginomempin +- login: iwpnd + avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=b2286006daafff5f991557344fee20b5da59639a&v=4 + url: https://github.com/iwpnd - login: s3ich4n avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=ba3025d698e1c986655e776ae383a3d60d9d578e&v=4 url: https://github.com/s3ich4n @@ -488,9 +504,6 @@ sponsors: - login: christippett avatarUrl: https://avatars.githubusercontent.com/u/7218120?u=434b9d29287d7de25772d94ddc74a9bd6d969284&v=4 url: https://github.com/christippett -- login: yukiyan - avatarUrl: https://avatars.githubusercontent.com/u/7304122?u=fadb64baf3934c708349bbea1142d260a6b6ce6b&v=4 - url: https://github.com/yukiyan - login: Kludex avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex @@ -503,18 +516,12 @@ sponsors: - login: cristeaadrian avatarUrl: https://avatars.githubusercontent.com/u/9112724?v=4 url: https://github.com/cristeaadrian -- login: opunsoars - avatarUrl: https://avatars.githubusercontent.com/u/9273060?u=97f5ecec274e159b22787ca2f466f13ab1797758&v=4 - url: https://github.com/opunsoars - login: otivvormes avatarUrl: https://avatars.githubusercontent.com/u/11317418?u=6de1edefb6afd0108c0ad2816bd6efc4464a9c44&v=4 url: https://github.com/otivvormes - login: iambobmae avatarUrl: https://avatars.githubusercontent.com/u/12390270?u=c9a35c2ee5092a9b4135ebb1f91b7f521c467031&v=4 url: https://github.com/iambobmae -- login: Cozmo25 - avatarUrl: https://avatars.githubusercontent.com/u/12619962?u=679dcd6785121e14f6254e9dd0961baf3b1fef5d&v=4 - url: https://github.com/Cozmo25 - login: ronaldnwilliams avatarUrl: https://avatars.githubusercontent.com/u/13632749?u=ac41a086d0728bf66a9d2bee9e5e377041ff44a4&v=4 url: https://github.com/ronaldnwilliams @@ -578,9 +585,6 @@ sponsors: - login: dudikbender avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4 url: https://github.com/dudikbender -- login: Brontomerus - avatarUrl: https://avatars.githubusercontent.com/u/61284158?u=4aee24daee1921daa722cde3fcb6701e3e37ea31&v=4 - url: https://github.com/Brontomerus - login: primer-io avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4 url: https://github.com/primer-io @@ -593,24 +597,24 @@ sponsors: - login: anthonycepeda avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 url: https://github.com/anthonycepeda -- login: pqhaa - avatarUrl: https://avatars.githubusercontent.com/u/81242906?u=a71c5869241fc14dea6e413fb4b84287fefed38e&v=4 - url: https://github.com/pqhaa -- login: saldistefano - avatarUrl: https://avatars.githubusercontent.com/u/82109221?v=4 - url: https://github.com/saldistefano - login: linux-china avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4 url: https://github.com/linux-china - login: jhb avatarUrl: https://avatars.githubusercontent.com/u/142217?v=4 url: https://github.com/jhb +- login: yourkin + avatarUrl: https://avatars.githubusercontent.com/u/178984?v=4 + url: https://github.com/yourkin - login: jmagnusson avatarUrl: https://avatars.githubusercontent.com/u/190835?v=4 url: https://github.com/jmagnusson - login: slafs avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4 url: https://github.com/slafs +- login: adamghill + avatarUrl: https://avatars.githubusercontent.com/u/317045?u=f1349d5ffe84a19f324e204777859fbf69ddf633&v=4 + url: https://github.com/adamghill - login: eteq avatarUrl: https://avatars.githubusercontent.com/u/346587?v=4 url: https://github.com/eteq @@ -620,11 +624,11 @@ sponsors: - login: hongqn avatarUrl: https://avatars.githubusercontent.com/u/405587?u=470b4c04832e45141fd5264d3354845cc9fc6466&v=4 url: https://github.com/hongqn -- login: lukin0110 - avatarUrl: https://avatars.githubusercontent.com/u/992275?u=d20b7e18b213ae7004585b382eccb542db5ffe48&v=4 - url: https://github.com/lukin0110 +- login: rinckd + avatarUrl: https://avatars.githubusercontent.com/u/546002?u=1fcc7e664dc86524a0af6837a0c222829c3fd4e5&v=4 + url: https://github.com/rinckd - login: Pytlicek - avatarUrl: https://avatars.githubusercontent.com/u/1430522?v=4 + avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=169dba3bfbc04ed214a914640ff435969f19ddb3&v=4 url: https://github.com/Pytlicek - login: okken avatarUrl: https://avatars.githubusercontent.com/u/1568356?u=0a991a21bdc62e2bea9ad311652f2c45f453dc84&v=4 @@ -635,6 +639,9 @@ sponsors: - login: cbonoz avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4 url: https://github.com/cbonoz +- login: rglsk + avatarUrl: https://avatars.githubusercontent.com/u/2768101?u=e349c88673f2155fe021331377c656a9d74bcc25&v=4 + url: https://github.com/rglsk - login: Atem18 avatarUrl: https://avatars.githubusercontent.com/u/2875254?v=4 url: https://github.com/Atem18 @@ -659,9 +666,6 @@ sponsors: - login: JonasKs avatarUrl: https://avatars.githubusercontent.com/u/5310116?u=98a049f3e1491bffb91e1feb7e93def6881a9389&v=4 url: https://github.com/JonasKs -- login: iwpnd - avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=b2286006daafff5f991557344fee20b5da59639a&v=4 - url: https://github.com/iwpnd - login: holec avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4 url: https://github.com/holec @@ -680,6 +684,9 @@ sponsors: - login: hard-coders avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 url: https://github.com/hard-coders +- login: satwikkansal + avatarUrl: https://avatars.githubusercontent.com/u/10217535?u=b12d6ef74ea297de9e46da6933b1a5b7ba9e6a61&v=4 + url: https://github.com/satwikkansal - login: pheanex avatarUrl: https://avatars.githubusercontent.com/u/10408624?u=5b6bab6ee174aa6e991333e06eb29f628741013d&v=4 url: https://github.com/pheanex @@ -689,12 +696,15 @@ sponsors: - login: JimFawkes avatarUrl: https://avatars.githubusercontent.com/u/12075115?u=dc58ecfd064d72887c34bf500ddfd52592509acd&v=4 url: https://github.com/JimFawkes -- login: sebastianmarines - avatarUrl: https://avatars.githubusercontent.com/u/18373185?u=3f74dbd238bd3ab40179323c5906bb162da5b5a7&v=4 - url: https://github.com/sebastianmarines +- login: logan-connolly + avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4 + url: https://github.com/logan-connolly - login: iPr0ger avatarUrl: https://avatars.githubusercontent.com/u/19322290?v=4 url: https://github.com/iPr0ger +- login: sadikkuzu + avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4 + url: https://github.com/sadikkuzu - login: ghandic avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 url: https://github.com/ghandic @@ -710,9 +720,6 @@ sponsors: - login: rgreen32 avatarUrl: https://avatars.githubusercontent.com/u/35779241?u=c9d64ad1ab364b6a1ec8e3d859da9ca802d681d8&v=4 url: https://github.com/rgreen32 -- login: leynier - avatarUrl: https://avatars.githubusercontent.com/u/36774373?u=60eee7ab14aada5aab8af6fbd11d14732750a7ab&v=4 - url: https://github.com/leynier - login: askurihin avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4 url: https://github.com/askurihin @@ -723,10 +730,10 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=9638bfeacfa5940358188f8205ce662bba022b53&v=4 url: https://github.com/JitPackJoyride - login: es3n1n - avatarUrl: https://avatars.githubusercontent.com/u/40367813?u=f562f0f93b108a923be6aba1ec041128286c3c50&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/40367813?u=e881a3880f1e342d19a1ea7c8e1b6d76c52dc294&v=4 url: https://github.com/es3n1n - login: ilias-ant - avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=064bf3a60fcb3c445ab038386321098920b3f4e4&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4 url: https://github.com/ilias-ant - login: kbhatiya999 avatarUrl: https://avatars.githubusercontent.com/u/47816034?v=4 From f78464451073b3f72b65495b2b11ef6ddd869ac4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Jul 2021 15:18:24 +0000 Subject: [PATCH 046/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fba17035b..32df4ed0c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#3450](https://github.com/tiangolo/fastapi/pull/3450) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🌐 Portuguese translation of Tutorial - Body - Fields. PR [#3420](https://github.com/tiangolo/fastapi/pull/3420) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Add Chinese translation for Tutorial - Request - Forms - and - Files. PR [#3249](https://github.com/tiangolo/fastapi/pull/3249) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for Tutorial - Handling - Errors. PR [#3299](https://github.com/tiangolo/fastapi/pull/3299) by [@jaystone776](https://github.com/jaystone776). From 8a1f0aa3b63fafc493ca05b5effbe7557706ddf0 Mon Sep 17 00:00:00 2001 From: Camila Gutierrez Date: Sat, 3 Jul 2021 16:13:28 +0200 Subject: [PATCH 047/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Spanish=20translat?= =?UTF-8?q?ion=20of=20Tutorial=20-=20First=20Steps=20(#2208)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/es/docs/tutorial/first-steps.md | 333 +++++++++++++++++++++++++++ docs/es/mkdocs.yml | 1 + 2 files changed, 334 insertions(+) create mode 100644 docs/es/docs/tutorial/first-steps.md diff --git a/docs/es/docs/tutorial/first-steps.md b/docs/es/docs/tutorial/first-steps.md new file mode 100644 index 000000000..79f0a51c0 --- /dev/null +++ b/docs/es/docs/tutorial/first-steps.md @@ -0,0 +1,333 @@ +# Primeros pasos + +Un archivo muy simple de FastAPI podría verse así: + +```Python +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Copia eso a un archivo `main.py`. + +Corre el servidor en vivo: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +!!! note "Nota" + El comando `uvicorn main:app` se refiere a: + + * `main`: el archivo `main.py` (el "módulo" de Python). + * `app`: el objeto creado dentro de `main.py` con la línea `app = FastAPI()`. + * `--reload`: hace que el servidor se reinicie cada vez que cambia el código. Úsalo únicamente para desarrollo. + +En el output, hay una línea que dice más o menos: + +```hl_lines="4" +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +Esa línea muestra la URL dónde se está sirviendo tu app en tu maquina local. + +### Revísalo + +Abre tu navegador en http://127.0.0.1:8000. + +Verás la respuesta en JSON: + +```JSON +{"message": "Hello World"} +``` + +### Documentación interactiva de la API + +Ahora dirígete a http://127.0.0.1:8000/docs. + +Ahí verás la documentación automática e interactiva de la API (proveída por Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Documentación alternativa de la API + +Ahora, dirígete a http://127.0.0.1:8000/redoc. + +Aquí verás la documentación automática alternativa (proveída por ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +### OpenAPI + +**FastAPI** genera un "schema" con toda tu API usando el estándar para definir APIs, **OpenAPI**. + +#### "Schema" + +Un "schema" es una definición o descripción de algo. No es el código que la implementa, sino solo una descripción abstracta. + +#### "Schema" de la API + +En este caso, OpenAPI es una especificación que dicta como se debe definir el schema de tu API. + +La definición del schema incluye los paths de tu API, los parámetros que podría recibir, etc. + +#### "Schema" de datos + +El concepto "schema" también se puede referir a la forma de algunos datos, como un contenido en formato JSON. + +En ese caso haría referencia a los atributos del JSON, los tipos de datos que tiene, etc. + +#### OpenAPI y JSON Schema + +OpenAPI define un schema de API para tu API. Ese schema incluye definiciones (o "schemas") de los datos enviados y recibidos por tu API usando **JSON Schema**, el estándar para los schemas de datos en JSON. + +#### Revisa el `openapi.json` + +Si sientes curiosidad por saber cómo se ve el schema de OpenAPI en bruto, FastAPI genera automáticamente un (schema) JSON con la descripción de todo tu API. + +Lo puedes ver directamente en: http://127.0.0.1:8000/openapi.json. + +Esto te mostrará un JSON que comienza con algo como: + +```JSON +{ + "openapi": "3.0.2", + "info": { + "title": "FastAPI", + "version": "0.1.0" + }, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + + + +... +``` + +#### ¿Para qué se usa OpenAPI? + +El schema de OpenAPI es lo que alimenta a los dos sistemas de documentación interactiva incluidos. + +También hay docenas de alternativas, todas basadas en OpenAPI. Podrías añadir fácilmente cualquiera de esas alternativas a tu aplicación construida con **FastAPI**. + +También podrías usarlo para generar código automáticamente, para los clientes que se comunican con tu API. Por ejemplo, frontend, móvil o aplicaciones de IoT. + +## Repaso, paso a paso + +### Paso 1: importa `FastAPI` + +```Python hl_lines="1" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +`FastAPI` es una clase de Python que provee toda la funcionalidad para tu API. + +!!! note "Detalles Técnicos" + `FastAPI` es una clase que hereda directamente de `Starlette`. + + También puedes usar toda la funcionalidad de Starlette. + +### Paso 2: crea un "instance" de `FastAPI` + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Aquí la variable `app` será un instance de la clase `FastAPI`. + +Este será el punto de interacción principal para crear todo tu API. + +Esta `app` es la misma a la que nos referimos cuando usamos el comando de `uvicorn`: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Si creas un app como: + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial002.py!} +``` + +y lo guardas en un archivo `main.py`, entonces ejecutarías `uvicorn` así: + +
+ +```console +$ uvicorn main:my_awesome_api --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +### Paso 3: crea un *operación de path* + +#### Path + +"Path" aquí se refiere a la última parte de una URL comenzando desde el primer `/`. + +Entonces, en una URL como: + +``` +https://example.com/items/foo +``` + +...el path sería: + +``` +/items/foo +``` + +!!! info "Información" + Un "path" también se conoce habitualmente como "endpoint", "route" o "ruta". + +Cuando construyes una API, el "path" es la manera principal de separar los "intereses" y los "recursos". + +#### Operación + +"Operación" aquí se refiere a uno de los "métodos" de HTTP. + +Uno como: + +* `POST` +* `GET` +* `PUT` +* `DELETE` + +...y los más exóticos: + +* `OPTIONS` +* `HEAD` +* `PATCH` +* `TRACE` + +En el protocolo de HTTP, te puedes comunicar con cada path usando uno (o más) de estos "métodos". + +--- + +Cuando construyes APIs, normalmente usas uno de estos métodos específicos de HTTP para realizar una acción específica. + +Normalmente usas: + +* `POST`: para crear datos. +* `GET`: para leer datos. +* `PUT`: para actualizar datos. +* `DELETE`: para borrar datos. + +Así que en OpenAPI, cada uno de estos métodos de HTTP es referido como una "operación". + +Nosotros también los llamaremos "**operación**". + +#### Define un *decorador de operaciones de path* + +```Python hl_lines="6" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +El `@app.get("/")` le dice a **FastAPI** que la función que tiene justo debajo está a cargo de manejar los requests que van a: + +* el path `/` +* usando una operación get + +!!! info "Información sobre `@decorator`" + Esa sintaxis `@algo` se llama un "decorador" en Python. + + Lo pones encima de una función. Es como un lindo sombrero decorado (creo que de ahí salió el concepto). + + Un "decorador" toma la función que tiene debajo y hace algo con ella. + + En nuestro caso, este decorador le dice a **FastAPI** que la función que está debajo corresponde al **path** `/` con una **operación** `get`. + + Es el "**decorador de operaciones de path**". + +También puedes usar las otras operaciones: + +* `@app.post()` +* `@app.put()` +* `@app.delete()` + +y las más exóticas: + +* `@app.options()` +* `@app.head()` +* `@app.patch()` +* `@app.trace()` + +!!! tip "Consejo" + Tienes la libertad de usar cada operación (método de HTTP) como quieras. + + **FastAPI** no impone ningún significado específico. + + La información que está presentada aquí es una guía, no un requerimiento. + + Por ejemplo, cuando usas GraphQL normalmente realizas todas las acciones usando únicamente operaciones `POST`. + +### Paso 4: define la **función de la operación de path** + +Esta es nuestra "**función de la operación de path**": + +* **path**: es `/`. +* **operación**: es `get`. +* **función**: es la función debajo del "decorador" (debajo de `@app.get("/")`). + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Esto es una función de Python. + +Esta función será llamada por **FastAPI** cada vez que reciba un request en la URL "`/`" usando una operación `GET`. + +En este caso es una función `async`. + +--- + +También podrías definirla como una función normal, en vez de `async def`: + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial003.py!} +``` + +!!! note "Nota" + Si no sabes la diferencia, revisa el [Async: *"¿Tienes prisa?"*](../async.md#in-a-hurry){.internal-link target=_blank}. + +### Paso 5: devuelve el contenido + +```Python hl_lines="8" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Puedes devolver `dict`, `list`, valores singulares como un `str`, `int`, etc. + +También puedes devolver modelos de Pydantic (ya verás más sobre esto más adelante). + +Hay muchos objetos y modelos que pueden ser convertidos automáticamente a JSON (incluyendo ORMs, etc.). Intenta usar tus favoritos, es muy probable que ya tengan soporte. + +## Repaso + +* Importa `FastAPI`. +* Crea un instance de `app`. +* Escribe un **decorador de operación de path** (como `@app.get("/")`). +* Escribe una **función de la operación de path** (como `def root(): ...` arriba). +* Corre el servidor de desarrollo (como `uvicorn main:app --reload`). diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 1554cc3ea..2f6e02488 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -55,6 +55,7 @@ nav: - python-types.md - Tutorial - Guía de Usuario: - tutorial/index.md + - tutorial/first-steps.md - Guía de Usuario Avanzada: - advanced/index.md - async.md From afec8c4580ebe7a7a601c3560414f5c0ade49b31 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 3 Jul 2021 14:14:01 +0000 Subject: [PATCH 048/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 32df4ed0c..e64529b40 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Spanish translation of Tutorial - First Steps. PR [#2208](https://github.com/tiangolo/fastapi/pull/2208) by [@mariacamilagl](https://github.com/mariacamilagl). * 👥 Update FastAPI People. PR [#3450](https://github.com/tiangolo/fastapi/pull/3450) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🌐 Portuguese translation of Tutorial - Body - Fields. PR [#3420](https://github.com/tiangolo/fastapi/pull/3420) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Add Chinese translation for Tutorial - Request - Forms - and - Files. PR [#3249](https://github.com/tiangolo/fastapi/pull/3249) by [@jaystone776](https://github.com/jaystone776). From faec748ef6b81de62242588a51f6a22b5fc82240 Mon Sep 17 00:00:00 2001 From: Camila Gutierrez Date: Sat, 3 Jul 2021 16:46:49 +0200 Subject: [PATCH 049/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Spanish=20translat?= =?UTF-8?q?ion=20of=20Tutorial=20-=20Path=20Parameters=20(#2219)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Pedro A. Moreno Co-authored-by: Sebastián Ramírez --- docs/es/docs/tutorial/path-params.md | 244 +++++++++++++++++++++++++++ docs/es/mkdocs.yml | 1 + 2 files changed, 245 insertions(+) create mode 100644 docs/es/docs/tutorial/path-params.md diff --git a/docs/es/docs/tutorial/path-params.md b/docs/es/docs/tutorial/path-params.md new file mode 100644 index 000000000..6432de1cd --- /dev/null +++ b/docs/es/docs/tutorial/path-params.md @@ -0,0 +1,244 @@ +# Parámetros de path + +Puedes declarar los "parámetros" o "variables" con la misma sintaxis que usan los format strings de Python: + +```Python hl_lines="6-7" +{!../../../docs_src/path_params/tutorial001.py!} +``` + +El valor del parámetro de path `item_id` será pasado a tu función como el argumento `item_id`. + +Entonces, si corres este ejemplo y vas a http://127.0.0.1:8000/items/foo, verás una respuesta de: + +```JSON +{"item_id":"foo"} +``` + +## Parámetros de path con tipos + +Puedes declarar el tipo de un parámetro de path en la función usando las anotaciones de tipos estándar de Python: + +```Python hl_lines="7" +{!../../../docs_src/path_params/tutorial002.py!} +``` + +En este caso, `item_id` es declarado como un `int`. + +!!! check "Revisa" + Esto te dará soporte en el editor dentro de tu función, con chequeos de errores, autocompletado, etc. + +## Conversión de datos + +Si corres este ejemplo y abres tu navegador en http://127.0.0.1:8000/items/3 verás una respuesta de: + +```JSON +{"item_id":3} +``` + +!!! check "Revisa" + Observa que el valor que recibió (y devolvió) tu función es `3`, como un Python `int`, y no un string `"3"`. + + Entonces, con esa declaración de tipos **FastAPI** te da "parsing" automático del request. + +## Validación de datos + +Pero si abres tu navegador en http://127.0.0.1:8000/items/foo verás este lindo error de HTTP: + +```JSON +{ + "detail": [ + { + "loc": [ + "path", + "item_id" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ] +} +``` + +debido a que el parámetro de path `item_id` tenía el valor `"foo"`, que no es un `int`. + +El mismo error aparecería si pasaras un `float` en vez de un `int` como en: http://127.0.0.1:8000/items/4.2 + +!!! check "Revisa" + Así, con la misma declaración de tipo de Python, **FastAPI** te da validación de datos. + + Observa que el error también muestra claramente el punto exacto en el que no pasó la validación. + + Esto es increíblemente útil cuando estás desarrollando y debugging código que interactúa con tu API. + +## Documentación + +Cuando abras tu navegador en http://127.0.0.1:8000/docs verás la documentación automática e interactiva del API como: + + + +!!! check "Revisa" + Nuevamente, con la misma declaración de tipo de Python, **FastAPI** te da documentación automática e interactiva (integrándose con Swagger UI) + + Observa que el parámetro de path está declarado como un integer. + +## Beneficios basados en estándares, documentación alternativa + +Debido a que el schema generado es del estándar OpenAPI hay muchas herramientas compatibles. + +Es por esto que **FastAPI** mismo provee una documentación alternativa de la API (usando ReDoc), a la que puedes acceder en http://127.0.0.1:8000/redoc: + + + +De la misma manera hay muchas herramientas compatibles. Incluyendo herramientas de generación de código para muchos lenguajes. + +## Pydantic + +Toda la validación de datos es realizada tras bastidores por Pydantic, así que obtienes todos sus beneficios. Así sabes que estás en buenas manos. + +Puedes usar las mismas declaraciones de tipos con `str`, `float`, `bool` y otros tipos de datos más complejos. + +Exploraremos varios de estos tipos en los próximos capítulos del tutorial. + +## El orden importa + +Cuando creas *operaciones de path* puedes encontrarte con situaciones en las que tengas un path fijo. + +Digamos algo como `/users/me` que sea para obtener datos del usuario actual. + +... y luego puedes tener el path `/users/{user_id}` para obtener los datos sobre un usuario específico asociados a un ID de usuario. + +Porque las *operaciones de path* son evaluadas en orden, tienes que asegurarte de que el path para `/users/me` sea declarado antes que el path para `/users/{user_id}`: + +```Python hl_lines="6 11" +{!../../../docs_src/path_params/tutorial003.py!} +``` + +De otra manera el path para `/users/{user_id}` coincidiría también con `/users/me` "pensando" que está recibiendo el parámetro `user_id` con el valor `"me"`. + +## Valores predefinidos + +Si tienes una *operación de path* que recibe un *parámetro de path* pero quieres que los valores posibles del *parámetro de path* sean predefinidos puedes usar un `Enum` estándar de Python. + +### Crea una clase `Enum` + +Importa `Enum` y crea una sub-clase que herede desde `str` y desde `Enum`. + +Al heredar desde `str` la documentación de la API podrá saber que los valores deben ser de tipo `string` y podrá mostrarlos correctamente. + +Luego crea atributos de clase con valores fijos, que serán los valores disponibles válidos: + +```Python hl_lines="1 6-9" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +!!! info "Información" + Las Enumerations (o enums) están disponibles en Python desde la versión 3.4. + +!!! tip "Consejo" + Si lo estás dudando, "AlexNet", "ResNet", y "LeNet" son solo nombres de modelos de Machine Learning. + +### Declara un *parámetro de path* + +Luego, crea un *parámetro de path* con anotaciones de tipos usando la clase enum que creaste (`ModelName`): + +```Python hl_lines="16" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +### Revisa la documentación + +Debido a que los valores disponibles para el *parámetro de path* están predefinidos, la documentación interactiva los puede mostrar bien: + + + +### Trabajando con los *enumerations* de Python + +El valor del *parámetro de path* será un *enumeration member*. + +#### Compara *enumeration members* + +Puedes compararlo con el *enumeration member* en el enum (`ModelName`) que creaste: + +```Python hl_lines="17" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +#### Obtén el *enumeration value* + +Puedes obtener el valor exacto (un `str` en este caso) usando `model_name.value`, o en general, `your_enum_member.value`: + +```Python hl_lines="20" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +!!! tip "Consejo" + También podrías obtener el valor `"lenet"` con `ModelName.lenet.value`. + +#### Devuelve *enumeration members* + +Puedes devolver *enum members* desde tu *operación de path* inclusive en un body de JSON anidado (por ejemplo, un `dict`). + +Ellos serán convertidos a sus valores correspondientes (strings en este caso) antes de devolverlos al cliente: + +```Python hl_lines="18 21 23" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +En tu cliente obtendrás una respuesta en JSON como: + +```JSON +{ + "model_name": "alexnet", + "message": "Deep Learning FTW!" +} +``` + +## Parámetros de path parameters que contienen paths + +Digamos que tienes una *operación de path* con un path `/files/{file_path}`. + +Pero necesitas que el mismo `file_path` contenga un path como `home/johndoe/myfile.txt`. + +Entonces, la URL para ese archivo sería algo como: `/files/home/johndoe/myfile.txt`. + +### Soporte de OpenAPI + +OpenAPI no soporta una manera de declarar un *parámetro de path* que contenga un path, dado que esto podría llevar a escenarios que son difíciles de probar y definir. + +Sin embargo, lo puedes hacer en **FastAPI** usando una de las herramientas internas de Starlette. + +La documentación seguirá funcionando, aunque no añadirá ninguna información diciendo que el parámetro debería contener un path. + +### Convertidor de path + +Usando una opción directamente desde Starlette puedes declarar un *parámetro de path* que contenga un path usando una URL como: + +``` +/files/{file_path:path} +``` + +En este caso el nombre del parámetro es `file_path` y la última parte, `:path`, le dice que el parámetro debería coincidir con cualquier path. + +Entonces lo puedes usar con: + +```Python hl_lines="6" +{!../../../docs_src/path_params/tutorial004.py!} +``` + +!!! tip "Consejo" + Podrías necesitar que el parámetro contenga `/home/johndoe/myfile.txt` con un slash inicial (`/`). + + En este caso la URL sería `/files//home/johndoe/myfile.txt` con un slash doble (`//`) entre `files` y `home`. + +## Repaso + +Con **FastAPI**, usando declaraciones de tipo de Python intuitivas y estándares, obtienes: + +* Soporte en el editor: chequeos de errores, auto-completado, etc. +* "Parsing" de datos +* Validación de datos +* Anotación de la API y documentación automática + +Solo tienes que declararlos una vez. + +Esa es probablemente la principal ventaja visible de **FastAPI** sobre otros frameworks alternativos (aparte del rendimiento puro). diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 2f6e02488..bee119ea9 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -56,6 +56,7 @@ nav: - Tutorial - Guía de Usuario: - tutorial/index.md - tutorial/first-steps.md + - tutorial/path-params.md - Guía de Usuario Avanzada: - advanced/index.md - async.md From e1d4fc532552d88f52b15950b274ee3c40b2942d Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 3 Jul 2021 14:47:21 +0000 Subject: [PATCH 050/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e64529b40..22047dd83 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Spanish translation of Tutorial - Path Parameters. PR [#2219](https://github.com/tiangolo/fastapi/pull/2219) by [@mariacamilagl](https://github.com/mariacamilagl). * 🌐 Add Spanish translation of Tutorial - First Steps. PR [#2208](https://github.com/tiangolo/fastapi/pull/2208) by [@mariacamilagl](https://github.com/mariacamilagl). * 👥 Update FastAPI People. PR [#3450](https://github.com/tiangolo/fastapi/pull/3450) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🌐 Portuguese translation of Tutorial - Body - Fields. PR [#3420](https://github.com/tiangolo/fastapi/pull/3420) by [@ComicShrimp](https://github.com/ComicShrimp). From 7e4bfaf0e9d407ea33a69acf1fe7ba73bd986e30 Mon Sep 17 00:00:00 2001 From: Nasaruddin Date: Sat, 3 Jul 2021 22:12:51 +0700 Subject: [PATCH 051/814] =?UTF-8?q?=F0=9F=8C=90=20Initialize=20Indonesian?= =?UTF-8?q?=20translations=20(#3014)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nasaruddin --- docs/en/mkdocs.yml | 3 + docs/es/mkdocs.yml | 3 + docs/fr/mkdocs.yml | 3 + docs/id/docs/index.md | 464 ++++++++++++++++++++++++++++++++++++ docs/id/mkdocs.yml | 119 +++++++++ docs/id/overrides/main.html | 13 + docs/it/mkdocs.yml | 3 + docs/ja/mkdocs.yml | 3 + docs/ko/mkdocs.yml | 3 + docs/pt/mkdocs.yml | 3 + docs/ru/mkdocs.yml | 3 + docs/sq/mkdocs.yml | 3 + docs/tr/mkdocs.yml | 3 + docs/uk/mkdocs.yml | 3 + docs/zh/mkdocs.yml | 3 + 15 files changed, 632 insertions(+) create mode 100644 docs/id/docs/index.md create mode 100644 docs/id/mkdocs.yml create mode 100644 docs/id/overrides/main.html diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 1c9faf5fa..efb5378d1 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -193,6 +194,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index bee119ea9..292cb5491 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -99,6 +100,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 250af172a..7ff24f8c4 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -98,6 +99,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/id/docs/index.md b/docs/id/docs/index.md new file mode 100644 index 000000000..edc19fa48 --- /dev/null +++ b/docs/id/docs/index.md @@ -0,0 +1,464 @@ + +{!../../../docs/missing-translation.md!} + + +

+ FastAPI +

+

+ FastAPI framework, high performance, easy to learn, fast to code, ready for production +

+

+ + Test + + + Coverage + + + Package version + +

+ +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: https://github.com/tiangolo/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. + +The key features are: + +* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). + +* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * +* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. + +* estimation based on tests on an internal development team, building production applications. + +## Gold Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + +## Opinions + +"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" + +
Kabir Khan - Microsoft (ref)
+ +--- + +"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" + +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
+ +--- + +"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" + +
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
+ +--- + +"_I’m over the moon excited about **FastAPI**. It’s so fun!_" + +
Brian Okken - Python Bytes podcast host (ref)
+ +--- + +"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" + +
Timothy Crosley - Hug creator (ref)
+ +--- + +"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" + +"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" + +
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +## **Typer**, the FastAPI of CLIs + + + +If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. + +**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 + +## Requirements + +Python 3.6+ + +FastAPI stands on the shoulders of giants: + +* Starlette for the web parts. +* Pydantic for the data parts. + +## Installation + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+ +You will also need an ASGI server, for production such as Uvicorn or Hypercorn. + +
+ +```console +$ pip install uvicorn[standard] + +---> 100% +``` + +
+ +## Example + +### Create it + +* Create a file `main.py` with: + +```Python +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +
+Or use async def... + +If your code uses `async` / `await`, use `async def`: + +```Python hl_lines="9 14" +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +**Note**: + +If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. + +
+ +### Run it + +Run the server with: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+About the command uvicorn main:app --reload... + +The command `uvicorn main:app` refers to: + +* `main`: the file `main.py` (the Python "module"). +* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. +* `--reload`: make the server restart after code changes. Only do this for development. + +
+ +### Check it + +Open your browser at http://127.0.0.1:8000/items/5?q=somequery. + +You will see the JSON response as: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +You already created an API that: + +* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. +* Both _paths_ take `GET` operations (also known as HTTP _methods_). +* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. +* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. + +### Interactive API docs + +Now go to http://127.0.0.1:8000/docs. + +You will see the automatic interactive API documentation (provided by Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Alternative API docs + +And now, go to http://127.0.0.1:8000/redoc. + +You will see the alternative automatic documentation (provided by ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Example upgrade + +Now modify the file `main.py` to receive a body from a `PUT` request. + +Declare the body using standard Python types, thanks to Pydantic. + +```Python hl_lines="4 9-12 25-27" +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Optional[bool] = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} +``` + +The server should reload automatically (because you added `--reload` to the `uvicorn` command above). + +### Interactive API docs upgrade + +Now go to http://127.0.0.1:8000/docs. + +* The interactive API documentation will be automatically updated, including the new body: + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) + +* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) + +### Alternative API docs upgrade + +And now, go to http://127.0.0.1:8000/redoc. + +* The alternative documentation will also reflect the new query parameter and body: + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Recap + +In summary, you declare **once** the types of parameters, body, etc. as function parameters. + +You do that with standard modern Python types. + +You don't have to learn a new syntax, the methods or classes of a specific library, etc. + +Just standard **Python 3.6+**. + +For example, for an `int`: + +```Python +item_id: int +``` + +or for a more complex `Item` model: + +```Python +item: Item +``` + +...and with that single declaration you get: + +* Editor support, including: + * Completion. + * Type checks. +* Validation of data: + * Automatic and clear errors when the data is invalid. + * Validation even for deeply nested JSON objects. +* Conversion of input data: coming from the network to Python data and types. Reading from: + * JSON. + * Path parameters. + * Query parameters. + * Cookies. + * Headers. + * Forms. + * Files. +* Conversion of output data: converting from Python data and types to network data (as JSON): + * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). + * `datetime` objects. + * `UUID` objects. + * Database models. + * ...and many more. +* Automatic interactive API documentation, including 2 alternative user interfaces: + * Swagger UI. + * ReDoc. + +--- + +Coming back to the previous code example, **FastAPI** will: + +* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. +* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. + * If it is not, the client will see a useful, clear error. +* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. + * As the `q` parameter is declared with `= None`, it is optional. + * Without the `None` it would be required (as is the body in the case with `PUT`). +* For `PUT` requests to `/items/{item_id}`, Read the body as JSON: + * Check that it has a required attribute `name` that should be a `str`. + * Check that it has a required attribute `price` that has to be a `float`. + * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. + * All this would also work for deeply nested JSON objects. +* Convert from and to JSON automatically. +* Document everything with OpenAPI, that can be used by: + * Interactive documentation systems. + * Automatic client code generation systems, for many languages. +* Provide 2 interactive documentation web interfaces directly. + +--- + +We just scratched the surface, but you already get the idea of how it all works. + +Try changing the line with: + +```Python + return {"item_name": item.name, "item_id": item_id} +``` + +...from: + +```Python + ... "item_name": item.name ... +``` + +...to: + +```Python + ... "item_price": item.price ... +``` + +...and see how your editor will auto-complete the attributes and know their types: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +For a more complete example including more features, see the Tutorial - User Guide. + +**Spoiler alert**: the tutorial - user guide includes: + +* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. +* How to set **validation constraints** as `maximum_length` or `regex`. +* A very powerful and easy to use **Dependency Injection** system. +* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. +* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). +* Many extra features (thanks to Starlette) as: + * **WebSockets** + * **GraphQL** + * extremely easy tests based on `requests` and `pytest` + * **CORS** + * **Cookie Sessions** + * ...and more. + +## Performance + +Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) + +To understand more about it, see the section Benchmarks. + +## Optional Dependencies + +Used by Pydantic: + +* ujson - for faster JSON "parsing". +* email_validator - for email validation. + +Used by Starlette: + +* requests - Required if you want to use the `TestClient`. +* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. +* jinja2 - Required if you want to use the default template configuration. +* python-multipart - Required if you want to support form "parsing", with `request.form()`. +* itsdangerous - Required for `SessionMiddleware` support. +* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). +* graphene - Required for `GraphQLApp` support. +* ujson - Required if you want to use `UJSONResponse`. + +Used by FastAPI / Starlette: + +* uvicorn - for the server that loads and serves your application. +* orjson - Required if you want to use `ORJSONResponse`. + +You can install all of these with `pip install fastapi[all]`. + +## License + +This project is licensed under the terms of the MIT license. diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml new file mode 100644 index 000000000..1868aac8c --- /dev/null +++ b/docs/id/mkdocs.yml @@ -0,0 +1,119 @@ +site_name: FastAPI +site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production +site_url: https://fastapi.tiangolo.com/id/ +theme: + name: material + custom_dir: overrides + palette: + - scheme: default + primary: teal + accent: amber + toggle: + icon: material/lightbulb-outline + name: Switch to light mode + - scheme: slate + primary: teal + accent: amber + toggle: + icon: material/lightbulb + name: Switch to dark mode + features: + - search.suggest + - search.highlight + icon: + repo: fontawesome/brands/github-alt + logo: https://fastapi.tiangolo.com/img/icon-white.svg + favicon: https://fastapi.tiangolo.com/img/favicon.png + language: id +repo_name: tiangolo/fastapi +repo_url: https://github.com/tiangolo/fastapi +edit_uri: '' +google_analytics: +- UA-133183413-1 +- auto +plugins: +- search +- markdownextradata: + data: data +nav: +- FastAPI: index.md +- Languages: + - en: / + - es: /es/ + - fr: /fr/ + - id: /id/ + - it: /it/ + - ja: /ja/ + - ko: /ko/ + - pt: /pt/ + - ru: /ru/ + - sq: /sq/ + - tr: /tr/ + - uk: /uk/ + - zh: /zh/ +markdown_extensions: +- toc: + permalink: true +- markdown.extensions.codehilite: + guess_lang: false +- markdown_include.include: + base_path: docs +- admonition +- codehilite +- extra +- pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_div_format '' +- pymdownx.tabbed +extra: + social: + - icon: fontawesome/brands/github-alt + link: https://github.com/tiangolo/fastapi + - icon: fontawesome/brands/discord + link: https://discord.gg/VQjSZaeJmf + - icon: fontawesome/brands/twitter + link: https://twitter.com/tiangolo + - icon: fontawesome/brands/linkedin + link: https://www.linkedin.com/in/tiangolo + - icon: fontawesome/brands/dev + link: https://dev.to/tiangolo + - icon: fontawesome/brands/medium + link: https://medium.com/@tiangolo + - icon: fontawesome/solid/globe + link: https://tiangolo.com + alternate: + - link: / + name: en - English + - link: /es/ + name: es - español + - link: /fr/ + name: fr - français + - link: /id/ + name: id + - link: /it/ + name: it - italiano + - link: /ja/ + name: ja - 日本語 + - link: /ko/ + name: ko - 한국어 + - link: /pt/ + name: pt - português + - link: /ru/ + name: ru - русский язык + - link: /sq/ + name: sq - shqip + - link: /tr/ + name: tr - Türkçe + - link: /uk/ + name: uk - українська мова + - link: /zh/ + name: zh - 汉语 +extra_css: +- https://fastapi.tiangolo.com/css/termynal.css +- https://fastapi.tiangolo.com/css/custom.css +extra_javascript: +- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js +- https://fastapi.tiangolo.com/js/termynal.js +- https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/id/overrides/main.html b/docs/id/overrides/main.html new file mode 100644 index 000000000..abf6f3108 --- /dev/null +++ b/docs/id/overrides/main.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block announce %} + + + {% include ".icons/material/email.svg" %} + Subscribe to the FastAPI and friends newsletter 🎉 + + +{% endblock %} diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index f03730466..2b057b67e 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -90,6 +91,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index c2d905b13..e083de096 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -129,6 +130,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 7f1991ed3..8768d61a2 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -96,6 +97,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 6102a859d..27c1f706b 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -99,6 +100,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index b2b1b9aa7..ca3feedef 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -90,6 +91,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index 9b255718b..77de29e13 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -90,6 +91,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index b65088447..234aae178 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -90,6 +91,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index cecd2444f..8ecf20d17 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -90,6 +91,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 85e470e59..359fb4e8f 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -41,6 +41,7 @@ nav: - en: / - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -136,6 +137,8 @@ extra: name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ From 7eb17fc8740badea747701d8af7a183875b86fdc Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 3 Jul 2021 15:13:30 +0000 Subject: [PATCH 052/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 22047dd83..690d8943d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Initialize Indonesian translations. PR [#3014](https://github.com/tiangolo/fastapi/pull/3014) by [@pace-noge](https://github.com/pace-noge). * 🌐 Add Spanish translation of Tutorial - Path Parameters. PR [#2219](https://github.com/tiangolo/fastapi/pull/2219) by [@mariacamilagl](https://github.com/mariacamilagl). * 🌐 Add Spanish translation of Tutorial - First Steps. PR [#2208](https://github.com/tiangolo/fastapi/pull/2208) by [@mariacamilagl](https://github.com/mariacamilagl). * 👥 Update FastAPI People. PR [#3450](https://github.com/tiangolo/fastapi/pull/3450) by [@github-actions[bot]](https://github.com/apps/github-actions). From edf6b2d61ff2645d8fcde30e60421ee9d8f2a4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 3 Jul 2021 18:25:12 +0200 Subject: [PATCH 053/814] =?UTF-8?q?=E2=99=BB=20Assume=20request=20bodies?= =?UTF-8?q?=20contain=20JSON=20when=20no=20Content-Type=20header=20is=20pr?= =?UTF-8?q?ovided=20(#3456)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/routing.py | 4 +++- tests/test_tutorial/test_body/test_tutorial001.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/fastapi/routing.py b/fastapi/routing.py index 9b51f03ca..3cf35f509 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -184,7 +184,9 @@ def get_request_handler( if body_bytes: json_body: Any = Undefined content_type_value = request.headers.get("content-type") - if content_type_value: + if not content_type_value: + json_body = await request.json() + else: message = email.message.Message() message["content-type"] = content_type_value if message.get_content_maintype() == "application": diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py index c90240ae4..7bf62c907 100644 --- a/tests/test_tutorial/test_body/test_tutorial001.py +++ b/tests/test_tutorial/test_body/test_tutorial001.py @@ -229,6 +229,20 @@ def test_geo_json(): assert response.status_code == 200, response.text +def test_no_content_type_is_json(): + response = client.post( + "/items/", + data='{"name": "Foo", "price": 50.5}', + ) + assert response.status_code == 200, response.text + assert response.json() == { + "name": "Foo", + "description": None, + "price": 50.5, + "tax": None, + } + + def test_wrong_headers(): data = '{"name": "Foo", "price": 50.5}' invalid_dict = { From 15fd60b29ab54c464c993f7fc1ac61eae65df7fe Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 3 Jul 2021 16:26:48 +0000 Subject: [PATCH 054/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 690d8943d..8746ce2a6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻ Assume request bodies contain JSON when no Content-Type header is provided. PR [#3456](https://github.com/tiangolo/fastapi/pull/3456) by [@tiangolo](https://github.com/tiangolo). * 🌐 Initialize Indonesian translations. PR [#3014](https://github.com/tiangolo/fastapi/pull/3014) by [@pace-noge](https://github.com/pace-noge). * 🌐 Add Spanish translation of Tutorial - Path Parameters. PR [#2219](https://github.com/tiangolo/fastapi/pull/2219) by [@mariacamilagl](https://github.com/mariacamilagl). * 🌐 Add Spanish translation of Tutorial - First Steps. PR [#2208](https://github.com/tiangolo/fastapi/pull/2208) by [@mariacamilagl](https://github.com/mariacamilagl). From 787e54b096af45222ca4038bc8f286e050358f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 3 Jul 2021 18:30:46 +0200 Subject: [PATCH 055/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8746ce2a6..a2f2d49e3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,16 +2,19 @@ ## Latest Changes -* ♻ Assume request bodies contain JSON when no Content-Type header is provided. PR [#3456](https://github.com/tiangolo/fastapi/pull/3456) by [@tiangolo](https://github.com/tiangolo). +### Fixes + +* ♻ Assume request bodies contain JSON when no Content-Type header is provided. This should allow upgrading FastAPI applications with clients that send JSON data without a `Content-Type` header. And there's still protection against CSRFs. PR [#3456](https://github.com/tiangolo/fastapi/pull/3456) by [@tiangolo](https://github.com/tiangolo). + +### Translations + * 🌐 Initialize Indonesian translations. PR [#3014](https://github.com/tiangolo/fastapi/pull/3014) by [@pace-noge](https://github.com/pace-noge). * 🌐 Add Spanish translation of Tutorial - Path Parameters. PR [#2219](https://github.com/tiangolo/fastapi/pull/2219) by [@mariacamilagl](https://github.com/mariacamilagl). * 🌐 Add Spanish translation of Tutorial - First Steps. PR [#2208](https://github.com/tiangolo/fastapi/pull/2208) by [@mariacamilagl](https://github.com/mariacamilagl). -* 👥 Update FastAPI People. PR [#3450](https://github.com/tiangolo/fastapi/pull/3450) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🌐 Portuguese translation of Tutorial - Body - Fields. PR [#3420](https://github.com/tiangolo/fastapi/pull/3420) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Add Chinese translation for Tutorial - Request - Forms - and - Files. PR [#3249](https://github.com/tiangolo/fastapi/pull/3249) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for Tutorial - Handling - Errors. PR [#3299](https://github.com/tiangolo/fastapi/pull/3299) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for Tutorial - Form - Data. PR [#3248](https://github.com/tiangolo/fastapi/pull/3248) by [@jaystone776](https://github.com/jaystone776). -* 👥 Update FastAPI People. PR [#3319](https://github.com/tiangolo/fastapi/pull/3319) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🌐 Add Chinese translation for Tutorial - Body - Updates. PR [#3237](https://github.com/tiangolo/fastapi/pull/3237) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Chinese translation for FastAPI People. PR [#3112](https://github.com/tiangolo/fastapi/pull/3112) by [@hareru](https://github.com/hareru). * 🌐 Add French translation for Project Generation. PR [#3197](https://github.com/tiangolo/fastapi/pull/3197) by [@Smlep](https://github.com/Smlep). @@ -20,9 +23,14 @@ * 🌐 Add French translation for Alternatives, Inspiration and Comparisons. PR [#3020](https://github.com/tiangolo/fastapi/pull/3020) by [@rjNemo](https://github.com/rjNemo). * 🌐 Fix Chinese translation code snippet mismatch in Tutorial - Python Types Intro. PR [#2573](https://github.com/tiangolo/fastapi/pull/2573) by [@BoYanZh](https://github.com/BoYanZh). * 🌐 Add Portuguese translation for Development Contributing. PR [#1364](https://github.com/tiangolo/fastapi/pull/1364) by [@Serrones](https://github.com/Serrones). -* ⬆ Upgrade docs development dependency on `typer-cli` to >=0.0.12 to fix conflicts. PR [#3429](https://github.com/tiangolo/fastapi/pull/3429) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Chinese translation for Tutorial - Request - Files. PR [#3244](https://github.com/tiangolo/fastapi/pull/3244) by [@jaystone776](https://github.com/jaystone776). +### Internal + +* 👥 Update FastAPI People. PR [#3450](https://github.com/tiangolo/fastapi/pull/3450) by [@github-actions[bot]](https://github.com/apps/github-actions). +* 👥 Update FastAPI People. PR [#3319](https://github.com/tiangolo/fastapi/pull/3319) by [@github-actions[bot]](https://github.com/apps/github-actions). +* ⬆ Upgrade docs development dependency on `typer-cli` to >=0.0.12 to fix conflicts. PR [#3429](https://github.com/tiangolo/fastapi/pull/3429) by [@tiangolo](https://github.com/tiangolo). + ## 0.65.2 ### Security fixes From b725e9eb45d0336a1eef1d9c4f698b3fcf3d84d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 3 Jul 2021 18:32:50 +0200 Subject: [PATCH 056/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a2f2d49e3..442ff9f85 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -4,7 +4,7 @@ ### Fixes -* ♻ Assume request bodies contain JSON when no Content-Type header is provided. This should allow upgrading FastAPI applications with clients that send JSON data without a `Content-Type` header. And there's still protection against CSRFs. PR [#3456](https://github.com/tiangolo/fastapi/pull/3456) by [@tiangolo](https://github.com/tiangolo). +* ♻ Assume request bodies contain JSON when no Content-Type header is provided. This fixes a breaking change introduced by [0.65.2 with PR #2118](https://github.com/tiangolo/fastapi/pull/2118). It should allow upgrading FastAPI applications with clients that send JSON data without a `Content-Type` header. And there's still protection against CSRFs. PR [#3456](https://github.com/tiangolo/fastapi/pull/3456) by [@tiangolo](https://github.com/tiangolo). ### Translations From 79f52c76cf19d1c3f37707049c1cd0c3ca33e7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 3 Jul 2021 18:33:32 +0200 Subject: [PATCH 057/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.65?= =?UTF-8?q?.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 442ff9f85..a46ef4c50 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.65.3 + ### Fixes * ♻ Assume request bodies contain JSON when no Content-Type header is provided. This fixes a breaking change introduced by [0.65.2 with PR #2118](https://github.com/tiangolo/fastapi/pull/2118). It should allow upgrading FastAPI applications with clients that send JSON data without a `Content-Type` header. And there's still protection against CSRFs. PR [#3456](https://github.com/tiangolo/fastapi/pull/3456) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index d04f2ea96..66a63d369 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.65.2" +__version__ = "0.65.3" from starlette import status as status From 0ed6c9234186ad61b6e6f21b557c978aed799253 Mon Sep 17 00:00:00 2001 From: Jacob Magnusson Date: Sat, 3 Jul 2021 19:15:59 +0200 Subject: [PATCH 058/814] =?UTF-8?q?=F0=9F=90=9B=20Support=20custom=20OpenA?= =?UTF-8?q?PI=20/=20JSON=20Schema=20fields=20in=20the=20generated=20output?= =?UTF-8?q?=20OpenAPI=20(#1429)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/openapi/models.py | 3 ++ tests/test_custom_schema_fields.py | 51 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/test_custom_schema_fields.py diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index fd480946d..efbd88ad7 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -117,6 +117,9 @@ class SchemaBase(BaseModel): example: Optional[Any] = None deprecated: Optional[bool] = None + class Config: + extra: str = "allow" + class Schema(SchemaBase): allOf: Optional[List[SchemaBase]] = None diff --git a/tests/test_custom_schema_fields.py b/tests/test_custom_schema_fields.py new file mode 100644 index 000000000..10b02608c --- /dev/null +++ b/tests/test_custom_schema_fields.py @@ -0,0 +1,51 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + + class Config: + schema_extra = { + "x-something-internal": {"level": 4}, + } + + +@app.get("/foo", response_model=Item) +def foo(): + return {"name": "Foo item"} + + +client = TestClient(app) + + +item_schema = { + "title": "Item", + "required": ["name"], + "type": "object", + "x-something-internal": { + "level": 4, + }, + "properties": { + "name": { + "title": "Name", + "type": "string", + } + }, +} + + +def test_custom_response_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json()["components"]["schemas"]["Item"] == item_schema + + +def test_response(): + # For coverage + response = client.get("/foo") + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo item"} From ea8d7f689efcb0ddf28f4686fa3be90c2154503b Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 3 Jul 2021 17:16:33 +0000 Subject: [PATCH 059/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a46ef4c50..779b28067 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Support custom OpenAPI / JSON Schema fields in the generated output OpenAPI. PR [#1429](https://github.com/tiangolo/fastapi/pull/1429) by [@jmagnusson](https://github.com/jmagnusson). ## 0.65.3 From dc5a966548df973d0fd2d3a28bad65d0436f6fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 3 Jul 2021 21:51:28 +0200 Subject: [PATCH 060/814] =?UTF-8?q?=E2=9C=A8=20Allow=20setting=20the=20`re?= =?UTF-8?q?sponse=5Fclass`=20to=20`RedirectResponse`=20and=20returning=20t?= =?UTF-8?q?he=20URL=20from=20the=20function=20(#3457)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/custom-response.md | 31 ++++++++++++++++ docs_src/custom_response/tutorial006.py | 2 +- docs_src/custom_response/tutorial006b.py | 9 +++++ docs_src/custom_response/tutorial006c.py | 9 +++++ docs_src/custom_response/tutorial009b.py | 10 ++++++ fastapi/applications.py | 20 +++++------ fastapi/openapi/utils.py | 15 +++++++- fastapi/routing.py | 35 ++++++++++--------- .../test_custom_response/test_tutorial006.py | 26 ++++++++++++++ .../test_custom_response/test_tutorial006b.py | 32 +++++++++++++++++ .../test_custom_response/test_tutorial006c.py | 32 +++++++++++++++++ .../test_custom_response/test_tutorial009.py | 17 +++++++++ .../test_custom_response/test_tutorial009b.py | 17 +++++++++ 13 files changed, 226 insertions(+), 29 deletions(-) create mode 100644 docs_src/custom_response/tutorial006b.py create mode 100644 docs_src/custom_response/tutorial006c.py create mode 100644 docs_src/custom_response/tutorial009b.py create mode 100644 tests/test_tutorial/test_custom_response/test_tutorial006b.py create mode 100644 tests/test_tutorial/test_custom_response/test_tutorial006c.py create mode 100644 tests/test_tutorial/test_custom_response/test_tutorial009.py create mode 100644 tests/test_tutorial/test_custom_response/test_tutorial009b.py diff --git a/docs/en/docs/advanced/custom-response.md b/docs/en/docs/advanced/custom-response.md index fa253305e..20b694ced 100644 --- a/docs/en/docs/advanced/custom-response.md +++ b/docs/en/docs/advanced/custom-response.md @@ -161,10 +161,33 @@ An alternative JSON response using Date: Sat, 3 Jul 2021 19:52:03 +0000 Subject: [PATCH 061/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 779b28067..68e8198a8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). * 🐛 Support custom OpenAPI / JSON Schema fields in the generated output OpenAPI. PR [#1429](https://github.com/tiangolo/fastapi/pull/1429) by [@jmagnusson](https://github.com/jmagnusson). ## 0.65.3 From 9f3c8cd13963ef7af93a875204b4ca46e12f2d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 3 Jul 2021 21:59:39 +0200 Subject: [PATCH 062/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= =?UTF-8?q?,=20add=20links=20to=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 68e8198a8..f17e89342 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,7 @@ ## Latest Changes -* ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). +* ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. New and updated docs are in the tutorial section **Custom Response - HTML, Stream, File, others**, in [RedirectResponse](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse) and in [FileResponse](https://fastapi.tiangolo.com/advanced/custom-response/#fileresponse). PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). * 🐛 Support custom OpenAPI / JSON Schema fields in the generated output OpenAPI. PR [#1429](https://github.com/tiangolo/fastapi/pull/1429) by [@jmagnusson](https://github.com/jmagnusson). ## 0.65.3 From f16c7729bd2df51eefdda0ec7af1e7bed0bef1b3 Mon Sep 17 00:00:00 2001 From: Juan Funez Date: Sun, 4 Jul 2021 14:49:31 +0200 Subject: [PATCH 063/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Spanish=20translat?= =?UTF-8?q?ion=20for=20`advanced/path-operation-advanced-configuration.md`?= =?UTF-8?q?=20(#1251)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Camila Gutierrez Co-authored-by: Sebastián Ramírez Co-authored-by: Camila Gutierrez --- .../path-operation-advanced-configuration.md | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/es/docs/advanced/path-operation-advanced-configuration.md diff --git a/docs/es/docs/advanced/path-operation-advanced-configuration.md b/docs/es/docs/advanced/path-operation-advanced-configuration.md new file mode 100644 index 000000000..e4edcc52b --- /dev/null +++ b/docs/es/docs/advanced/path-operation-advanced-configuration.md @@ -0,0 +1,52 @@ +# Configuración avanzada de las operaciones de path + +## OpenAPI operationId + +!!! warning "Advertencia" + Si no eres una persona "experta" en OpenAPI, probablemente no necesitas leer esto. + +Puedes asignar el `operationId` de OpenAPI para ser usado en tu *operación de path* con el parámetro `operation_id`. + +En este caso tendrías que asegurarte de que sea único para cada operación. + +```Python hl_lines="6" +{!../../../docs_src/path_operation_advanced_configuration/tutorial001.py!} +``` + +### Usando el nombre de la *función de la operación de path* en el operationId + +Si quieres usar tus nombres de funciones de API como `operationId`s, puedes iterar sobre todos ellos y sobrescribir `operation_id` de cada *operación de path* usando su `APIRoute.name`. + +Deberías hacerlo después de adicionar todas tus *operaciones de path*. + +```Python hl_lines="2 12 13 14 15 16 17 18 19 20 21 24" +{!../../../docs_src/path_operation_advanced_configuration/tutorial002.py!} +``` + +!!! tip "Consejo" + Si llamas manualmente a `app.openapi()`, debes actualizar el `operationId`s antes de hacerlo. + +!!! warning "Advertencia" + Si haces esto, debes asegurarte de que cada una de tus *funciones de las operaciones de path* tenga un nombre único. + + Incluso si están en diferentes módulos (archivos Python). + +## Excluir de OpenAPI + +Para excluir una *operación de path* del esquema OpenAPI generado (y por tanto del la documentación generada automáticamente), usa el parámetro `include_in_schema` y asigna el valor como `False`; + +```Python hl_lines="6" +{!../../../docs_src/path_operation_advanced_configuration/tutorial003.py!} +``` + +## Descripción avanzada desde el docstring + +Puedes limitar las líneas usadas desde el docstring de una *operación de path* para OpenAPI. + +Agregar un `\f` (un carácter de "form feed" escapado) hace que **FastAPI** trunque el output utilizada para OpenAPI en ese punto. + +No será mostrado en la documentación, pero otras herramientas (como Sphinx) serán capaces de usar el resto. + +```Python hl_lines="19 20 21 22 23 24 25 26 27 28 29" +{!../../../docs_src/path_operation_advanced_configuration/tutorial004.py!} +``` From 18e0828daf2ce53fef6d8cc5e0f7a905f38fc5c9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Jul 2021 12:50:02 +0000 Subject: [PATCH 064/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f17e89342..ef853d412 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Spanish translation for `advanced/path-operation-advanced-configuration.md`. PR [#1251](https://github.com/tiangolo/fastapi/pull/1251) by [@jfunez](https://github.com/jfunez). * ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. New and updated docs are in the tutorial section **Custom Response - HTML, Stream, File, others**, in [RedirectResponse](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse) and in [FileResponse](https://fastapi.tiangolo.com/advanced/custom-response/#fileresponse). PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). * 🐛 Support custom OpenAPI / JSON Schema fields in the generated output OpenAPI. PR [#1429](https://github.com/tiangolo/fastapi/pull/1429) by [@jmagnusson](https://github.com/jmagnusson). From 3d1b107d70f0bb03966fbb8b7aaac2ac33f621d3 Mon Sep 17 00:00:00 2001 From: Juan Funez Date: Sun, 4 Jul 2021 16:14:29 +0200 Subject: [PATCH 065/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Spanish=20translat?= =?UTF-8?q?ion=20for=20`advanced/additional-status-codes.md`=20(#1252)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Camila Gutierrez --- .../docs/advanced/additional-status-codes.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 docs/es/docs/advanced/additional-status-codes.md diff --git a/docs/es/docs/advanced/additional-status-codes.md b/docs/es/docs/advanced/additional-status-codes.md new file mode 100644 index 000000000..67224fb36 --- /dev/null +++ b/docs/es/docs/advanced/additional-status-codes.md @@ -0,0 +1,37 @@ +# Códigos de estado adicionales + +Por defecto, **FastAPI** devolverá las respuestas utilizando una `JSONResponse`, poniendo el contenido que devuelves en tu *operación de path* dentro de esa `JSONResponse`. + +Utilizará el código de estado por defecto, o el que hayas asignado en tu *operación de path*. + +## Códigos de estado adicionales + +Si quieres devolver códigos de estado adicionales además del principal, puedes hacerlo devolviendo directamente una `Response`, como una `JSONResponse`, y asignar directamente el código de estado adicional. + +Por ejemplo, digamos que quieres tener una *operación de path* que permita actualizar ítems y devolver códigos de estado HTTP 200 "OK" cuando sea exitosa. + +Pero también quieres que acepte nuevos ítems. Cuando los ítems no existan anteriormente, serán creados y devolverá un código de estado HTTP 201 "Created". + +Para conseguir esto importa `JSONResponse` y devuelve ahí directamente tu contenido, asignando el `status_code` que quieras: + +```Python hl_lines="2 19" +{!../../../docs_src/additional_status_codes/tutorial001.py!} +``` + +!!! warning "Advertencia" + Cuando devuelves directamente una `Response`, como en los ejemplos anteriores, será devuelta directamente. + + No será serializado con el modelo, etc. + + Asegurate de que la respuesta tenga los datos que quieras, y que los valores sean JSON válidos (si estás usando `JSONResponse`). + +!!! note "Detalles Técnicos" + También podrías utilizar `from starlette.responses import JSONResponse`. + + **FastAPI** provee las mismas `starlette.responses` que `fastapi.responses` simplemente como una convención para ti, el desarrollador. Pero la mayoría de las respuestas disponibles vienen directamente de Starlette. Lo mismo con `status`. + +## OpenAPI y documentación de API + +Si quieres devolver códigos de estado y respuestas adicionales directamente, estas no estarán incluidas en el schema de OpenAPI (documentación de API), porque FastAPI no tiene una manera de conocer de antemano lo que vas a devolver. + +Pero puedes documentar eso en tu código usando [Respuestas Adicionales](additional-responses.md){.internal-link target=_blank}. From 5fa3e239db41c35c1c5da464f0082710aa03eebb Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Jul 2021 14:15:04 +0000 Subject: [PATCH 066/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ef853d412..f59c87838 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Spanish translation for `advanced/additional-status-codes.md`. PR [#1252](https://github.com/tiangolo/fastapi/pull/1252) by [@jfunez](https://github.com/jfunez). * 🌐 Add Spanish translation for `advanced/path-operation-advanced-configuration.md`. PR [#1251](https://github.com/tiangolo/fastapi/pull/1251) by [@jfunez](https://github.com/jfunez). * ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. New and updated docs are in the tutorial section **Custom Response - HTML, Stream, File, others**, in [RedirectResponse](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse) and in [FileResponse](https://fastapi.tiangolo.com/advanced/custom-response/#fileresponse). PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). * 🐛 Support custom OpenAPI / JSON Schema fields in the generated output OpenAPI. PR [#1429](https://github.com/tiangolo/fastapi/pull/1429) by [@jmagnusson](https://github.com/jmagnusson). From c235e9b78cacbecf2275cd7b8fa770a078300f8f Mon Sep 17 00:00:00 2001 From: Juan Funez Date: Sun, 4 Jul 2021 19:06:18 +0200 Subject: [PATCH 067/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Spanish=20translat?= =?UTF-8?q?ion=20for=20`advanced/response-directly.md`=20(#1253)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Camila Gutierrez --- docs/es/docs/advanced/response-directly.md | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 docs/es/docs/advanced/response-directly.md diff --git a/docs/es/docs/advanced/response-directly.md b/docs/es/docs/advanced/response-directly.md new file mode 100644 index 000000000..54dadf576 --- /dev/null +++ b/docs/es/docs/advanced/response-directly.md @@ -0,0 +1,63 @@ +# Devolver una respuesta directamente + +Cuando creas una *operación de path* normalmente puedes devolver cualquier dato: un `dict`, una `list`, un modelo Pydantic, un modelo de base de datos, etc. + +Por defecto, **FastAPI** convertiría automáticamente ese valor devuelto a JSON usando el `jsonable_encoder` explicado en [Codificador Compatible JSON](../tutorial/encoder.md){.internal-link target=_blank}. + +Luego, tras bastidores, pondría esos datos compatibles con JSON (por ejemplo, un `dict`) dentro de una `JSONResponse` que se usaría para enviar la respuesta al cliente. + +Pero puedes devolver una `JSONResponse` directamente de tu *operación de path*. + +Esto puede ser útil, por ejemplo, para devolver cookies o headers personalizados. + +## Devolver una `Response` + +De hecho, puedes devolver cualquier `Response` o cualquier subclase de la misma. + +!!! tip "Consejo" + `JSONResponse` en sí misma es una subclase de `Response`. + +Y cuando devuelves una `Response`, **FastAPI** la pasará directamente. + +No hará ninguna conversión de datos con modelos Pydantic, no convertirá el contenido a ningún tipo, etc. + +Esto te da mucha flexibilidad. Puedes devolver cualquier tipo de dato, sobrescribir cualquer declaración de datos o validación, etc. + +## Usando el `jsonable_encoder` en una `Response` + +Como **FastAPI** no realiza ningún cambio en la `Response` que devuelves, debes asegurarte de que el contenido está listo. + +Por ejemplo, no puedes poner un modelo Pydantic en una `JSONResponse` sin primero convertirlo a un `dict` con todos los tipos de datos (como `datetime`, `UUID`, etc) convertidos a tipos compatibles con JSON. + +Para esos casos, puedes usar el `jsonable_encoder` para convertir tus datos antes de pasarlos a la respuesta: + +```Python hl_lines="4 6 20 21" +{!../../../docs_src/response_directly/tutorial001.py!} +``` + +!!! note "Detalles Técnicos" + También puedes usar `from starlette.responses import JSONResponse`. + + **FastAPI** provee `starlette.responses` como `fastapi.responses`, simplemente como una conveniencia para ti, el desarrollador. Pero la mayoría de las respuestas disponibles vienen directamente de Starlette. + +## Devolviendo una `Response` personalizada + +El ejemplo anterior muestra las partes que necesitas, pero no es muy útil todavía, dado que podrías simplemente devolver el `item` directamente, y **FastAPI** lo pondría en una `JSONResponse` por ti, convirtiéndolo en un `dict`, etc. Todo esto por defecto. + +Ahora, veamos cómo puedes usarlo para devolver una respuesta personalizada. + +Digamos que quieres devolver una respuesta XML. + +Podrías poner tu contenido XML en un string, ponerlo en una `Response` y devolverlo: + +```Python hl_lines="1 18" +{!../../../docs_src/response_directly/tutorial002.py!} +``` + +## Notas + +Cuando devuelves una `Response` directamente, los datos no son validados, convertidos (serializados), ni documentados automáticamente. + +Pero todavía es posible documentarlo como es descrito en [Respuestas adicionales en OpenAPI](additional-responses.md){.internal-link target=_blank}. + +Puedes ver en secciones posteriores como usar/declarar esas `Response`s personalizadas aún teniendo conversión automática de datos, documentación, etc. From a4d0724a97b4e16a0fa8be41c0d7d2b086bf1412 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Jul 2021 17:06:51 +0000 Subject: [PATCH 068/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f59c87838..5b2d67700 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Spanish translation for `advanced/response-directly.md`. PR [#1253](https://github.com/tiangolo/fastapi/pull/1253) by [@jfunez](https://github.com/jfunez). * 🌐 Add Spanish translation for `advanced/additional-status-codes.md`. PR [#1252](https://github.com/tiangolo/fastapi/pull/1252) by [@jfunez](https://github.com/jfunez). * 🌐 Add Spanish translation for `advanced/path-operation-advanced-configuration.md`. PR [#1251](https://github.com/tiangolo/fastapi/pull/1251) by [@jfunez](https://github.com/jfunez). * ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. New and updated docs are in the tutorial section **Custom Response - HTML, Stream, File, others**, in [RedirectResponse](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse) and in [FileResponse](https://fastapi.tiangolo.com/advanced/custom-response/#fileresponse). PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). From 6ebf60b17582db1a6a1f74b12ea629a9090fb6c4 Mon Sep 17 00:00:00 2001 From: Camila Gutierrez Date: Sun, 4 Jul 2021 19:34:46 +0200 Subject: [PATCH 069/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Spanish=20translat?= =?UTF-8?q?ion=20for=20`tutorial/query-params.md`=20(#2243)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/es/docs/tutorial/query-params.md | 197 ++++++++++++++++++++++++++ docs/es/mkdocs.yml | 1 + 2 files changed, 198 insertions(+) create mode 100644 docs/es/docs/tutorial/query-params.md diff --git a/docs/es/docs/tutorial/query-params.md b/docs/es/docs/tutorial/query-params.md new file mode 100644 index 000000000..69caee6e8 --- /dev/null +++ b/docs/es/docs/tutorial/query-params.md @@ -0,0 +1,197 @@ +# Parámetros de query + +Cuando declaras otros parámetros de la función que no hacen parte de los parámetros de path estos se interpretan automáticamente como parámetros de "query". + +```Python hl_lines="9" +{!../../../docs_src/query_params/tutorial001.py!} +``` + +El query es el conjunto de pares de key-value que van después del `?` en la URL, separados por caracteres `&`. + +Por ejemplo, en la URL: + +``` +http://127.0.0.1:8000/items/?skip=0&limit=10 +``` + +...los parámetros de query son: + +* `skip`: con un valor de `0` +* `limit`: con un valor de `10` + +Dado que son parte de la URL son strings "naturalmente". + +Pero cuando los declaras con tipos de Python (en el ejemplo arriba, como `int`) son convertidos a ese tipo y son validados con él. + +Todo el proceso que aplicaba a los parámetros de path también aplica a los parámetros de query: + +* Soporte del editor (obviamente) +* "Parsing" de datos +* Validación de datos +* Documentación automática + +## Configuraciones por defecto + +Como los parámetros de query no están fijos en una parte del path pueden ser opcionales y pueden tener valores por defecto. + +El ejemplo arriba tiene `skip=0` y `limit=10` como los valores por defecto. + +Entonces, si vas a la URL: + +``` +http://127.0.0.1:8000/items/ +``` + +Sería lo mismo que ir a: + +``` +http://127.0.0.1:8000/items/?skip=0&limit=10 +``` + +Pero, si por ejemplo vas a: + +``` +http://127.0.0.1:8000/items/?skip=20 +``` + +Los valores de los parámetros en tu función serán: + +* `skip=20`: porque lo definiste en la URL +* `limit=10`: porque era el valor por defecto + +## Parámetros opcionales + +Del mismo modo puedes declarar parámetros de query opcionales definiendo el valor por defecto como `None`: + +```Python hl_lines="9" +{!../../../docs_src/query_params/tutorial002.py!} +``` + +En este caso el parámetro de la función `q` será opcional y será `None` por defecto. + +!!! check "Revisa" + También puedes notar que **FastAPI** es lo suficientemente inteligente para darse cuenta de que el parámetro de path `item_id` es un parámetro de path y que `q` no lo es, y por lo tanto es un parámetro de query. + +!!! note "Nota" + FastAPI sabrá que `q` es opcional por el `= None`. + + El `Optional` en `Optional[str]` no es usado por FastAPI (FastAPI solo usará la parte `str`), pero el `Optional[str]` le permitirá a tu editor ayudarte a encontrar errores en tu código. + +## Conversión de tipos de parámetros de query + +También puedes declarar tipos `bool` y serán convertidos: + +```Python hl_lines="9" +{!../../../docs_src/query_params/tutorial003.py!} +``` + +En este caso, si vas a: + +``` +http://127.0.0.1:8000/items/foo?short=1 +``` + +o + +``` +http://127.0.0.1:8000/items/foo?short=True +``` + +o + +``` +http://127.0.0.1:8000/items/foo?short=true +``` + +o + +``` +http://127.0.0.1:8000/items/foo?short=on +``` + +o + +``` +http://127.0.0.1:8000/items/foo?short=yes +``` + +o cualquier otra variación (mayúsculas, primera letra en mayúscula, etc.) tu función verá el parámetro `short` con un valor `bool` de `True`. Si no, lo verá como `False`. + +## Múltiples parámetros de path y query + +Puedes declarar múltiples parámetros de path y parámetros de query al mismo tiempo. **FastAPI** sabe cuál es cuál. + +No los tienes que declarar en un orden específico. + +Serán detectados por nombre: + +```Python hl_lines="8 10" +{!../../../docs_src/query_params/tutorial004.py!} +``` + +## Parámetros de query requeridos + +Cuando declaras un valor por defecto para los parámetros que no son de path (por ahora solo hemos visto parámetros de query), entonces no es requerido. + +Si no quieres añadir un valor específico sino solo hacerlo opcional, pon el valor por defecto como `None`. + +Pero cuando quieres hacer que un parámetro de query sea requerido, puedes simplemente no declararle un valor por defecto: + +```Python hl_lines="6-7" +{!../../../docs_src/query_params/tutorial005.py!} +``` + +Aquí el parámetro de query `needy` es un parámetro de query requerido, del tipo `str`. + +Si abres tu navegador en una URL como: + +``` +http://127.0.0.1:8000/items/foo-item +``` + +...sin añadir el parámetro `needy` requerido, verás un error como: + +```JSON +{ + "detail": [ + { + "loc": [ + "query", + "needy" + ], + "msg": "field required", + "type": "value_error.missing" + } + ] +} +``` + +Dado que `needy` es un parámetro requerido necesitarías declararlo en la URL: + +``` +http://127.0.0.1:8000/items/foo-item?needy=sooooneedy +``` + +...esto funcionaría: + +```JSON +{ + "item_id": "foo-item", + "needy": "sooooneedy" +} +``` + +Por supuesto que también puedes definir algunos parámetros como requeridos, con un valor por defecto y otros completamente opcionales: + +```Python hl_lines="10" +{!../../../docs_src/query_params/tutorial006.py!} +``` + +En este caso hay 3 parámetros de query: + +* `needy`, un `str` requerido. +* `skip`, un `int` con un valor por defecto de `0`. +* `limit`, un `int` opcional. + +!!! tip "Consejo" + También podrías usar los `Enum`s de la misma manera que con los [Parámetros de path](path-params.md#predefined-values){.internal-link target=_blank}. diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 292cb5491..787decd1f 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -58,6 +58,7 @@ nav: - tutorial/index.md - tutorial/first-steps.md - tutorial/path-params.md + - tutorial/query-params.md - Guía de Usuario Avanzada: - advanced/index.md - async.md From dcfa9eb8fe6ac27fd0a79f6448d83174b629a75b Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Jul 2021 17:35:19 +0000 Subject: [PATCH 070/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5b2d67700..0cde3585d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Spanish translation for `tutorial/query-params.md`. PR [#2243](https://github.com/tiangolo/fastapi/pull/2243) by [@mariacamilagl](https://github.com/mariacamilagl). * 🌐 Add Spanish translation for `advanced/response-directly.md`. PR [#1253](https://github.com/tiangolo/fastapi/pull/1253) by [@jfunez](https://github.com/jfunez). * 🌐 Add Spanish translation for `advanced/additional-status-codes.md`. PR [#1252](https://github.com/tiangolo/fastapi/pull/1252) by [@jfunez](https://github.com/jfunez). * 🌐 Add Spanish translation for `advanced/path-operation-advanced-configuration.md`. PR [#1251](https://github.com/tiangolo/fastapi/pull/1251) by [@jfunez](https://github.com/jfunez). From 0e0931d3082cd44f56f13617b1d76b5dab87eaff Mon Sep 17 00:00:00 2001 From: Rubikoid Date: Sun, 4 Jul 2021 21:53:40 +0300 Subject: [PATCH 071/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20include/exclude=20?= =?UTF-8?q?for=20dicts=20in=20`jsonable=5Fencoder`=20(#2016)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/encoders.py | 4 +- tests/test_response_model_include_exclude.py | 174 +++++++++++++++++++ 2 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 tests/test_response_model_include_exclude.py diff --git a/fastapi/encoders.py b/fastapi/encoders.py index 6a2a75dda..51cab419d 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -36,9 +36,9 @@ def jsonable_encoder( custom_encoder: Dict[Any, Callable[[Any], Any]] = {}, sqlalchemy_safe: bool = True, ) -> Any: - if include is not None and not isinstance(include, set): + if include is not None and not isinstance(include, (set, dict)): include = set(include) - if exclude is not None and not isinstance(exclude, set): + if exclude is not None and not isinstance(exclude, (set, dict)): exclude = set(exclude) if isinstance(obj, BaseModel): encoder = getattr(obj.__config__, "json_encoders", {}) diff --git a/tests/test_response_model_include_exclude.py b/tests/test_response_model_include_exclude.py new file mode 100644 index 000000000..533f8105b --- /dev/null +++ b/tests/test_response_model_include_exclude.py @@ -0,0 +1,174 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient +from pydantic import BaseModel + + +class Test(BaseModel): + foo: str + bar: str + + +class Test2(BaseModel): + test: Test + baz: str + + +class Test3(BaseModel): + name: str + age: int + test2: Test2 + + +app = FastAPI() + + +@app.get( + "/simple_include", + response_model=Test2, + response_model_include={"baz": ..., "test": {"foo"}}, +) +def simple_include(): + return Test2( + test=Test(foo="simple_include test foo", bar="simple_include test bar"), + baz="simple_include test2 baz", + ) + + +@app.get( + "/simple_include_dict", + response_model=Test2, + response_model_include={"baz": ..., "test": {"foo"}}, +) +def simple_include_dict(): + return { + "test": { + "foo": "simple_include_dict test foo", + "bar": "simple_include_dict test bar", + }, + "baz": "simple_include_dict test2 baz", + } + + +@app.get( + "/simple_exclude", + response_model=Test2, + response_model_exclude={"test": {"bar"}}, +) +def simple_exclude(): + return Test2( + test=Test(foo="simple_exclude test foo", bar="simple_exclude test bar"), + baz="simple_exclude test2 baz", + ) + + +@app.get( + "/simple_exclude_dict", + response_model=Test2, + response_model_exclude={"test": {"bar"}}, +) +def simple_exclude_dict(): + return { + "test": { + "foo": "simple_exclude_dict test foo", + "bar": "simple_exclude_dict test bar", + }, + "baz": "simple_exclude_dict test2 baz", + } + + +@app.get( + "/mixed", + response_model=Test3, + response_model_include={"test2", "name"}, + response_model_exclude={"test2": {"baz"}}, +) +def mixed(): + return Test3( + name="mixed test3 name", + age=3, + test2=Test2( + test=Test(foo="mixed test foo", bar="mixed test bar"), baz="mixed test2 baz" + ), + ) + + +@app.get( + "/mixed_dict", + response_model=Test3, + response_model_include={"test2", "name"}, + response_model_exclude={"test2": {"baz"}}, +) +def mixed_dict(): + return { + "name": "mixed_dict test3 name", + "age": 3, + "test2": { + "test": {"foo": "mixed_dict test foo", "bar": "mixed_dict test bar"}, + "baz": "mixed_dict test2 baz", + }, + } + + +client = TestClient(app) + + +def test_nested_include_simple(): + response = client.get("/simple_include") + + assert response.status_code == 200, response.text + + assert response.json() == { + "baz": "simple_include test2 baz", + "test": {"foo": "simple_include test foo"}, + } + + +def test_nested_include_simple_dict(): + response = client.get("/simple_include_dict") + + assert response.status_code == 200, response.text + + assert response.json() == { + "baz": "simple_include_dict test2 baz", + "test": {"foo": "simple_include_dict test foo"}, + } + + +def test_nested_exclude_simple(): + response = client.get("/simple_exclude") + assert response.status_code == 200, response.text + assert response.json() == { + "baz": "simple_exclude test2 baz", + "test": {"foo": "simple_exclude test foo"}, + } + + +def test_nested_exclude_simple_dict(): + response = client.get("/simple_exclude_dict") + assert response.status_code == 200, response.text + assert response.json() == { + "baz": "simple_exclude_dict test2 baz", + "test": {"foo": "simple_exclude_dict test foo"}, + } + + +def test_nested_include_mixed(): + response = client.get("/mixed") + assert response.status_code == 200, response.text + assert response.json() == { + "name": "mixed test3 name", + "test2": { + "test": {"foo": "mixed test foo", "bar": "mixed test bar"}, + }, + } + + +def test_nested_include_mixed_dict(): + response = client.get("/mixed_dict") + assert response.status_code == 200, response.text + assert response.json() == { + "name": "mixed_dict test3 name", + "test2": { + "test": {"foo": "mixed_dict test foo", "bar": "mixed_dict test bar"}, + }, + } From 0c4ded88fe2e6b6911321c1ca679605b96a7acd2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Jul 2021 18:54:19 +0000 Subject: [PATCH 072/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0cde3585d..f6560fd91 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix include/exclude for dicts in `jsonable_encoder`. PR [#2016](https://github.com/tiangolo/fastapi/pull/2016) by [@Rubikoid](https://github.com/Rubikoid). * 🌐 Add Spanish translation for `tutorial/query-params.md`. PR [#2243](https://github.com/tiangolo/fastapi/pull/2243) by [@mariacamilagl](https://github.com/mariacamilagl). * 🌐 Add Spanish translation for `advanced/response-directly.md`. PR [#1253](https://github.com/tiangolo/fastapi/pull/1253) by [@jfunez](https://github.com/jfunez). * 🌐 Add Spanish translation for `advanced/additional-status-codes.md`. PR [#1252](https://github.com/tiangolo/fastapi/pull/1252) by [@jfunez](https://github.com/jfunez). From d27a218bc3b836a5ca30190ba99ccf8eb5917f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 4 Jul 2021 20:58:49 +0200 Subject: [PATCH 073/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f6560fd91..b2137e600 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,13 +2,21 @@ ## Latest Changes +### Features + +* ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. New and updated docs are in the tutorial section **Custom Response - HTML, Stream, File, others**, in [RedirectResponse](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse) and in [FileResponse](https://fastapi.tiangolo.com/advanced/custom-response/#fileresponse). PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). + +### Fixes + * 🐛 Fix include/exclude for dicts in `jsonable_encoder`. PR [#2016](https://github.com/tiangolo/fastapi/pull/2016) by [@Rubikoid](https://github.com/Rubikoid). +* 🐛 Support custom OpenAPI / JSON Schema fields in the generated output OpenAPI. PR [#1429](https://github.com/tiangolo/fastapi/pull/1429) by [@jmagnusson](https://github.com/jmagnusson). + +### Translations + * 🌐 Add Spanish translation for `tutorial/query-params.md`. PR [#2243](https://github.com/tiangolo/fastapi/pull/2243) by [@mariacamilagl](https://github.com/mariacamilagl). * 🌐 Add Spanish translation for `advanced/response-directly.md`. PR [#1253](https://github.com/tiangolo/fastapi/pull/1253) by [@jfunez](https://github.com/jfunez). * 🌐 Add Spanish translation for `advanced/additional-status-codes.md`. PR [#1252](https://github.com/tiangolo/fastapi/pull/1252) by [@jfunez](https://github.com/jfunez). * 🌐 Add Spanish translation for `advanced/path-operation-advanced-configuration.md`. PR [#1251](https://github.com/tiangolo/fastapi/pull/1251) by [@jfunez](https://github.com/jfunez). -* ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. New and updated docs are in the tutorial section **Custom Response - HTML, Stream, File, others**, in [RedirectResponse](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse) and in [FileResponse](https://fastapi.tiangolo.com/advanced/custom-response/#fileresponse). PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). -* 🐛 Support custom OpenAPI / JSON Schema fields in the generated output OpenAPI. PR [#1429](https://github.com/tiangolo/fastapi/pull/1429) by [@jmagnusson](https://github.com/jmagnusson). ## 0.65.3 From 7e9d5aacf8044728e09e6c16e4104fc96b8cea28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 4 Jul 2021 20:59:46 +0200 Subject: [PATCH 074/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.66?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b2137e600..9e5c7dd77 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.66.0 + ### Features * ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. New and updated docs are in the tutorial section **Custom Response - HTML, Stream, File, others**, in [RedirectResponse](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse) and in [FileResponse](https://fastapi.tiangolo.com/advanced/custom-response/#fileresponse). PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 66a63d369..9ac36997f 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.65.3" +__version__ = "0.66.0" from starlette import status as status From dfd453e001779e1c31b7484615851f4289180215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 4 Jul 2021 21:18:45 +0200 Subject: [PATCH 075/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9e5c7dd77..771797543 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,7 +7,7 @@ ### Features -* ✨ Allow setting the `response_class` to `RedirectResponse` and returning the URL from the function. New and updated docs are in the tutorial section **Custom Response - HTML, Stream, File, others**, in [RedirectResponse](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse) and in [FileResponse](https://fastapi.tiangolo.com/advanced/custom-response/#fileresponse). PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). +* ✨ Allow setting the `response_class` to `RedirectResponse` or `FileResponse` and returning the URL from the function. New and updated docs are in the tutorial section **Custom Response - HTML, Stream, File, others**, in [RedirectResponse](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse) and in [FileResponse](https://fastapi.tiangolo.com/advanced/custom-response/#fileresponse). PR [#3457](https://github.com/tiangolo/fastapi/pull/3457) by [@tiangolo](https://github.com/tiangolo). ### Fixes From 8cc6f9baac8342e7057e13161f9b73f3baa26e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 5 Jul 2021 13:45:03 +0200 Subject: [PATCH 076/814] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20python-j?= =?UTF-8?q?ose=20dependency=20for=20tests=20(#3468)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 25440bde4..dcb03504c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,7 +73,7 @@ doc = [ "pyyaml >=5.3.1,<6.0.0" ] dev = [ - "python-jose[cryptography] >=3.1.0,<4.0.0", + "python-jose[cryptography] >=3.3.0,<4.0.0", "passlib[bcrypt] >=1.7.2,<2.0.0", "autoflake >=1.3.1,<2.0.0", "flake8 >=3.8.3,<4.0.0", From e721d0435080ad339188bb8519c53c07e59ed859 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 5 Jul 2021 11:45:43 +0000 Subject: [PATCH 077/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 771797543..6db010fdd 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade python-jose dependency for tests. PR [#3468](https://github.com/tiangolo/fastapi/pull/3468) by [@tiangolo](https://github.com/tiangolo). ## 0.66.0 From 3d6da2c32db2d0761f0d165e140559c3478ea677 Mon Sep 17 00:00:00 2001 From: Lucas <61513630+lsglucas@users.noreply.github.com> Date: Mon, 19 Jul 2021 09:32:54 -0300 Subject: [PATCH 078/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/deployment/index.md`=20(#3337)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/pt/docs/deployment/index.md | 7 +++++++ docs/pt/mkdocs.yml | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 docs/pt/docs/deployment/index.md diff --git a/docs/pt/docs/deployment/index.md b/docs/pt/docs/deployment/index.md new file mode 100644 index 000000000..1ff0e44a0 --- /dev/null +++ b/docs/pt/docs/deployment/index.md @@ -0,0 +1,7 @@ +# Implantação - Introdução + +A implantação de uma aplicação **FastAPI** é relativamente simples. + +Existem várias maneiras para fazer isso, dependendo do seu caso específico e das ferramentas que você utiliza. + +Você verá mais detalhes para se ter em mente e algumas das técnicas para a implantação nas próximas seções. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 27c1f706b..d40f1a261 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -57,6 +57,8 @@ nav: - tutorial/index.md - tutorial/first-steps.md - tutorial/body-fields.md +- Implantação: + - deployment/index.md - alternatives.md - history-design-future.md - external-links.md From 50baf5e80427103feeb330cbee878e1e18509b93 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 19 Jul 2021 12:33:34 +0000 Subject: [PATCH 079/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6db010fdd..c1855d024 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/deployment/index.md`. PR [#3337](https://github.com/tiangolo/fastapi/pull/3337) by [@lsglucas](https://github.com/lsglucas). * ⬆️ Upgrade python-jose dependency for tests. PR [#3468](https://github.com/tiangolo/fastapi/pull/3468) by [@tiangolo](https://github.com/tiangolo). ## 0.66.0 From 0876d3df1d2083e127b26c717e976806162553d5 Mon Sep 17 00:00:00 2001 From: oandersonmagalhaes <83456692+oandersonmagalhaes@users.noreply.github.com> Date: Mon, 19 Jul 2021 09:46:39 -0300 Subject: [PATCH 080/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/tutorial/security/index.md`=20(#3507)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Izabela Guerreiro Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/security/index.md | 101 ++++++++++++++++++++++++ docs/pt/mkdocs.yml | 2 + 2 files changed, 103 insertions(+) create mode 100644 docs/pt/docs/tutorial/security/index.md diff --git a/docs/pt/docs/tutorial/security/index.md b/docs/pt/docs/tutorial/security/index.md new file mode 100644 index 000000000..70f864040 --- /dev/null +++ b/docs/pt/docs/tutorial/security/index.md @@ -0,0 +1,101 @@ +# Introdução à segurança + +Há várias formas de lidar segurança, autenticação e autorização. + +E isso normalmente é um tópico “difícil” e complexo. + +Em muitos frameworks e sistemas, apenas lidar com segurança e autenticação exige muito esforço e código (em muitos casos isso pode ser 50% ou mais de todo o código escrito). + +**FastAPI** tem muitas ferramentas para ajudar você com a parte de **Segurança** facilmente, rapidamente, de uma forma padrão, sem ter que estudar e aprender tudo sobre especificações de segurança. + +Mas primeiro, vamos verificar alguns pequenos conceitos. + +## Está com pressa? + +Se você não se importa com qualquer um desses termos e só precisa adicionar segurança com autenticação baseada em usuário e senha _agora_, pule para os próximos capítulos. + +## OAuth2 + +OAuth2 é uma especificação que define várias formas para lidar com autenticação e autorização. + +Ela é bastante extensiva na especificação e cobre casos de uso muito complexos. + +Ela inclui uma forma para autenticação usando “third party”/aplicações de terceiros. + +Isso é o que todos os sistemas com “Login with Facebook, Google, Twitter, GitHub” usam por baixo. + +### OAuth 1 + +Havia um OAuth 1, que é bem diferente do OAuth2, e mais complexo, isso incluía diretamente as especificações de como criptografar a comunicação. + +Não é muito popular ou usado nos dias atuais. + +OAuth2 não especifica como criptografar a comunicação, ele espera que você tenha sua aplicação em um servidor HTTPS. + +!!! tip "Dica" + Na seção sobre **deployment** você irá ver como configurar HTTPS de modo gratuito, usando Traefik e Let’s Encrypt. + + +## OpenID Connect + +OpenID Connect é outra especificação, baseada em **OAuth2**. + +Ela é apenas uma extensão do OAuth2 especificando algumas coisas que são relativamente ambíguas no OAuth2, para tentar torná-lo mais interoperável. + +Por exemplo, o login do Google usa OpenID Connect (que por baixo dos panos usa OAuth2). + +Mas o login do Facebook não tem suporte para OpenID Connect. Ele tem a própria implementação do OAuth2. + +### OpenID (não "OpenID Connect") + +Houve também uma especificação “OpenID”. Ela tentou resolver a mesma coisa que a **OpenID Connect**, mas não baseada em OAuth2. + +Então, ela foi um sistema adicional completo. + +Ela não é muito popular ou usada nos dias de hoje. + +## OpenAPI + +OpenAPI (anteriormente conhecido como Swagger) é a especificação aberta para a criação de APIs (agora parte da Linux Foundation). + +**FastAPI** é baseado no **OpenAPI**. + +Isso é o que torna possível ter múltiplas automações interativas de interfaces de documentação, geração de código, etc. + +OpenAPI tem uma forma para definir múltiplos “esquemas” de segurança. + +Por usá-los, você pode ter vantagens de todas essas ferramentas baseadas nos padrões, incluindo os sistemas de documentação interativa. + +OpenAPI define os seguintes esquemas de segurança: + +* `apiKey`: uma chave específica de aplicação que pode vir de: + * Um parâmetro query. + * Um header. + * Um cookie. +* `http`: padrão HTTP de sistemas autenticação, incluindo: + * `bearer`: um header de `Authorization` com valor de `Bearer` adicionado de um token. Isso é herança do OAuth2. + * HTTP Basic authentication. + * HTTP Digest, etc. +* `oauth2`: todas as formas do OAuth2 para lidar com segurança (chamados "fluxos"). + * Vários desses fluxos são apropriados para construir um provedor de autenticação OAuth2 (como Google, Facebook, Twitter, GitHub, etc): + * `implicit` + * `clientCredentials` + * `authorizationCode` + * Mas existe um “fluxo” específico que pode ser perfeitamente usado para resolver autenticação diretamente na mesma aplicação: + * `password`: alguns dos próximos capítulos tratarão disso. +* `openIdConnect`: tem uma forma para definir como descobrir automaticamente o dado da autenticação OAuth2. + * Essa descoberta automática é o que é definido na especificação OpenID Connect. + + +!!! tip "Dica" + Integração com outros provedores de autenticação/autorização como Google, Facebook, Twitter, GitHub, etc. é bem possível e relativamente fácil. + + O problema mais complexo é criar um provedor de autenticação/autorização como eles, mas o FastAPI dá a você ferramentas para fazer isso facilmente, enquanto faz o trabalho pesado para você. + +## **FastAPI** utilitários + +**FastAPI** fornece várias ferramentas para cada um desses esquemas de segurança no módulo `fastapi.security` que simplesmente usa esses mecanismos de segurança. + +Nos próximos capítulos você irá ver como adicionar segurança à sua API usando essas ferramentas disponibilizadas pelo **FastAPI**. + +E você irá ver também como isso é automaticamente integrado dentro do sistema de documentação interativo. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index d40f1a261..e4f3a62d9 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -57,6 +57,8 @@ nav: - tutorial/index.md - tutorial/first-steps.md - tutorial/body-fields.md + - Segurança: + - tutorial/security/index.md - Implantação: - deployment/index.md - alternatives.md From 163b086f2193a77221918e7c90ff62abdde6399d Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 19 Jul 2021 12:47:20 +0000 Subject: [PATCH 081/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c1855d024..67b45980f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/tutorial/security/index.md`. PR [#3507](https://github.com/tiangolo/fastapi/pull/3507) by [@oandersonmagalhaes](https://github.com/oandersonmagalhaes). * 🌐 Add Portuguese translation for `docs/deployment/index.md`. PR [#3337](https://github.com/tiangolo/fastapi/pull/3337) by [@lsglucas](https://github.com/lsglucas). * ⬆️ Upgrade python-jose dependency for tests. PR [#3468](https://github.com/tiangolo/fastapi/pull/3468) by [@tiangolo](https://github.com/tiangolo). From 5342a0a00f1e1d7a69ec4cb77ec6ac47deecabc9 Mon Sep 17 00:00:00 2001 From: Mark H <7569289+0x4Dark@users.noreply.github.com> Date: Mon, 19 Jul 2021 14:49:09 +0200 Subject: [PATCH 082/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20basic=20setup=20fo?= =?UTF-8?q?r=20German=20translations=20(#3522)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/de/docs/index.md | 467 +++++++++++++++++++++++++++++++++++ docs/de/mkdocs.yml | 125 ++++++++++ docs/de/overrides/.gitignore | 0 docs/en/mkdocs.yml | 3 + docs/es/mkdocs.yml | 3 + docs/fr/mkdocs.yml | 3 + docs/id/mkdocs.yml | 6 + docs/it/mkdocs.yml | 3 + docs/ja/mkdocs.yml | 3 + docs/ko/mkdocs.yml | 3 + docs/pl/mkdocs.yml | 6 + docs/pt/mkdocs.yml | 3 + docs/ru/mkdocs.yml | 3 + docs/sq/mkdocs.yml | 3 + docs/tr/mkdocs.yml | 3 + docs/uk/mkdocs.yml | 3 + docs/zh/mkdocs.yml | 3 + 17 files changed, 640 insertions(+) create mode 100644 docs/de/docs/index.md create mode 100644 docs/de/mkdocs.yml create mode 100644 docs/de/overrides/.gitignore diff --git a/docs/de/docs/index.md b/docs/de/docs/index.md new file mode 100644 index 000000000..3b8bb6371 --- /dev/null +++ b/docs/de/docs/index.md @@ -0,0 +1,467 @@ + +{!../../../docs/missing-translation.md!} + + +

+ FastAPI +

+

+ FastAPI framework, high performance, easy to learn, fast to code, ready for production +

+

+ + Test + + + Coverage + + + Package version + +

+ +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: https://github.com/tiangolo/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. + +The key features are: + +* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). + +* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * +* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. + +* estimation based on tests on an internal development team, building production applications. + +## Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + +## Opinions + +"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" + +
Kabir Khan - Microsoft (ref)
+ +--- + +"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" + +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
+ +--- + +"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" + +
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
+ +--- + +"_I’m over the moon excited about **FastAPI**. It’s so fun!_" + +
Brian Okken - Python Bytes podcast host (ref)
+ +--- + +"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" + +
Timothy Crosley - Hug creator (ref)
+ +--- + +"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" + +"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" + +
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +## **Typer**, the FastAPI of CLIs + + + +If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. + +**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 + +## Requirements + +Python 3.6+ + +FastAPI stands on the shoulders of giants: + +* Starlette for the web parts. +* Pydantic for the data parts. + +## Installation + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+ +You will also need an ASGI server, for production such as Uvicorn or Hypercorn. + +
+ +```console +$ pip install uvicorn[standard] + +---> 100% +``` + +
+ +## Example + +### Create it + +* Create a file `main.py` with: + +```Python +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +
+Or use async def... + +If your code uses `async` / `await`, use `async def`: + +```Python hl_lines="9 14" +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +**Note**: + +If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. + +
+ +### Run it + +Run the server with: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+About the command uvicorn main:app --reload... + +The command `uvicorn main:app` refers to: + +* `main`: the file `main.py` (the Python "module"). +* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. +* `--reload`: make the server restart after code changes. Only do this for development. + +
+ +### Check it + +Open your browser at http://127.0.0.1:8000/items/5?q=somequery. + +You will see the JSON response as: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +You already created an API that: + +* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. +* Both _paths_ take `GET` operations (also known as HTTP _methods_). +* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. +* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. + +### Interactive API docs + +Now go to http://127.0.0.1:8000/docs. + +You will see the automatic interactive API documentation (provided by Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Alternative API docs + +And now, go to http://127.0.0.1:8000/redoc. + +You will see the alternative automatic documentation (provided by ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Example upgrade + +Now modify the file `main.py` to receive a body from a `PUT` request. + +Declare the body using standard Python types, thanks to Pydantic. + +```Python hl_lines="4 9-12 25-27" +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Optional[bool] = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} +``` + +The server should reload automatically (because you added `--reload` to the `uvicorn` command above). + +### Interactive API docs upgrade + +Now go to http://127.0.0.1:8000/docs. + +* The interactive API documentation will be automatically updated, including the new body: + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) + +* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) + +### Alternative API docs upgrade + +And now, go to http://127.0.0.1:8000/redoc. + +* The alternative documentation will also reflect the new query parameter and body: + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Recap + +In summary, you declare **once** the types of parameters, body, etc. as function parameters. + +You do that with standard modern Python types. + +You don't have to learn a new syntax, the methods or classes of a specific library, etc. + +Just standard **Python 3.6+**. + +For example, for an `int`: + +```Python +item_id: int +``` + +or for a more complex `Item` model: + +```Python +item: Item +``` + +...and with that single declaration you get: + +* Editor support, including: + * Completion. + * Type checks. +* Validation of data: + * Automatic and clear errors when the data is invalid. + * Validation even for deeply nested JSON objects. +* Conversion of input data: coming from the network to Python data and types. Reading from: + * JSON. + * Path parameters. + * Query parameters. + * Cookies. + * Headers. + * Forms. + * Files. +* Conversion of output data: converting from Python data and types to network data (as JSON): + * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). + * `datetime` objects. + * `UUID` objects. + * Database models. + * ...and many more. +* Automatic interactive API documentation, including 2 alternative user interfaces: + * Swagger UI. + * ReDoc. + +--- + +Coming back to the previous code example, **FastAPI** will: + +* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. +* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. + * If it is not, the client will see a useful, clear error. +* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. + * As the `q` parameter is declared with `= None`, it is optional. + * Without the `None` it would be required (as is the body in the case with `PUT`). +* For `PUT` requests to `/items/{item_id}`, Read the body as JSON: + * Check that it has a required attribute `name` that should be a `str`. + * Check that it has a required attribute `price` that has to be a `float`. + * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. + * All this would also work for deeply nested JSON objects. +* Convert from and to JSON automatically. +* Document everything with OpenAPI, that can be used by: + * Interactive documentation systems. + * Automatic client code generation systems, for many languages. +* Provide 2 interactive documentation web interfaces directly. + +--- + +We just scratched the surface, but you already get the idea of how it all works. + +Try changing the line with: + +```Python + return {"item_name": item.name, "item_id": item_id} +``` + +...from: + +```Python + ... "item_name": item.name ... +``` + +...to: + +```Python + ... "item_price": item.price ... +``` + +...and see how your editor will auto-complete the attributes and know their types: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +For a more complete example including more features, see the Tutorial - User Guide. + +**Spoiler alert**: the tutorial - user guide includes: + +* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. +* How to set **validation constraints** as `maximum_length` or `regex`. +* A very powerful and easy to use **Dependency Injection** system. +* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. +* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). +* Many extra features (thanks to Starlette) as: + * **WebSockets** + * **GraphQL** + * extremely easy tests based on `requests` and `pytest` + * **CORS** + * **Cookie Sessions** + * ...and more. + +## Performance + +Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) + +To understand more about it, see the section Benchmarks. + +## Optional Dependencies + +Used by Pydantic: + +* ujson - for faster JSON "parsing". +* email_validator - for email validation. + +Used by Starlette: + +* requests - Required if you want to use the `TestClient`. +* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. +* jinja2 - Required if you want to use the default template configuration. +* python-multipart - Required if you want to support form "parsing", with `request.form()`. +* itsdangerous - Required for `SessionMiddleware` support. +* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). +* graphene - Required for `GraphQLApp` support. +* ujson - Required if you want to use `UJSONResponse`. + +Used by FastAPI / Starlette: + +* uvicorn - for the server that loads and serves your application. +* orjson - Required if you want to use `ORJSONResponse`. + +You can install all of these with `pip install fastapi[all]`. + +## License + +This project is licensed under the terms of the MIT license. diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml new file mode 100644 index 000000000..a00316687 --- /dev/null +++ b/docs/de/mkdocs.yml @@ -0,0 +1,125 @@ +site_name: FastAPI +site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production +site_url: https://fastapi.tiangolo.com/de/ +theme: + name: material + custom_dir: overrides + palette: + - scheme: default + primary: teal + accent: amber + toggle: + icon: material/lightbulb-outline + name: Switch to light mode + - scheme: slate + primary: teal + accent: amber + toggle: + icon: material/lightbulb + name: Switch to dark mode + features: + - search.suggest + - search.highlight + icon: + repo: fontawesome/brands/github-alt + logo: https://fastapi.tiangolo.com/img/icon-white.svg + favicon: https://fastapi.tiangolo.com/img/favicon.png + language: de +repo_name: tiangolo/fastapi +repo_url: https://github.com/tiangolo/fastapi +edit_uri: '' +google_analytics: +- UA-133183413-1 +- auto +plugins: +- search +- markdownextradata: + data: data +nav: +- FastAPI: index.md +- Languages: + - en: / + - de: /de/ + - es: /es/ + - fr: /fr/ + - id: /id/ + - it: /it/ + - ja: /ja/ + - ko: /ko/ + - pl: /pl/ + - pt: /pt/ + - ru: /ru/ + - sq: /sq/ + - tr: /tr/ + - uk: /uk/ + - zh: /zh/ +markdown_extensions: +- toc: + permalink: true +- markdown.extensions.codehilite: + guess_lang: false +- markdown_include.include: + base_path: docs +- admonition +- codehilite +- extra +- pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_div_format '' +- pymdownx.tabbed +extra: + social: + - icon: fontawesome/brands/github-alt + link: https://github.com/tiangolo/fastapi + - icon: fontawesome/brands/discord + link: https://discord.gg/VQjSZaeJmf + - icon: fontawesome/brands/twitter + link: https://twitter.com/tiangolo + - icon: fontawesome/brands/linkedin + link: https://www.linkedin.com/in/tiangolo + - icon: fontawesome/brands/dev + link: https://dev.to/tiangolo + - icon: fontawesome/brands/medium + link: https://medium.com/@tiangolo + - icon: fontawesome/solid/globe + link: https://tiangolo.com + alternate: + - link: / + name: en - English + - link: /de/ + name: de + - link: /es/ + name: es - español + - link: /fr/ + name: fr - français + - link: /id/ + name: id + - link: /it/ + name: it - italiano + - link: /ja/ + name: ja - 日本語 + - link: /ko/ + name: ko - 한국어 + - link: /pl/ + name: pl + - link: /pt/ + name: pt - português + - link: /ru/ + name: ru - русский язык + - link: /sq/ + name: sq - shqip + - link: /tr/ + name: tr - Türkçe + - link: /uk/ + name: uk - українська мова + - link: /zh/ + name: zh - 汉语 +extra_css: +- https://fastapi.tiangolo.com/css/termynal.css +- https://fastapi.tiangolo.com/css/custom.css +extra_javascript: +- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js +- https://fastapi.tiangolo.com/js/termynal.js +- https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/de/overrides/.gitignore b/docs/de/overrides/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index efb5378d1..d86ea1c39 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -190,6 +191,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 787decd1f..40c7c0ec4 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -97,6 +98,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 7ff24f8c4..3b98e3e3f 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -95,6 +96,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index 1868aac8c..ed716124f 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -39,12 +39,14 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ + - pl: /pl/ - pt: /pt/ - ru: /ru/ - sq: /sq/ @@ -86,6 +88,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ @@ -98,6 +102,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /pl/ + name: pl - link: /pt/ name: pt - português - link: /ru/ diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index 2b057b67e..11f7fe357 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -87,6 +88,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index e083de096..ee69e49f8 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -126,6 +127,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 8768d61a2..f11333f3e 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -93,6 +94,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index a2c6102b8..749d22938 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -39,8 +39,10 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ + - id: /id/ - it: /it/ - ja: /ja/ - ko: /ko/ @@ -86,10 +88,14 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ name: fr - français + - link: /id/ + name: id - link: /it/ name: it - italiano - link: /ja/ diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index e4f3a62d9..b1fa273cf 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -100,6 +101,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index ca3feedef..6db8fe33d 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -87,6 +88,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index 77de29e13..8ebf80358 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -87,6 +88,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 234aae178..660cb9238 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -87,6 +88,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index 8ecf20d17..3fdd9825e 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -87,6 +88,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 359fb4e8f..5cfc07c6c 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -39,6 +39,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - de: /de/ - es: /es/ - fr: /fr/ - id: /id/ @@ -133,6 +134,8 @@ extra: alternate: - link: / name: en - English + - link: /de/ + name: de - link: /es/ name: es - español - link: /fr/ From 71c96d9eb9052272812e28c6450b419016677895 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 19 Jul 2021 12:49:41 +0000 Subject: [PATCH 083/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 67b45980f..5f54f7892 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add basic setup for German translations. PR [#3522](https://github.com/tiangolo/fastapi/pull/3522) by [@0x4Dark](https://github.com/0x4Dark). * 🌐 Add Portuguese translation for `docs/tutorial/security/index.md`. PR [#3507](https://github.com/tiangolo/fastapi/pull/3507) by [@oandersonmagalhaes](https://github.com/oandersonmagalhaes). * 🌐 Add Portuguese translation for `docs/deployment/index.md`. PR [#3337](https://github.com/tiangolo/fastapi/pull/3337) by [@lsglucas](https://github.com/lsglucas). * ⬆️ Upgrade python-jose dependency for tests. PR [#3468](https://github.com/tiangolo/fastapi/pull/3468) by [@tiangolo](https://github.com/tiangolo). From 2d296c5d079f9fa29531fe9659581e858771c3ab Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 19 Jul 2021 20:14:58 +0100 Subject: [PATCH 084/814] =?UTF-8?q?=F0=9F=94=A7=20Configure=20strict=20pyt?= =?UTF-8?q?est=20options=20and=20update/refactor=20tests=20(#2790)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/custom-response.md | 14 ++- docs/ja/docs/advanced/custom-response.md | 2 +- docs/zh/docs/advanced/custom-response.md | 2 +- docs_src/custom_response/tutorial008.py | 7 +- pyproject.toml | 19 ++- tests/test_response_model_include_exclude.py | 111 +++++++++--------- .../test_request_files/test_tutorial001.py | 32 +++-- .../test_request_files/test_tutorial002.py | 56 ++++----- .../test_tutorial001.py | 33 +++--- 9 files changed, 147 insertions(+), 129 deletions(-) diff --git a/docs/en/docs/advanced/custom-response.md b/docs/en/docs/advanced/custom-response.md index 20b694ced..546adad2a 100644 --- a/docs/en/docs/advanced/custom-response.md +++ b/docs/en/docs/advanced/custom-response.md @@ -198,14 +198,24 @@ Takes an async generator or a normal generator/iterator and streams the response #### Using `StreamingResponse` with file-like objects -If you have a file-like object (e.g. the object returned by `open()`), you can return it in a `StreamingResponse`. +If you have a file-like object (e.g. the object returned by `open()`), you can create a generator function to iterate over that file-like object. + +That way, you don't have to read it all first in memory, and you can pass that generator function to the `StreamingResponse`, and return it. This includes many libraries to interact with cloud storage, video processing, and others. -```Python hl_lines="2 10-11" +```{ .python .annotate hl_lines="2 10-12 14" } {!../../../docs_src/custom_response/tutorial008.py!} ``` +1. This is the generator function. It's a "generator function" because it contains `yield` statements inside. +2. By using a `with` block, we make sure that the file-like object is closed after the generator function is done. So, after it finishes sending the response. +3. This `yield from` tells the function to iterate over that thing named `file_like`. And then, for each part iterated, yield that part as coming from this generator function. + + So, it is a generator function that transfers the "generating" work to something else internally. + + By doing it this way, we can put it in a `with` block, and that way, ensure that it is closed after finishing. + !!! tip Notice that here as we are using standard `open()` that doesn't support `async` and `await`, we declare the path operation with normal `def`. diff --git a/docs/ja/docs/advanced/custom-response.md b/docs/ja/docs/advanced/custom-response.md index 8d23ae2fc..d8b47629a 100644 --- a/docs/ja/docs/advanced/custom-response.md +++ b/docs/ja/docs/advanced/custom-response.md @@ -179,7 +179,7 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス これにはクラウドストレージとの連携や映像処理など、多くのライブラリが含まれています。 -```Python hl_lines="2 10-11" +```Python hl_lines="2 10-12 14" {!../../../docs_src/custom_response/tutorial008.py!} ``` diff --git a/docs/zh/docs/advanced/custom-response.md b/docs/zh/docs/advanced/custom-response.md index b67ef6c2e..5f1a74e9e 100644 --- a/docs/zh/docs/advanced/custom-response.md +++ b/docs/zh/docs/advanced/custom-response.md @@ -183,7 +183,7 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它 包括许多与云存储,视频处理等交互的库。 -```Python hl_lines="2 10 11" +```Python hl_lines="2 10-12 14" {!../../../docs_src/custom_response/tutorial008.py!} ``` diff --git a/docs_src/custom_response/tutorial008.py b/docs_src/custom_response/tutorial008.py index d33273674..fc071cbee 100644 --- a/docs_src/custom_response/tutorial008.py +++ b/docs_src/custom_response/tutorial008.py @@ -7,5 +7,8 @@ app = FastAPI() @app.get("/") def main(): - file_like = open(some_file_path, mode="rb") - return StreamingResponse(file_like, media_type="video/mp4") + def iterfile(): # (1) + with open(some_file_path, mode="rb") as file_like: # (2) + yield from file_like # (3) + + return StreamingResponse(iterfile(), media_type="video/mp4") diff --git a/pyproject.toml b/pyproject.toml index dcb03504c..45880cc31 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,8 +43,8 @@ Documentation = "https://fastapi.tiangolo.com/" [tool.flit.metadata.requires-extra] test = [ - "pytest ==5.4.3", - "pytest-cov ==2.10.0", + "pytest >=6.2.4,<7.0.0", + "pytest-cov >=2.12.0,<3.0.0", "pytest-asyncio >=0.14.0,<0.15.0", "mypy ==0.812", "flake8 >=3.8.3,<4.0.0", @@ -99,3 +99,18 @@ all = [ [tool.isort] profile = "black" known_third_party = ["fastapi", "pydantic", "starlette"] + +[tool.pytest.ini_options] +addopts = [ + "--strict-config", + "--strict-markers", +] +xfail_strict = true +junit_family = "xunit2" +filterwarnings = [ + "error", + 'ignore:"@coroutine" decorator is deprecated since Python 3\.8, use "async def" instead:DeprecationWarning', + # TODO: if these ignores are needed, enable them, otherwise remove them + # 'ignore:The explicit passing of coroutine objects to asyncio\.wait\(\) is deprecated since Python 3\.8:DeprecationWarning', + # 'ignore:Exception ignored in. ") +def test_post_file(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") client = TestClient(app) - response = client.post("/files/", files={"file": open(path, "rb")}) + with path.open("rb") as file: + response = client.post("/files/", files={"file": file}) assert response.status_code == 200, response.text assert response.json() == {"file_size": 14} -def test_post_large_file(tmpdir): +def test_post_large_file(tmp_path): default_pydantic_max_size = 2 ** 16 - path = os.path.join(tmpdir, "test.txt") - with open(path, "wb") as file: - file.write(b"x" * (default_pydantic_max_size + 1)) + path = tmp_path / "test.txt" + path.write_bytes(b"x" * (default_pydantic_max_size + 1)) client = TestClient(app) - response = client.post("/files/", files={"file": open(path, "rb")}) + with path.open("rb") as file: + response = client.post("/files/", files={"file": file}) assert response.status_code == 200, response.text assert response.json() == {"file_size": default_pydantic_max_size + 1} -def test_post_upload_file(tmpdir): - path = os.path.join(tmpdir, "test.txt") - with open(path, "wb") as file: - file.write(b"") +def test_post_upload_file(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") client = TestClient(app) - response = client.post("/uploadfile/", files={"file": open(path, "rb")}) + with path.open("rb") as file: + response = client.post("/uploadfile/", files={"file": file}) assert response.status_code == 200, response.text assert response.json() == {"filename": "test.txt"} diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py index 58fe4269f..4e33ef464 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002.py @@ -1,5 +1,3 @@ -import os - from fastapi.testclient import TestClient from docs_src.request_files.tutorial002 import app @@ -172,42 +170,40 @@ def test_post_body_json(): assert response.json() == file_required -def test_post_files(tmpdir): - path = os.path.join(tmpdir, "test.txt") - with open(path, "wb") as file: - file.write(b"") - path2 = os.path.join(tmpdir, "test2.txt") - with open(path2, "wb") as file: - file.write(b"") +def test_post_files(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") + path2 = tmp_path / "test2.txt" + path2.write_bytes(b"") client = TestClient(app) - response = client.post( - "/files/", - files=( - ("files", ("test.txt", open(path, "rb"))), - ("files", ("test2.txt", open(path2, "rb"))), - ), - ) + with path.open("rb") as file, path2.open("rb") as file2: + response = client.post( + "/files/", + files=( + ("files", ("test.txt", file)), + ("files", ("test2.txt", file2)), + ), + ) assert response.status_code == 200, response.text assert response.json() == {"file_sizes": [14, 15]} -def test_post_upload_file(tmpdir): - path = os.path.join(tmpdir, "test.txt") - with open(path, "wb") as file: - file.write(b"") - path2 = os.path.join(tmpdir, "test2.txt") - with open(path2, "wb") as file: - file.write(b"") +def test_post_upload_file(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") + path2 = tmp_path / "test2.txt" + path2.write_bytes(b"") client = TestClient(app) - response = client.post( - "/uploadfiles/", - files=( - ("files", ("test.txt", open(path, "rb"))), - ("files", ("test2.txt", open(path2, "rb"))), - ), - ) + with path.open("rb") as file, path2.open("rb") as file2: + response = client.post( + "/uploadfiles/", + files=( + ("files", ("test.txt", file)), + ("files", ("test2.txt", file2)), + ), + ) assert response.status_code == 200, response.text assert response.json() == {"filenames": ["test.txt", "test2.txt"]} diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py index 6a98ee324..10cce5e61 100644 --- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py @@ -1,6 +1,3 @@ -import os -from pathlib import Path - from fastapi.testclient import TestClient from docs_src.request_forms_and_files.tutorial001 import app @@ -163,32 +160,30 @@ def test_post_body_json(): assert response.json() == file_and_token_required -def test_post_file_no_token(tmpdir): - path = os.path.join(tmpdir, "test.txt") - with open(path, "wb") as file: - file.write(b"") +def test_post_file_no_token(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") client = TestClient(app) - response = client.post("/files/", files={"file": open(path, "rb")}) + with path.open("rb") as file: + response = client.post("/files/", files={"file": file}) assert response.status_code == 422, response.text assert response.json() == token_required -def test_post_files_and_token(tmpdir): - patha = Path(tmpdir) / "test.txt" - pathb = Path(tmpdir) / "testb.txt" +def test_post_files_and_token(tmp_path): + patha = tmp_path / "test.txt" + pathb = tmp_path / "testb.txt" patha.write_text("") pathb.write_text("") client = TestClient(app) - response = client.post( - "/files/", - data={"token": "foo"}, - files={ - "file": patha.open("rb"), - "fileb": ("testb.txt", pathb.open("rb"), "text/plain"), - }, - ) + with patha.open("rb") as filea, pathb.open("rb") as fileb: + response = client.post( + "/files/", + data={"token": "foo"}, + files={"file": filea, "fileb": ("testb.txt", fileb, "text/plain")}, + ) assert response.status_code == 200, response.text assert response.json() == { "file_size": 14, From 5ac84120b34505f80a25fc197185c82c1cc72bbb Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 19 Jul 2021 19:15:35 +0000 Subject: [PATCH 085/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5f54f7892..444e7f024 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Configure strict pytest options and update/refactor tests. PR [#2790](https://github.com/tiangolo/fastapi/pull/2790) by [@graingert](https://github.com/graingert). * 🌐 Add basic setup for German translations. PR [#3522](https://github.com/tiangolo/fastapi/pull/3522) by [@0x4Dark](https://github.com/0x4Dark). * 🌐 Add Portuguese translation for `docs/tutorial/security/index.md`. PR [#3507](https://github.com/tiangolo/fastapi/pull/3507) by [@oandersonmagalhaes](https://github.com/oandersonmagalhaes). * 🌐 Add Portuguese translation for `docs/deployment/index.md`. PR [#3337](https://github.com/tiangolo/fastapi/pull/3337) by [@lsglucas](https://github.com/lsglucas). From db5b2bdf56d2339cd4df378e448df04330922feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 19 Jul 2021 21:21:40 +0200 Subject: [PATCH 086/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 444e7f024..f1202cd14 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,11 +2,16 @@ ## Latest Changes -* 🔧 Configure strict pytest options and update/refactor tests. PR [#2790](https://github.com/tiangolo/fastapi/pull/2790) by [@graingert](https://github.com/graingert). +### Translations + * 🌐 Add basic setup for German translations. PR [#3522](https://github.com/tiangolo/fastapi/pull/3522) by [@0x4Dark](https://github.com/0x4Dark). * 🌐 Add Portuguese translation for `docs/tutorial/security/index.md`. PR [#3507](https://github.com/tiangolo/fastapi/pull/3507) by [@oandersonmagalhaes](https://github.com/oandersonmagalhaes). * 🌐 Add Portuguese translation for `docs/deployment/index.md`. PR [#3337](https://github.com/tiangolo/fastapi/pull/3337) by [@lsglucas](https://github.com/lsglucas). -* ⬆️ Upgrade python-jose dependency for tests. PR [#3468](https://github.com/tiangolo/fastapi/pull/3468) by [@tiangolo](https://github.com/tiangolo). + +### Internal + +* 🔧 Configure strict pytest options and update/refactor tests. Upgrade pytest to `>=6.2.4,<7.0.0` and pytest-cov to `>=2.12.0,<3.0.0`. Initial PR [#2790](https://github.com/tiangolo/fastapi/pull/2790) by [@graingert](https://github.com/graingert). +* ⬆️ Upgrade python-jose dependency to `>=3.3.0,<4.0.0` for tests. PR [#3468](https://github.com/tiangolo/fastapi/pull/3468) by [@tiangolo](https://github.com/tiangolo). ## 0.66.0 From 0a38c51b9edfaec5f1d49d01247dc2b8467f5dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 19 Jul 2021 21:26:52 +0200 Subject: [PATCH 087/814] =?UTF-8?q?=F0=9F=94=96=20Release=200.66.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 ++ fastapi/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f1202cd14..3a814e182 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,8 @@ ## Latest Changes +## 0.66.1 + ### Translations * 🌐 Add basic setup for German translations. PR [#3522](https://github.com/tiangolo/fastapi/pull/3522) by [@0x4Dark](https://github.com/0x4Dark). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 9ac36997f..7ae93ef8c 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.66.0" +__version__ = "0.66.1" from starlette import status as status From ba84f167f5f9da0fc23f1c1321c1e0477b59cd19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 10:52:10 +0200 Subject: [PATCH 088/814] =?UTF-8?q?=F0=9F=94=A7=20Sort=20external=20links?= =?UTF-8?q?=20in=20docs=20to=20have=20the=20most=20recent=20at=20the=20top?= =?UTF-8?q?=20(#3568)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/data/external_links.yml | 502 ++++++++++++++++---------------- docs/en/docs/help-fastapi.md | 2 +- 2 files changed, 252 insertions(+), 252 deletions(-) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index 8d175cbe9..b1e7e04c0 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,258 +1,258 @@ articles: english: - - link: https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59 - title: FastAPI/Starlette debug vs prod - author_link: https://medium.com/@williamhayes - author: William Hayes - - link: https://medium.com/data-rebels/fastapi-google-as-an-external-authentication-provider-3a527672cf33 - title: FastAPI — Google as an external authentication provider - author_link: https://medium.com/@nilsdebruin - author: Nils de Bruin - - link: https://medium.com/data-rebels/fastapi-how-to-add-basic-and-cookie-authentication-a45c85ef47d3 - title: FastAPI — How to add basic and cookie authentication - author_link: https://medium.com/@nilsdebruin - author: Nils de Bruin - - link: https://dev.to/errietta/introduction-to-the-fastapi-python-framework-2n10 - title: Introduction to the fastapi python framework - author_link: https://dev.to/errietta - author: Errieta Kostala - - link: https://nickc1.github.io/api,/scikit-learn/2019/01/10/scikit-fastapi.html - title: "FastAPI and Scikit-Learn: Easily Deploy Models" - author_link: https://nickc1.github.io/ - author: Nick Cortale - - link: https://medium.com/data-rebels/fastapi-authentication-revisited-enabling-api-key-authentication-122dc5975680 - title: "FastAPI authentication revisited: Enabling API key authentication" - author_link: https://medium.com/@nilsdebruin - author: Nils de Bruin - - link: https://medium.com/@nico.axtmann95/deploying-a-scikit-learn-model-with-onnx-und-fastapi-1af398268915 - title: Deploying a scikit-learn model with ONNX and FastAPI - author_link: https://www.linkedin.com/in/nico-axtmann - author: Nico Axtmann - - link: https://geekflare.com/python-asynchronous-web-frameworks/ - title: Top 5 Asynchronous Web Frameworks for Python - author_link: https://geekflare.com/author/ankush/ - author: Ankush Thakur - - link: https://medium.com/@gntrm/jwt-authentication-with-fastapi-and-aws-cognito-1333f7f2729e - title: JWT Authentication with FastAPI and AWS Cognito - author_link: https://twitter.com/gntrm - author: Johannes Gontrum - - link: https://towardsdatascience.com/how-to-deploy-a-machine-learning-model-dc51200fe8cf - title: How to Deploy a Machine Learning Model - author_link: https://www.linkedin.com/in/mgrootendorst/ - author: Maarten Grootendorst - - link: https://eng.uber.com/ludwig-v0-2/ - title: "Uber: Ludwig v0.2 Adds New Features and Other Improvements to its Deep Learning Toolbox [including a FastAPI server]" - author_link: https://eng.uber.com - author: Uber Engineering - - link: https://gitlab.com/euri10/fastapi_cheatsheet - title: A FastAPI and Swagger UI visual cheatsheet - author_link: https://gitlab.com/euri10 - author: "@euri10" - - link: https://medium.com/@mike.p.moritz/using-docker-compose-to-deploy-a-lightweight-python-rest-api-with-a-job-queue-37e6072a209b - title: Using Docker Compose to deploy a lightweight Python REST API with a job queue - author_link: https://medium.com/@mike.p.moritz - author: Mike Moritz - - link: https://robwagner.dev/tortoise-fastapi-setup/ - title: Setting up Tortoise ORM with FastAPI - author_link: https://robwagner.dev/ - author: Rob Wagner - - link: https://dev.to/dbanty/why-i-m-leaving-flask-3ki6 - title: Why I'm Leaving Flask - author_link: https://dev.to/dbanty - author: Dylan Anthony - - link: https://medium.com/python-data/how-to-deploy-tensorflow-2-0-models-as-an-api-service-with-fastapi-docker-128b177e81f3 - title: How To Deploy Tensorflow 2.0 Models As An API Service With FastAPI & Docker - author_link: https://medium.com/@bbrenyah - author: Bernard Brenyah - - link: https://testdriven.io/blog/fastapi-crud/ - title: "TestDriven.io: Developing and Testing an Asynchronous API with FastAPI and Pytest" - author_link: https://testdriven.io/authors/herman - author: Michael Herman - - link: https://towardsdatascience.com/deploying-iris-classifications-with-fastapi-and-docker-7c9b83fdec3a - title: "Towards Data Science: Deploying Iris Classifications with FastAPI and Docker" - author_link: https://towardsdatascience.com/@mandygu - author: Mandy Gu - - link: https://medium.com/analytics-vidhya/deploy-machine-learning-models-with-keras-fastapi-redis-and-docker-4940df614ece - title: Deploy Machine Learning Models with Keras, FastAPI, Redis and Docker - author_link: https://medium.com/@shane.soh - author: Shane Soh - - link: https://medium.com/@arthur393/another-boilerplate-to-fastapi-azure-pipeline-ci-pytest-3c8d9a4be0bb - title: "Another Boilerplate to FastAPI: Azure Pipeline CI + Pytest" - author_link: https://twitter.com/arthurheinrique - author: Arthur Henrique - - link: https://iwpnd.pw/articles/2020-01/deploy-fastapi-to-aws-lambda - title: How to continuously deploy a FastAPI to AWS Lambda with AWS SAM - author_link: https://iwpnd.pw - author: Benjamin Ramser - - link: https://www.tutlinks.com/create-and-deploy-fastapi-app-to-heroku/ - title: Create and Deploy FastAPI app to Heroku without using Docker - author_link: https://www.linkedin.com/in/navule/ - author: Navule Pavan Kumar Rao - - link: https://iwpnd.pw/articles/2020-03/apache-kafka-fastapi-geostream - title: Apache Kafka producer and consumer with FastAPI and aiokafka - author_link: https://iwpnd.pw - author: Benjamin Ramser - - link: https://wuilly.com/2019/10/real-time-notifications-with-python-and-postgres/ - title: Real-time Notifications with Python and Postgres - author_link: https://wuilly.com/ - author: Guillermo Cruz - - link: https://dev.to/paurakhsharma/microservice-in-python-using-fastapi-24cc - title: Microservice in Python using FastAPI - author_link: https://twitter.com/PaurakhSharma - author: Paurakh Sharma Humagain - - link: https://dev.to/cuongld2/build-simple-api-service-with-python-fastapi-part-1-581o - title: Build simple API service with Python FastAPI — Part 1 - author_link: https://dev.to/cuongld2 - author: cuongld2 - - link: https://paulsec.github.io/posts/fastapi_plus_zeit_serverless_fu/ - title: FastAPI + Zeit.co = 🚀 - author_link: https://twitter.com/PaulWebSec - author: Paul Sec - - link: https://dev.to/tiangolo/build-a-web-api-from-scratch-with-fastapi-the-workshop-2ehe - title: Build a web API from scratch with FastAPI - the workshop - author_link: https://twitter.com/tiangolo - author: Sebastián Ramírez (tiangolo) - - link: https://www.twilio.com/blog/build-secure-twilio-webhook-python-fastapi - title: Build a Secure Twilio Webhook with Python and FastAPI - author_link: https://www.twilio.com - author: Twilio - - link: https://www.stavros.io/posts/fastapi-with-django/ - title: Using FastAPI with Django - author_link: https://twitter.com/Stavros - author: Stavros Korokithakis - - link: https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072 - title: Introducing Dispatch - author_link: https://netflixtechblog.com/ - author: Netflix - - link: https://davidefiocco.github.io/streamlit-fastapi-ml-serving/ - title: Machine learning model serving in Python using FastAPI and streamlit - author_link: https://github.com/davidefiocco - author: Davide Fiocco - - link: https://www.tutlinks.com/deploy-fastapi-on-azure/ - title: Deploy FastAPI on Azure App Service - author_link: https://www.linkedin.com/in/navule/ - author: Navule Pavan Kumar Rao - - link: https://towardsdatascience.com/build-and-host-fast-data-science-applications-using-fastapi-823be8a1d6a0 - title: Build And Host Fast Data Science Applications Using FastAPI - author_link: https://medium.com/@farhadmalik - author: Farhad Malik - - link: https://medium.com/@gabbyprecious2000/creating-a-crud-app-with-fastapi-part-one-7c049292ad37 - title: Creating a CRUD App with FastAPI (Part one) - author_link: https://medium.com/@gabbyprecious2000 - author: Precious Ndubueze - - link: https://julienharbulot.com/notification-server.html - title: HTTP server to display desktop notifications - author_link: https://julienharbulot.com/ - author: Julien Harbulot - - link: https://guitton.co/posts/fastapi-monitoring/ - title: How to monitor your FastAPI service - author_link: https://twitter.com/louis_guitton - author: Louis Guitton - - link: https://amitness.com/2020/06/fastapi-vs-flask/ - title: FastAPI for Flask Users - author_link: https://twitter.com/amitness - author: Amit Chaudhary - - link: https://valonjanuzaj.medium.com/deploy-a-dockerized-fastapi-application-to-aws-cc757830ba1b - title: Deploy a dockerized FastAPI application to AWS - author_link: https://www.linkedin.com/in/valon-januzaj-b02692187/ - author: Valon Januzaj - - link: https://dompatmore.com/blog/authenticate-your-fastapi-app-with-auth0 - title: Authenticate Your FastAPI App with auth0 - author_link: https://twitter.com/dompatmore - author: Dom Patmore - japanese: - - link: https://qiita.com/mtitg/items/47770e9a562dd150631d - title: FastAPI|DB接続してCRUDするPython製APIサーバーを構築 - author_link: https://qiita.com/mtitg - author: "@mtitg" - - link: https://qiita.com/ryoryomaru/items/59958ed385b3571d50de - title: python製の最新APIフレームワーク FastAPI を触ってみた - author_link: https://qiita.com/ryoryomaru - author: "@ryoryomaru" - - link: https://qiita.com/angel_katayoku/items/0e1f5dbbe62efc612a78 - title: FastAPIでCORSを回避 - author_link: https://qiita.com/angel_katayoku - author: "@angel_katayoku" - - link: https://qiita.com/angel_katayoku/items/4fbc1a4e2b33fa2237d2 - title: FastAPIをMySQLと接続してDockerで管理してみる - author_link: https://qiita.com/angel_katayoku - author: "@angel_katayoku" - - link: https://qiita.com/angel_katayoku/items/8a458a8952f50b73f420 - title: FastAPIでPOSTされたJSONのレスポンスbodyを受け取る - author_link: https://qiita.com/angel_katayoku - author: "@angel_katayoku" - - link: https://qiita.com/hikarut/items/b178af2e2440c67c6ac4 - title: フロントエンド開発者向けのDockerによるPython開発環境構築 - author_link: https://qiita.com/hikarut - author: Hikaru Takahashi - - link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-environment - title: "【第1回】FastAPIチュートリアル: ToDoアプリを作ってみよう【環境構築編】" - author_link: https://rightcode.co.jp/author/jun - author: ライトコードメディア編集部 - - link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-model-building - title: "【第2回】FastAPIチュートリアル: ToDoアプリを作ってみよう【モデル構築編】" - author_link: https://rightcode.co.jp/author/jun - author: ライトコードメディア編集部 - - link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-authentication-user-registration - title: "【第3回】FastAPIチュートリアル: toDoアプリを作ってみよう【認証・ユーザ登録編】" - author_link: https://rightcode.co.jp/author/jun - author: ライトコードメディア編集部 - - link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-admin-page-improvement - title: "【第4回】FastAPIチュートリアル: toDoアプリを作ってみよう【管理者ページ改良編】" - author_link: https://rightcode.co.jp/author/jun - author: ライトコードメディア編集部 - - link: https://qiita.com/bee2/items/0ad260ab9835a2087dae - title: PythonのWeb frameworkのパフォーマンス比較 (Django, Flask, responder, FastAPI, japronto) - author_link: https://qiita.com/bee2 - author: "@bee2" - - link: https://qiita.com/bee2/items/75d9c0d7ba20e7a4a0e9 - title: "[FastAPI] Python製のASGI Web フレームワーク FastAPIに入門する" - author_link: https://qiita.com/bee2 - author: "@bee2" - vietnamese: - - link: https://fullstackstation.com/fastapi-trien-khai-bang-docker/ - title: "FASTAPI: TRIỂN KHAI BẰNG DOCKER" - author_link: https://fullstackstation.com/author/figonking/ - author: Nguyễn Nhân - russian: - - link: https://habr.com/ru/post/454440/ - title: "Мелкая питонячая радость #2: Starlette - Солидная примочка – FastAPI" - author_link: https://habr.com/ru/users/57uff3r/ - author: Andrey Korchak - - link: https://habr.com/ru/post/478620/ - title: Почему Вы должны попробовать FastAPI? - author_link: https://github.com/prostomarkeloff - author: prostomarkeloff - - link: https://trkohler.com/fast-api-introduction-to-framework - title: "FastAPI: знакомимся с фреймворком" - author_link: https://www.linkedin.com/in/trkohler/ - author: Troy Köhler + - author: Dom Patmore + author_link: https://twitter.com/dompatmore + link: https://dompatmore.com/blog/authenticate-your-fastapi-app-with-auth0 + title: Authenticate Your FastAPI App with auth0 + - author: Valon Januzaj + author_link: https://www.linkedin.com/in/valon-januzaj-b02692187/ + link: https://valonjanuzaj.medium.com/deploy-a-dockerized-fastapi-application-to-aws-cc757830ba1b + title: Deploy a dockerized FastAPI application to AWS + - author: Amit Chaudhary + author_link: https://twitter.com/amitness + link: https://amitness.com/2020/06/fastapi-vs-flask/ + title: FastAPI for Flask Users + - author: Louis Guitton + author_link: https://twitter.com/louis_guitton + link: https://guitton.co/posts/fastapi-monitoring/ + title: How to monitor your FastAPI service + - author: Julien Harbulot + author_link: https://julienharbulot.com/ + link: https://julienharbulot.com/notification-server.html + title: HTTP server to display desktop notifications + - author: Precious Ndubueze + author_link: https://medium.com/@gabbyprecious2000 + link: https://medium.com/@gabbyprecious2000/creating-a-crud-app-with-fastapi-part-one-7c049292ad37 + title: Creating a CRUD App with FastAPI (Part one) + - author: Farhad Malik + author_link: https://medium.com/@farhadmalik + link: https://towardsdatascience.com/build-and-host-fast-data-science-applications-using-fastapi-823be8a1d6a0 + title: Build And Host Fast Data Science Applications Using FastAPI + - author: Navule Pavan Kumar Rao + author_link: https://www.linkedin.com/in/navule/ + link: https://www.tutlinks.com/deploy-fastapi-on-azure/ + title: Deploy FastAPI on Azure App Service + - author: Davide Fiocco + author_link: https://github.com/davidefiocco + link: https://davidefiocco.github.io/streamlit-fastapi-ml-serving/ + title: Machine learning model serving in Python using FastAPI and streamlit + - author: Netflix + author_link: https://netflixtechblog.com/ + link: https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072 + title: Introducing Dispatch + - author: Stavros Korokithakis + author_link: https://twitter.com/Stavros + link: https://www.stavros.io/posts/fastapi-with-django/ + title: Using FastAPI with Django + - author: Twilio + author_link: https://www.twilio.com + link: https://www.twilio.com/blog/build-secure-twilio-webhook-python-fastapi + title: Build a Secure Twilio Webhook with Python and FastAPI + - author: Sebastián Ramírez (tiangolo) + author_link: https://twitter.com/tiangolo + link: https://dev.to/tiangolo/build-a-web-api-from-scratch-with-fastapi-the-workshop-2ehe + title: Build a web API from scratch with FastAPI - the workshop + - author: Paul Sec + author_link: https://twitter.com/PaulWebSec + link: https://paulsec.github.io/posts/fastapi_plus_zeit_serverless_fu/ + title: FastAPI + Zeit.co = 🚀 + - author: cuongld2 + author_link: https://dev.to/cuongld2 + link: https://dev.to/cuongld2/build-simple-api-service-with-python-fastapi-part-1-581o + title: Build simple API service with Python FastAPI — Part 1 + - author: Paurakh Sharma Humagain + author_link: https://twitter.com/PaurakhSharma + link: https://dev.to/paurakhsharma/microservice-in-python-using-fastapi-24cc + title: Microservice in Python using FastAPI + - author: Guillermo Cruz + author_link: https://wuilly.com/ + link: https://wuilly.com/2019/10/real-time-notifications-with-python-and-postgres/ + title: Real-time Notifications with Python and Postgres + - author: Benjamin Ramser + author_link: https://iwpnd.pw + link: https://iwpnd.pw/articles/2020-03/apache-kafka-fastapi-geostream + title: Apache Kafka producer and consumer with FastAPI and aiokafka + - author: Navule Pavan Kumar Rao + author_link: https://www.linkedin.com/in/navule/ + link: https://www.tutlinks.com/create-and-deploy-fastapi-app-to-heroku/ + title: Create and Deploy FastAPI app to Heroku without using Docker + - author: Benjamin Ramser + author_link: https://iwpnd.pw + link: https://iwpnd.pw/articles/2020-01/deploy-fastapi-to-aws-lambda + title: How to continuously deploy a FastAPI to AWS Lambda with AWS SAM + - author: Arthur Henrique + author_link: https://twitter.com/arthurheinrique + link: https://medium.com/@arthur393/another-boilerplate-to-fastapi-azure-pipeline-ci-pytest-3c8d9a4be0bb + title: 'Another Boilerplate to FastAPI: Azure Pipeline CI + Pytest' + - author: Shane Soh + author_link: https://medium.com/@shane.soh + link: https://medium.com/analytics-vidhya/deploy-machine-learning-models-with-keras-fastapi-redis-and-docker-4940df614ece + title: Deploy Machine Learning Models with Keras, FastAPI, Redis and Docker + - author: Mandy Gu + author_link: https://towardsdatascience.com/@mandygu + link: https://towardsdatascience.com/deploying-iris-classifications-with-fastapi-and-docker-7c9b83fdec3a + title: 'Towards Data Science: Deploying Iris Classifications with FastAPI and Docker' + - author: Michael Herman + author_link: https://testdriven.io/authors/herman + link: https://testdriven.io/blog/fastapi-crud/ + title: 'TestDriven.io: Developing and Testing an Asynchronous API with FastAPI and Pytest' + - author: Bernard Brenyah + author_link: https://medium.com/@bbrenyah + link: https://medium.com/python-data/how-to-deploy-tensorflow-2-0-models-as-an-api-service-with-fastapi-docker-128b177e81f3 + title: How To Deploy Tensorflow 2.0 Models As An API Service With FastAPI & Docker + - author: Dylan Anthony + author_link: https://dev.to/dbanty + link: https://dev.to/dbanty/why-i-m-leaving-flask-3ki6 + title: Why I'm Leaving Flask + - author: Rob Wagner + author_link: https://robwagner.dev/ + link: https://robwagner.dev/tortoise-fastapi-setup/ + title: Setting up Tortoise ORM with FastAPI + - author: Mike Moritz + author_link: https://medium.com/@mike.p.moritz + link: https://medium.com/@mike.p.moritz/using-docker-compose-to-deploy-a-lightweight-python-rest-api-with-a-job-queue-37e6072a209b + title: Using Docker Compose to deploy a lightweight Python REST API with a job queue + - author: '@euri10' + author_link: https://gitlab.com/euri10 + link: https://gitlab.com/euri10/fastapi_cheatsheet + title: A FastAPI and Swagger UI visual cheatsheet + - author: Uber Engineering + author_link: https://eng.uber.com + link: https://eng.uber.com/ludwig-v0-2/ + title: 'Uber: Ludwig v0.2 Adds New Features and Other Improvements to its Deep Learning Toolbox [including a FastAPI server]' + - author: Maarten Grootendorst + author_link: https://www.linkedin.com/in/mgrootendorst/ + link: https://towardsdatascience.com/how-to-deploy-a-machine-learning-model-dc51200fe8cf + title: How to Deploy a Machine Learning Model + - author: Johannes Gontrum + author_link: https://twitter.com/gntrm + link: https://medium.com/@gntrm/jwt-authentication-with-fastapi-and-aws-cognito-1333f7f2729e + title: JWT Authentication with FastAPI and AWS Cognito + - author: Ankush Thakur + author_link: https://geekflare.com/author/ankush/ + link: https://geekflare.com/python-asynchronous-web-frameworks/ + title: Top 5 Asynchronous Web Frameworks for Python + - author: Nico Axtmann + author_link: https://www.linkedin.com/in/nico-axtmann + link: https://medium.com/@nico.axtmann95/deploying-a-scikit-learn-model-with-onnx-und-fastapi-1af398268915 + title: Deploying a scikit-learn model with ONNX and FastAPI + - author: Nils de Bruin + author_link: https://medium.com/@nilsdebruin + link: https://medium.com/data-rebels/fastapi-authentication-revisited-enabling-api-key-authentication-122dc5975680 + title: 'FastAPI authentication revisited: Enabling API key authentication' + - author: Nick Cortale + author_link: https://nickc1.github.io/ + link: https://nickc1.github.io/api,/scikit-learn/2019/01/10/scikit-fastapi.html + title: 'FastAPI and Scikit-Learn: Easily Deploy Models' + - author: Errieta Kostala + author_link: https://dev.to/errietta + link: https://dev.to/errietta/introduction-to-the-fastapi-python-framework-2n10 + title: Introduction to the fastapi python framework + - author: Nils de Bruin + author_link: https://medium.com/@nilsdebruin + link: https://medium.com/data-rebels/fastapi-how-to-add-basic-and-cookie-authentication-a45c85ef47d3 + title: FastAPI — How to add basic and cookie authentication + - author: Nils de Bruin + author_link: https://medium.com/@nilsdebruin + link: https://medium.com/data-rebels/fastapi-google-as-an-external-authentication-provider-3a527672cf33 + title: FastAPI — Google as an external authentication provider + - author: William Hayes + author_link: https://medium.com/@williamhayes + link: https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59 + title: FastAPI/Starlette debug vs prod german: - - link: https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/ - title: Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI - author_link: https://twitter.com/_nicoax - author: Nico Axtmann + - author: Nico Axtmann + author_link: https://twitter.com/_nicoax + link: https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/ + title: Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI + japanese: + - author: '@bee2' + author_link: https://qiita.com/bee2 + link: https://qiita.com/bee2/items/75d9c0d7ba20e7a4a0e9 + title: '[FastAPI] Python製のASGI Web フレームワーク FastAPIに入門する' + - author: '@bee2' + author_link: https://qiita.com/bee2 + link: https://qiita.com/bee2/items/0ad260ab9835a2087dae + title: PythonのWeb frameworkのパフォーマンス比較 (Django, Flask, responder, FastAPI, japronto) + - author: ライトコードメディア編集部 + author_link: https://rightcode.co.jp/author/jun + link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-admin-page-improvement + title: '【第4回】FastAPIチュートリアル: toDoアプリを作ってみよう【管理者ページ改良編】' + - author: ライトコードメディア編集部 + author_link: https://rightcode.co.jp/author/jun + link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-authentication-user-registration + title: '【第3回】FastAPIチュートリアル: toDoアプリを作ってみよう【認証・ユーザ登録編】' + - author: ライトコードメディア編集部 + author_link: https://rightcode.co.jp/author/jun + link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-model-building + title: '【第2回】FastAPIチュートリアル: ToDoアプリを作ってみよう【モデル構築編】' + - author: ライトコードメディア編集部 + author_link: https://rightcode.co.jp/author/jun + link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-environment + title: '【第1回】FastAPIチュートリアル: ToDoアプリを作ってみよう【環境構築編】' + - author: Hikaru Takahashi + author_link: https://qiita.com/hikarut + link: https://qiita.com/hikarut/items/b178af2e2440c67c6ac4 + title: フロントエンド開発者向けのDockerによるPython開発環境構築 + - author: '@angel_katayoku' + author_link: https://qiita.com/angel_katayoku + link: https://qiita.com/angel_katayoku/items/8a458a8952f50b73f420 + title: FastAPIでPOSTされたJSONのレスポンスbodyを受け取る + - author: '@angel_katayoku' + author_link: https://qiita.com/angel_katayoku + link: https://qiita.com/angel_katayoku/items/4fbc1a4e2b33fa2237d2 + title: FastAPIをMySQLと接続してDockerで管理してみる + - author: '@angel_katayoku' + author_link: https://qiita.com/angel_katayoku + link: https://qiita.com/angel_katayoku/items/0e1f5dbbe62efc612a78 + title: FastAPIでCORSを回避 + - author: '@ryoryomaru' + author_link: https://qiita.com/ryoryomaru + link: https://qiita.com/ryoryomaru/items/59958ed385b3571d50de + title: python製の最新APIフレームワーク FastAPI を触ってみた + - author: '@mtitg' + author_link: https://qiita.com/mtitg + link: https://qiita.com/mtitg/items/47770e9a562dd150631d + title: FastAPI|DB接続してCRUDするPython製APIサーバーを構築 + russian: + - author: Troy Köhler + author_link: https://www.linkedin.com/in/trkohler/ + link: https://trkohler.com/fast-api-introduction-to-framework + title: 'FastAPI: знакомимся с фреймворком' + - author: prostomarkeloff + author_link: https://github.com/prostomarkeloff + link: https://habr.com/ru/post/478620/ + title: Почему Вы должны попробовать FastAPI? + - author: Andrey Korchak + author_link: https://habr.com/ru/users/57uff3r/ + link: https://habr.com/ru/post/454440/ + title: 'Мелкая питонячая радость #2: Starlette - Солидная примочка – FastAPI' + vietnamese: + - author: Nguyễn Nhân + author_link: https://fullstackstation.com/author/figonking/ + link: https://fullstackstation.com/fastapi-trien-khai-bang-docker/ + title: 'FASTAPI: TRIỂN KHAI BẰNG DOCKER' podcasts: english: - - link: https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855 - title: FastAPI on PythonBytes - author_link: https://pythonbytes.fm/ - author: Python Bytes FM - - link: https://www.pythonpodcast.com/fastapi-web-application-framework-episode-259/ - title: "Build The Next Generation Of Python Web Applications With FastAPI - Episode 259 - interview to Sebastían Ramírez (tiangolo)" - author_link: https://www.pythonpodcast.com/ - author: Podcast.`__init__` + - author: Podcast.`__init__` + author_link: https://www.pythonpodcast.com/ + link: https://www.pythonpodcast.com/fastapi-web-application-framework-episode-259/ + title: Build The Next Generation Of Python Web Applications With FastAPI - Episode 259 - interview to Sebastían Ramírez (tiangolo) + - author: Python Bytes FM + author_link: https://pythonbytes.fm/ + link: https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855 + title: FastAPI on PythonBytes talks: english: - - link: https://www.youtube.com/watch?v=3DLwPcrE5mA - title: "PyCon UK 2019: FastAPI from the ground up" - author_link: https://twitter.com/chriswithers13 - author: Chris Withers - - link: https://www.youtube.com/watch?v=z9K5pwb0rt8 - title: "PyConBY 2020: Serve ML models easily with FastAPI" - author_link: https://twitter.com/tiangolo - author: "Sebastián Ramírez (tiangolo)" - - link: https://www.youtube.com/watch?v=PnpTY1f4k2U - title: "[VIRTUAL] Py.Amsterdam's flying Software Circus: Intro to FastAPI" - author_link: https://twitter.com/tiangolo - author: "Sebastián Ramírez (tiangolo)" + - author: Sebastián Ramírez (tiangolo) + author_link: https://twitter.com/tiangolo + link: https://www.youtube.com/watch?v=PnpTY1f4k2U + title: '[VIRTUAL] Py.Amsterdam''s flying Software Circus: Intro to FastAPI' + - author: Sebastián Ramírez (tiangolo) + author_link: https://twitter.com/tiangolo + link: https://www.youtube.com/watch?v=z9K5pwb0rt8 + title: 'PyConBY 2020: Serve ML models easily with FastAPI' + - author: Chris Withers + author_link: https://twitter.com/chriswithers13 + link: https://www.youtube.com/watch?v=3DLwPcrE5mA + title: 'PyCon UK 2019: FastAPI from the ground up' diff --git a/docs/en/docs/help-fastapi.md b/docs/en/docs/help-fastapi.md index 625e84ef6..561db2d38 100644 --- a/docs/en/docs/help-fastapi.md +++ b/docs/en/docs/help-fastapi.md @@ -92,7 +92,7 @@ You can [contribute](contributing.md){.internal-link target=_blank} to the sourc * To fix a typo you found on the documentation. * To share an article, video, or podcast you created or found about FastAPI by editing this file. - * Make sure you add your link to the end of the corresponding section. + * Make sure you add your link to the start of the corresponding section. * To help [translate the documentation](contributing.md#translations){.internal-link target=_blank} to your language. * You can also help reviewing the translations created by others. * To propose new documentation sections. From c1801738b0485b50a8337ec8b31be95ce50bf084 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 08:52:50 +0000 Subject: [PATCH 089/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3a814e182..01a5ac94e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Sort external links in docs to have the most recent at the top. PR [#3568](https://github.com/tiangolo/fastapi/pull/3568) by [@tiangolo](https://github.com/tiangolo). ## 0.66.1 ### Translations From 3d81bc638b1bf0fd64716091b10dbc807d181e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 11:24:40 +0200 Subject: [PATCH 090/814] =?UTF-8?q?=F0=9F=91=B7=20Rename=20and=20clarify?= =?UTF-8?q?=20CI=20workflow=20job=20names=20(#3570)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-docs.yml | 2 +- .github/workflows/preview-docs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index e62264458..eba5fc57e 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -4,7 +4,7 @@ on: pull_request: types: [opened, synchronize] jobs: - build: + build-docs: runs-on: ubuntu-18.04 steps: - name: Dump GitHub context diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml index 8401e9872..0c0d2ac59 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/preview-docs.yml @@ -7,7 +7,7 @@ on: - completed jobs: - deploy: + preview-docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 From 7741635b3b7660a42169ee3fc84c0978cb0e063d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 11:39:12 +0200 Subject: [PATCH 091/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20External=20Link,?= =?UTF-8?q?=20replaces=20#1898=20(#3571)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index b1e7e04c0..a4e4c10d8 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: Patrick Ladon + author_link: https://dev.to/factorlive + link: https://dev.to/factorlive/python-facebook-messenger-webhook-with-fastapi-on-glitch-4n90 + title: Python Facebook messenger webhook with FastAPI on Glitch - author: Dom Patmore author_link: https://twitter.com/dompatmore link: https://dompatmore.com/blog/authenticate-your-fastapi-app-with-auth0 From 67ef62a4ddfe67b6b2a29d6c663cf807254870e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 11:54:27 +0200 Subject: [PATCH 092/814] =?UTF-8?q?=F0=9F=91=B7=20Update=20GitHub=20Action?= =?UTF-8?q?=20latest-changes=20(#3573)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/latest-changes.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml index b2604eef1..829377bb3 100644 --- a/.github/workflows/latest-changes.yml +++ b/.github/workflows/latest-changes.yml @@ -11,15 +11,27 @@ on: 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: latest-changes: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + # Allow debugging with tmate + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} + with: + limit-access-to-actor: true + token: ${{ secrets.ACTIONS_TOKEN }} + standard_token: ${{ secrets.GITHUB_TOKEN }} - uses: docker://tiangolo/latest-changes:0.0.3 with: - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.ACTION_TOKEN }} latest_changes_file: docs/en/docs/release-notes.md latest_changes_header: '## Latest Changes\n\n' debug_logs: true From fcfff5e8e54ad6633d1fa9b61b55997079af7eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 12:33:42 +0200 Subject: [PATCH 093/814] =?UTF-8?q?=F0=9F=91=B7=20Update=20GitHub=20Action?= =?UTF-8?q?=20latest-changes=20(#3574)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/latest-changes.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml index 829377bb3..ed4d4554c 100644 --- a/.github/workflows/latest-changes.yml +++ b/.github/workflows/latest-changes.yml @@ -21,6 +21,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + with: + # To allow latest-changes to commit to master + token: ${{ secrets.ACTION_TOKEN }} # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 From 9ab7da65621b9e38808e393739c152ff18d58593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 12:41:32 +0200 Subject: [PATCH 094/814] =?UTF-8?q?=F0=9F=91=B7=20Update=20GitHub=20Action?= =?UTF-8?q?=20latest-changes,=20strike=202=20=E2=9A=BE=20(#3575)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/latest-changes.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml index ed4d4554c..42236beba 100644 --- a/.github/workflows/latest-changes.yml +++ b/.github/workflows/latest-changes.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v2 with: # To allow latest-changes to commit to master - token: ${{ secrets.ACTION_TOKEN }} + token: ${{ secrets.ACTIONS_TOKEN }} # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 @@ -34,7 +34,7 @@ jobs: standard_token: ${{ secrets.GITHUB_TOKEN }} - uses: docker://tiangolo/latest-changes:0.0.3 with: - token: ${{ secrets.ACTION_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} latest_changes_file: docs/en/docs/release-notes.md latest_changes_header: '## Latest Changes\n\n' debug_logs: true From ef1716c39e7c0ec199b4d00c38bf8e84a35bb452 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 10:42:13 +0000 Subject: [PATCH 095/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 01a5ac94e..ab98abc66 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Update GitHub Action latest-changes, strike 2 ⚾. PR [#3575](https://github.com/tiangolo/fastapi/pull/3575) by [@tiangolo](https://github.com/tiangolo). * 🔧 Sort external links in docs to have the most recent at the top. PR [#3568](https://github.com/tiangolo/fastapi/pull/3568) by [@tiangolo](https://github.com/tiangolo). ## 0.66.1 From 3ce940709394d1b74fb598f2042a506e985f2057 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 11:08:47 +0000 Subject: [PATCH 096/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ab98abc66..033bdb459 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Rename and clarify CI workflow job names. PR [#3570](https://github.com/tiangolo/fastapi/pull/3570) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes, strike 2 ⚾. PR [#3575](https://github.com/tiangolo/fastapi/pull/3575) by [@tiangolo](https://github.com/tiangolo). * 🔧 Sort external links in docs to have the most recent at the top. PR [#3568](https://github.com/tiangolo/fastapi/pull/3568) by [@tiangolo](https://github.com/tiangolo). ## 0.66.1 From f6cc418d79af08a3a354658fe20609aad015c1cb Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 11:10:13 +0000 Subject: [PATCH 097/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 033bdb459..3167f064c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add External Link, replaces #1898. PR [#3571](https://github.com/tiangolo/fastapi/pull/3571) by [@tiangolo](https://github.com/tiangolo). * 👷 Rename and clarify CI workflow job names. PR [#3570](https://github.com/tiangolo/fastapi/pull/3570) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes, strike 2 ⚾. PR [#3575](https://github.com/tiangolo/fastapi/pull/3575) by [@tiangolo](https://github.com/tiangolo). * 🔧 Sort external links in docs to have the most recent at the top. PR [#3568](https://github.com/tiangolo/fastapi/pull/3568) by [@tiangolo](https://github.com/tiangolo). From f80230d6543107537f3ed2dcab7cb9e1f8fcefd8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 11:11:43 +0000 Subject: [PATCH 098/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3167f064c..d9b35c649 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Update GitHub Action latest-changes. PR [#3573](https://github.com/tiangolo/fastapi/pull/3573) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add External Link, replaces #1898. PR [#3571](https://github.com/tiangolo/fastapi/pull/3571) by [@tiangolo](https://github.com/tiangolo). * 👷 Rename and clarify CI workflow job names. PR [#3570](https://github.com/tiangolo/fastapi/pull/3570) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes, strike 2 ⚾. PR [#3575](https://github.com/tiangolo/fastapi/pull/3575) by [@tiangolo](https://github.com/tiangolo). From 6b65de6033128d55d3b0965811203e72569977ca Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 11:12:47 +0000 Subject: [PATCH 099/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d9b35c649..057b2cacb 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Update GitHub Action latest-changes. PR [#3574](https://github.com/tiangolo/fastapi/pull/3574) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes. PR [#3573](https://github.com/tiangolo/fastapi/pull/3573) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add External Link, replaces #1898. PR [#3571](https://github.com/tiangolo/fastapi/pull/3571) by [@tiangolo](https://github.com/tiangolo). * 👷 Rename and clarify CI workflow job names. PR [#3570](https://github.com/tiangolo/fastapi/pull/3570) by [@tiangolo](https://github.com/tiangolo). From 38194a29bc3aab2637b407ca05519500f9268310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 13:14:28 +0200 Subject: [PATCH 100/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20External=20Link:?= =?UTF-8?q?=20Deploy=20FastAPI=20on=20Ubuntu=20and=20Serve=20using=20Caddy?= =?UTF-8?q?=202=20Web=20Server=20(#3572)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index a4e4c10d8..d1972d5e1 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: Navule Pavan Kumar Rao + author_link: https://www.linkedin.com/in/navule/ + link: https://www.tutlinks.com/deploy-fastapi-on-ubuntu-gunicorn-caddy-2/ + title: Deploy FastAPI on Ubuntu and Serve using Caddy 2 Web Server - author: Patrick Ladon author_link: https://dev.to/factorlive link: https://dev.to/factorlive/python-facebook-messenger-webhook-with-fastapi-on-glitch-4n90 From 8c12ab0d5b6693147d9cb528bebf0f498166ae2c Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 11:15:03 +0000 Subject: [PATCH 101/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 057b2cacb..53f15a435 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add External Link: Deploy FastAPI on Ubuntu and Serve using Caddy 2 Web Server. PR [#3572](https://github.com/tiangolo/fastapi/pull/3572) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes. PR [#3574](https://github.com/tiangolo/fastapi/pull/3574) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes. PR [#3573](https://github.com/tiangolo/fastapi/pull/3573) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add External Link, replaces #1898. PR [#3571](https://github.com/tiangolo/fastapi/pull/3571) by [@tiangolo](https://github.com/tiangolo). From fc35b7d18d86cc223df165e87ab93b2a25c9bdf8 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Wed, 21 Jul 2021 14:10:47 +0200 Subject: [PATCH 102/814] =?UTF-8?q?=F0=9F=8E=A8=20Improve=20style=20for=20?= =?UTF-8?q?sponsors,=20add=20radius=20border=20(#2388)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/de/docs/index.md | 4 ++-- docs/en/docs/fastapi-people.md | 6 ++--- docs/en/docs/index.md | 4 ++-- docs/es/docs/index.md | 7 ++++-- docs/fr/docs/fastapi-people.md | 40 ++++++++++++++++++++++++++++++++++ docs/fr/docs/index.md | 7 ++++-- docs/id/docs/index.md | 7 ++++-- docs/it/docs/index.md | 7 ++++-- docs/ja/docs/fastapi-people.md | 18 ++++++++++----- docs/ja/docs/index.md | 7 ++++-- docs/ko/docs/index.md | 5 ++++- docs/pl/docs/index.md | 7 ++++-- docs/pt/docs/index.md | 7 ++++-- docs/ru/docs/index.md | 7 ++++-- docs/sq/docs/index.md | 7 ++++-- docs/tr/docs/index.md | 7 ++++-- docs/uk/docs/index.md | 7 ++++-- docs/zh/docs/fastapi-people.md | 34 +++++++++++++++++++---------- docs/zh/docs/index.md | 7 ++++-- 19 files changed, 146 insertions(+), 49 deletions(-) diff --git a/docs/de/docs/index.md b/docs/de/docs/index.md index 3b8bb6371..95fb7ae21 100644 --- a/docs/de/docs/index.md +++ b/docs/de/docs/index.md @@ -50,10 +50,10 @@ The key features are: {% if sponsors %} {% for sponsor in sponsors.gold -%} - + {% endfor -%} {%- for sponsor in sponsors.silver -%} - + {% endfor %} {% endif %} diff --git a/docs/en/docs/fastapi-people.md b/docs/en/docs/fastapi-people.md index e38c31c3d..ce8ea3887 100644 --- a/docs/en/docs/fastapi-people.md +++ b/docs/en/docs/fastapi-people.md @@ -118,7 +118,7 @@ They are supporting my work with **FastAPI** (and others), mainly through + {% endfor %} {% endif %} @@ -126,7 +126,7 @@ They are supporting my work with **FastAPI** (and others), mainly through + {% endfor %} {% endif %} @@ -134,7 +134,7 @@ They are supporting my work with **FastAPI** (and others), mainly through + {% endfor %} {% endif %} diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index 82e8a9fca..33aadb8ef 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -46,10 +46,10 @@ The key features are: {% if sponsors %} {% for sponsor in sponsors.gold -%} - + {% endfor -%} {%- for sponsor in sponsors.silver -%} - + {% endfor %} {% endif %} diff --git a/docs/es/docs/index.md b/docs/es/docs/index.md index 036584745..65eaf75d0 100644 --- a/docs/es/docs/index.md +++ b/docs/es/docs/index.md @@ -39,13 +39,16 @@ Sus características principales son: * Esta estimación está basada en pruebas con un equipo de desarrollo interno contruyendo aplicaciones listas para producción. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/fr/docs/fastapi-people.md b/docs/fr/docs/fastapi-people.md index 35d680df9..ac6e19831 100644 --- a/docs/fr/docs/fastapi-people.md +++ b/docs/fr/docs/fastapi-people.md @@ -114,6 +114,46 @@ Ce sont les **Sponsors**. 😎 Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec GitHub Sponsors. +### Gold Sponsors + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + +### Silver Sponsors + +{% if sponsors %} +{% for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + +### Bronze Sponsors + +{% if sponsors %} +{% for sponsor in sponsors.bronze -%} + +{% endfor %} +{% endif %} + +### Individual Sponsors + +{% if people %} +{% if people.sponsors_50 %} + +
+{% for user in people.sponsors_50 %} + + +{% endfor %} + +
+ +{% endif %} +{% endif %} + {% if people %}
{% for user in people.sponsors %} diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md index 9cc706c43..40e6dfdff 100644 --- a/docs/fr/docs/index.md +++ b/docs/fr/docs/index.md @@ -44,13 +44,16 @@ The key features are: * estimation based on tests on an internal development team, building production applications. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/id/docs/index.md b/docs/id/docs/index.md index edc19fa48..95fb7ae21 100644 --- a/docs/id/docs/index.md +++ b/docs/id/docs/index.md @@ -44,13 +44,16 @@ The key features are: * estimation based on tests on an internal development team, building production applications. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/it/docs/index.md b/docs/it/docs/index.md index 318acc413..c52f07e59 100644 --- a/docs/it/docs/index.md +++ b/docs/it/docs/index.md @@ -44,13 +44,16 @@ The key features are: * estimation based on tests on an internal development team, building production applications. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/ja/docs/fastapi-people.md b/docs/ja/docs/fastapi-people.md index b284698b6..1d263449a 100644 --- a/docs/ja/docs/fastapi-people.md +++ b/docs/ja/docs/fastapi-people.md @@ -119,7 +119,7 @@ FastAPIには、様々なバックグラウンドの人々を歓迎する素晴 {% if sponsors %} {% for sponsor in sponsors.gold -%} - + {% endfor %} {% endif %} @@ -127,15 +127,23 @@ FastAPIには、様々なバックグラウンドの人々を歓迎する素晴 {% if sponsors %} {% for sponsor in sponsors.silver -%} - + {% endfor %} {% endif %} +### Bronze Sponsors + +{% if sponsors %} +{% for sponsor in sponsors.bronze -%} + +{% endfor %} +{% endif %} + +### Individual Sponsors + {% if people %} {% if people.sponsors_50 %} -### Bronze Sponsors -
{% for user in people.sponsors_50 %} @@ -147,8 +155,6 @@ FastAPIには、様々なバックグラウンドの人々を歓迎する素晴 {% endif %} {% endif %} -### Individual Sponsors - {% if people %}
{% for user in people.sponsors %} diff --git a/docs/ja/docs/index.md b/docs/ja/docs/index.md index 87dac8832..229361503 100644 --- a/docs/ja/docs/index.md +++ b/docs/ja/docs/index.md @@ -40,13 +40,16 @@ FastAPI は、Pythonの標準である型ヒントに基づいてPython 3.6 以 \* 本番アプリケーションを構築している開発チームのテストによる見積もり。 -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md index 71533f5eb..ee3edded6 100644 --- a/docs/ko/docs/index.md +++ b/docs/ko/docs/index.md @@ -46,7 +46,10 @@ FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트 {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/pl/docs/index.md b/docs/pl/docs/index.md index edc19fa48..95fb7ae21 100644 --- a/docs/pl/docs/index.md +++ b/docs/pl/docs/index.md @@ -44,13 +44,16 @@ The key features are: * estimation based on tests on an internal development team, building production applications. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md index 97ca5a056..63f1f88fe 100644 --- a/docs/pt/docs/index.md +++ b/docs/pt/docs/index.md @@ -39,13 +39,16 @@ Os recursos chave são: * estimativas baseadas em testes realizados com equipe interna de desenvolvimento, construindo aplicações em produção. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index c5dac9c39..0c2506b87 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -44,13 +44,16 @@ The key features are: * estimation based on tests on an internal development team, building production applications. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/sq/docs/index.md b/docs/sq/docs/index.md index edc19fa48..95fb7ae21 100644 --- a/docs/sq/docs/index.md +++ b/docs/sq/docs/index.md @@ -44,13 +44,16 @@ The key features are: * estimation based on tests on an internal development team, building production applications. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md index 261471961..282e2b603 100644 --- a/docs/tr/docs/index.md +++ b/docs/tr/docs/index.md @@ -44,13 +44,16 @@ The key features are: * estimation based on tests on an internal development team, building production applications. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/uk/docs/index.md b/docs/uk/docs/index.md index edc19fa48..95fb7ae21 100644 --- a/docs/uk/docs/index.md +++ b/docs/uk/docs/index.md @@ -44,13 +44,16 @@ The key features are: * estimation based on tests on an internal development team, building production applications. -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} diff --git a/docs/zh/docs/fastapi-people.md b/docs/zh/docs/fastapi-people.md index 080af2ee6..ea239e6ca 100644 --- a/docs/zh/docs/fastapi-people.md +++ b/docs/zh/docs/fastapi-people.md @@ -116,20 +116,33 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋 ### 金牌赞助商 -{% if sponsors %} {% for sponsor in sponsors.gold -%} - -{% endfor %} {% endif %} +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} ### 银牌赞助商 -{% if sponsors %} {% for sponsor in sponsors.silver -%} - -{% endfor %} {% endif %} - -{% if people %} {% if people.sponsors_50 %} +{% if sponsors %} +{% for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} ### 铜牌赞助商 +{% if sponsors %} +{% for sponsor in sponsors.bronze -%} + +{% endfor %} +{% endif %} + +### 个人赞助 + +{% if people %} +{% if people.sponsors_50 %} +
{% for user in people.sponsors_50 %} @@ -138,9 +151,8 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋
-{% endif %} {% endif %} - -### 个人赞助 +{% endif %} +{% endif %} {% if people %}
diff --git a/docs/zh/docs/index.md b/docs/zh/docs/index.md index 0c73578aa..85707e573 100644 --- a/docs/zh/docs/index.md +++ b/docs/zh/docs/index.md @@ -40,13 +40,16 @@ FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框 * 根据对某个构建线上应用的内部开发团队所进行的测试估算得出。 -## Gold Sponsors +## Sponsors {% if sponsors %} {% for sponsor in sponsors.gold -%} - + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + {% endfor %} {% endif %} From bcd06fdfdf4662452e1076882635bbd18865b197 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 12:11:22 +0000 Subject: [PATCH 103/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 53f15a435..60c6c428b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🎨 Improve style for sponsors, add radius border. PR [#2388](https://github.com/tiangolo/fastapi/pull/2388) by [@Kludex](https://github.com/Kludex). * 📝 Add External Link: Deploy FastAPI on Ubuntu and Serve using Caddy 2 Web Server. PR [#3572](https://github.com/tiangolo/fastapi/pull/3572) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes. PR [#3574](https://github.com/tiangolo/fastapi/pull/3574) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes. PR [#3573](https://github.com/tiangolo/fastapi/pull/3573) by [@tiangolo](https://github.com/tiangolo). From 1ce7258a018d0ab190b4b80683f938798aa8577f Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Wed, 21 Jul 2021 14:14:34 +0200 Subject: [PATCH 104/814] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20typo=20on=20?= =?UTF-8?q?docstring=20in=20datastructures=20file=20(#2887)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/datastructures.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py index f22409c51..6a44a7df4 100644 --- a/fastapi/datastructures.py +++ b/fastapi/datastructures.py @@ -21,7 +21,7 @@ class DefaultPlaceholder: You shouldn't use this class directly. It's used internally to recognize when a default value has been overwritten, even - if the overriden default value was truthy. + if the overridden default value was truthy. """ def __init__(self, value: Any): @@ -42,6 +42,6 @@ def Default(value: DefaultType) -> DefaultType: You shouldn't use this function directly. It's used internally to recognize when a default value has been overwritten, even - if the overriden default value was truthy. + if the overridden default value was truthy. """ return DefaultPlaceholder(value) # type: ignore From 0d97e1f97dd141a0961c8c153262ba6e7341928d Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 12:15:08 +0000 Subject: [PATCH 105/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 60c6c428b..a82de67c2 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix typo on docstring in datastructures file. PR [#2887](https://github.com/tiangolo/fastapi/pull/2887) by [@Kludex](https://github.com/Kludex). * 🎨 Improve style for sponsors, add radius border. PR [#2388](https://github.com/tiangolo/fastapi/pull/2388) by [@Kludex](https://github.com/Kludex). * 📝 Add External Link: Deploy FastAPI on Ubuntu and Serve using Caddy 2 Web Server. PR [#3572](https://github.com/tiangolo/fastapi/pull/3572) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes. PR [#3574](https://github.com/tiangolo/fastapi/pull/3574) by [@tiangolo](https://github.com/tiangolo). From b9fed9b4859f37550776e6074e0faae50be1caab Mon Sep 17 00:00:00 2001 From: Rodrigo Arenas <31422766+rodrigo-arenas@users.noreply.github.com> Date: Wed, 21 Jul 2021 07:20:53 -0500 Subject: [PATCH 106/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link:?= =?UTF-8?q?=20Serve=20a=20machine=20learning=20model=20using=20Sklearn,=20?= =?UTF-8?q?FastAPI=20and=20Docker=20(#2974)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: rodrigoarenas456 <31422766+rodrigoarenas456@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index d1972d5e1..571709e78 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: Rodrigo Arenas + author_link: https://rodrigo-arenas.medium.com/ + link: https://medium.com/analytics-vidhya/serve-a-machine-learning-model-using-sklearn-fastapi-and-docker-85aabf96729b + title: "Serve a machine learning model using Sklearn, FastAPI and Docker" - author: Navule Pavan Kumar Rao author_link: https://www.linkedin.com/in/navule/ link: https://www.tutlinks.com/deploy-fastapi-on-ubuntu-gunicorn-caddy-2/ From 9ce1ae771cb3835d45e309b8785eb74acf391d17 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 12:21:46 +0000 Subject: [PATCH 107/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a82de67c2..60cc788e1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link: Serve a machine learning model using Sklearn, FastAPI and Docker. PR [#2974](https://github.com/tiangolo/fastapi/pull/2974) by [@rodrigo-arenas](https://github.com/rodrigo-arenas). * ✏️ Fix typo on docstring in datastructures file. PR [#2887](https://github.com/tiangolo/fastapi/pull/2887) by [@Kludex](https://github.com/Kludex). * 🎨 Improve style for sponsors, add radius border. PR [#2388](https://github.com/tiangolo/fastapi/pull/2388) by [@Kludex](https://github.com/Kludex). * 📝 Add External Link: Deploy FastAPI on Ubuntu and Serve using Caddy 2 Web Server. PR [#3572](https://github.com/tiangolo/fastapi/pull/3572) by [@tiangolo](https://github.com/tiangolo). From a1227624c8434544161bbba9fcaaf185cb2f26a9 Mon Sep 17 00:00:00 2001 From: Shahriyar Rzayev Date: Wed, 21 Jul 2021 16:28:15 +0400 Subject: [PATCH 108/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link:?= =?UTF-8?q?=20Building=20simple=20E-Commerce=20with=20NuxtJS=20and=20FastA?= =?UTF-8?q?PI=20(#3271)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index 571709e78..abc23ba55 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: Shahriyar(Shako) Rzayev + author_link: https://www.linkedin.com/in/shahriyar-rzayev/ + link: https://www.azepug.az/posts/fastapi/#building-simple-e-commerce-with-nuxtjs-and-fastapi-series + title: Building simple E-Commerce with NuxtJS and FastAPI - author: Rodrigo Arenas author_link: https://rodrigo-arenas.medium.com/ link: https://medium.com/analytics-vidhya/serve-a-machine-learning-model-using-sklearn-fastapi-and-docker-85aabf96729b From ba596152d9a66fe46f2834a08766edb2d35769f5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 12:28:48 +0000 Subject: [PATCH 109/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 60cc788e1..45ab8ad43 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link: Building simple E-Commerce with NuxtJS and FastAPI. PR [#3271](https://github.com/tiangolo/fastapi/pull/3271) by [@ShahriyarR](https://github.com/ShahriyarR). * 📝 Add external link: Serve a machine learning model using Sklearn, FastAPI and Docker. PR [#2974](https://github.com/tiangolo/fastapi/pull/2974) by [@rodrigo-arenas](https://github.com/rodrigo-arenas). * ✏️ Fix typo on docstring in datastructures file. PR [#2887](https://github.com/tiangolo/fastapi/pull/2887) by [@Kludex](https://github.com/Kludex). * 🎨 Improve style for sponsors, add radius border. PR [#2388](https://github.com/tiangolo/fastapi/pull/2388) by [@Kludex](https://github.com/Kludex). From 4cb4bdb9848798252f8decd6a1691968c09b15e0 Mon Sep 17 00:00:00 2001 From: David Brakman Date: Wed, 21 Jul 2021 08:37:06 -0400 Subject: [PATCH 110/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20"might=20me"?= =?UTF-8?q?=20->=20"might=20be"=20in=20`docs/en/docs/tutorial/schema-extra?= =?UTF-8?q?-example.md`=20(#3362)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/schema-extra-example.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md index 47ee8503a..71f9a3918 100644 --- a/docs/en/docs/tutorial/schema-extra-example.md +++ b/docs/en/docs/tutorial/schema-extra-example.md @@ -88,7 +88,7 @@ With `examples` added to `Body()` the `/docs` would look like: !!! warning These are very technical details about the standards **JSON Schema** and **OpenAPI**. - If the ideas above already work for you, that might me enough, and you probably don't need these details, feel free to skip them. + If the ideas above already work for you, that might be enough, and you probably don't need these details, feel free to skip them. When you add an example inside of a Pydantic model, using `schema_extra` or `Field(example="something")` that example is added to the **JSON Schema** for that Pydantic model. From b235653a6c191fe44ba52fe49e97fef307cbb0ba Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 12:37:40 +0000 Subject: [PATCH 111/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 45ab8ad43..c2a81e3e8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo "might me" -> "might be" in `docs/en/docs/tutorial/schema-extra-example.md`. PR [#3362](https://github.com/tiangolo/fastapi/pull/3362) by [@dbrakman](https://github.com/dbrakman). * 📝 Add external link: Building simple E-Commerce with NuxtJS and FastAPI. PR [#3271](https://github.com/tiangolo/fastapi/pull/3271) by [@ShahriyarR](https://github.com/ShahriyarR). * 📝 Add external link: Serve a machine learning model using Sklearn, FastAPI and Docker. PR [#2974](https://github.com/tiangolo/fastapi/pull/2974) by [@rodrigo-arenas](https://github.com/rodrigo-arenas). * ✏️ Fix typo on docstring in datastructures file. PR [#2887](https://github.com/tiangolo/fastapi/pull/2887) by [@Kludex](https://github.com/Kludex). From e4eac12c340de5905788a5acc941e513107c6b2a Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Wed, 21 Jul 2021 20:41:24 +0800 Subject: [PATCH 112/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20in=20`body-nes?= =?UTF-8?q?ted-models.md`=20(#3462)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typo in line 201, *where* should be *were* --- docs/en/docs/tutorial/body-nested-models.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/body-nested-models.md b/docs/en/docs/tutorial/body-nested-models.md index 14e725a21..7435e22d9 100644 --- a/docs/en/docs/tutorial/body-nested-models.md +++ b/docs/en/docs/tutorial/body-nested-models.md @@ -198,7 +198,7 @@ Even for items inside of lists: -You couldn't get this kind of editor support if you where working directly with `dict` instead of Pydantic models. +You couldn't get this kind of editor support if you were working directly with `dict` instead of Pydantic models. But you don't have to worry about them either, incoming dicts are converted automatically and your output is converted automatically to JSON too. From fd74c0f6a43ba4b59787e409b791543f5f2d417c Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 12:42:05 +0000 Subject: [PATCH 113/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c2a81e3e8..1f114d623 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo in `body-nested-models.md`. PR [#3462](https://github.com/tiangolo/fastapi/pull/3462) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo "might me" -> "might be" in `docs/en/docs/tutorial/schema-extra-example.md`. PR [#3362](https://github.com/tiangolo/fastapi/pull/3362) by [@dbrakman](https://github.com/dbrakman). * 📝 Add external link: Building simple E-Commerce with NuxtJS and FastAPI. PR [#3271](https://github.com/tiangolo/fastapi/pull/3271) by [@ShahriyarR](https://github.com/ShahriyarR). * 📝 Add external link: Serve a machine learning model using Sklearn, FastAPI and Docker. PR [#2974](https://github.com/tiangolo/fastapi/pull/2974) by [@rodrigo-arenas](https://github.com/rodrigo-arenas). From 1241f7f0b79a780e77a7748deaf48341e6a7472a Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Wed, 21 Jul 2021 20:44:15 +0800 Subject: [PATCH 114/814] =?UTF-8?q?=E2=9C=8F=20Fix=20code=20highlighted=20?= =?UTF-8?q?line=20in:=20`body-nested-models.md`=20(#3463)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/tutorial/body-nested-models.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/body-nested-models.md b/docs/en/docs/tutorial/body-nested-models.md index 7435e22d9..5bacf1666 100644 --- a/docs/en/docs/tutorial/body-nested-models.md +++ b/docs/en/docs/tutorial/body-nested-models.md @@ -218,7 +218,7 @@ That's what we are going to see here. In this case, you would accept any `dict` as long as it has `int` keys with `float` values: -```Python hl_lines="15" +```Python hl_lines="9" {!../../../docs_src/body_nested_models/tutorial009.py!} ``` From 1ce59152e7edc2e7a706470a196e69404dc79374 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 12:44:53 +0000 Subject: [PATCH 115/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1f114d623..2061aee21 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix code highlighted line in: `body-nested-models.md`. PR [#3463](https://github.com/tiangolo/fastapi/pull/3463) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo in `body-nested-models.md`. PR [#3462](https://github.com/tiangolo/fastapi/pull/3462) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo "might me" -> "might be" in `docs/en/docs/tutorial/schema-extra-example.md`. PR [#3362](https://github.com/tiangolo/fastapi/pull/3362) by [@dbrakman](https://github.com/dbrakman). * 📝 Add external link: Building simple E-Commerce with NuxtJS and FastAPI. PR [#3271](https://github.com/tiangolo/fastapi/pull/3271) by [@ShahriyarR](https://github.com/ShahriyarR). From 9355cc4eaa58f63d29f1730bd40590fb93bc66fa Mon Sep 17 00:00:00 2001 From: Ehigie Aito Date: Wed, 21 Jul 2021 14:15:33 +0100 Subject: [PATCH 116/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link:?= =?UTF-8?q?=20How=20to=20Create=20A=20Fake=20Certificate=20Authority=20And?= =?UTF-8?q?=20Generate=20TLS=20Certs=20for=20FastAPI=20(#2839)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index abc23ba55..40bf5ef04 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: "@pystar" + author_link: https://pystar.substack.com/ + link: https://pystar.substack.com/p/how-to-create-a-fake-certificate + title: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI - author: Shahriyar(Shako) Rzayev author_link: https://www.linkedin.com/in/shahriyar-rzayev/ link: https://www.azepug.az/posts/fastapi/#building-simple-e-commerce-with-nuxtjs-and-fastapi-series From 49517d331049a88116d1b8bdbc4d7126311bd20d Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 13:16:08 +0000 Subject: [PATCH 117/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2061aee21..209a39e40 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI. PR [#2839](https://github.com/tiangolo/fastapi/pull/2839) by [@aitoehigie](https://github.com/aitoehigie). * ✏ Fix code highlighted line in: `body-nested-models.md`. PR [#3463](https://github.com/tiangolo/fastapi/pull/3463) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo in `body-nested-models.md`. PR [#3462](https://github.com/tiangolo/fastapi/pull/3462) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo "might me" -> "might be" in `docs/en/docs/tutorial/schema-extra-example.md`. PR [#3362](https://github.com/tiangolo/fastapi/pull/3362) by [@dbrakman](https://github.com/dbrakman). From 96fdfc53cc47f30cff59bb847c2c19b79fd9efcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 16:39:12 +0200 Subject: [PATCH 118/814] =?UTF-8?q?=E2=9C=A8=20Support=20`dataclasses`=20i?= =?UTF-8?q?n=20responses=20(#3576)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: amit lissack --- fastapi/encoders.py | 3 ++ fastapi/routing.py | 3 ++ tests/test_serialize_response_dataclass.py | 60 ++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/fastapi/encoders.py b/fastapi/encoders.py index 51cab419d..3f599c9fa 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -1,3 +1,4 @@ +import dataclasses from collections import defaultdict from enum import Enum from pathlib import PurePath @@ -61,6 +62,8 @@ def jsonable_encoder( custom_encoder=encoder, sqlalchemy_safe=sqlalchemy_safe, ) + if dataclasses.is_dataclass(obj): + return dataclasses.asdict(obj) if isinstance(obj, Enum): return obj.value if isinstance(obj, PurePath): diff --git a/fastapi/routing.py b/fastapi/routing.py index a7c62af3c..f5fe0c0bd 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -1,4 +1,5 @@ import asyncio +import dataclasses import email.message import enum import inspect @@ -90,6 +91,8 @@ def _prepare_response_content( ) for k, v in res.items() } + elif dataclasses.is_dataclass(res): + return dataclasses.asdict(res) return res diff --git a/tests/test_serialize_response_dataclass.py b/tests/test_serialize_response_dataclass.py index d1b64c4e8..e520338ec 100644 --- a/tests/test_serialize_response_dataclass.py +++ b/tests/test_serialize_response_dataclass.py @@ -19,6 +19,11 @@ def get_valid(): return {"name": "valid", "price": 1.0} +@app.get("/items/object", response_model=Item) +def get_object(): + return Item(name="object", price=1.0, owner_ids=[1, 2, 3]) + + @app.get("/items/coerce", response_model=Item) def get_coerce(): return {"name": "coerce", "price": "1.0"} @@ -33,6 +38,29 @@ def get_validlist(): ] +@app.get("/items/objectlist", response_model=List[Item]) +def get_objectlist(): + return [ + Item(name="foo"), + Item(name="bar", price=1.0), + Item(name="baz", price=2.0, owner_ids=[1, 2, 3]), + ] + + +@app.get("/items/no-response-model/object") +def get_no_response_model_object(): + return Item(name="object", price=1.0, owner_ids=[1, 2, 3]) + + +@app.get("/items/no-response-model/objectlist") +def get_no_response_model_objectlist(): + return [ + Item(name="foo"), + Item(name="bar", price=1.0), + Item(name="baz", price=2.0, owner_ids=[1, 2, 3]), + ] + + client = TestClient(app) @@ -42,6 +70,12 @@ def test_valid(): assert response.json() == {"name": "valid", "price": 1.0, "owner_ids": None} +def test_object(): + response = client.get("/items/object") + response.raise_for_status() + assert response.json() == {"name": "object", "price": 1.0, "owner_ids": [1, 2, 3]} + + def test_coerce(): response = client.get("/items/coerce") response.raise_for_status() @@ -56,3 +90,29 @@ def test_validlist(): {"name": "bar", "price": 1.0, "owner_ids": None}, {"name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]}, ] + + +def test_objectlist(): + response = client.get("/items/objectlist") + response.raise_for_status() + assert response.json() == [ + {"name": "foo", "price": None, "owner_ids": None}, + {"name": "bar", "price": 1.0, "owner_ids": None}, + {"name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]}, + ] + + +def test_no_response_model_object(): + response = client.get("/items/no-response-model/object") + response.raise_for_status() + assert response.json() == {"name": "object", "price": 1.0, "owner_ids": [1, 2, 3]} + + +def test_no_response_model_objectlist(): + response = client.get("/items/no-response-model/objectlist") + response.raise_for_status() + assert response.json() == [ + {"name": "foo", "price": None, "owner_ids": None}, + {"name": "bar", "price": 1.0, "owner_ids": None}, + {"name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]}, + ] From 75d8a6b5c2de727f5926087fe0ee52cd48e5aebb Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 14:39:54 +0000 Subject: [PATCH 119/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 209a39e40..83506539c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Support `dataclasses` in responses. PR [#3576](https://github.com/tiangolo/fastapi/pull/3576) by [@tiangolo](https://github.com/tiangolo). * 📝 Add external link: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI. PR [#2839](https://github.com/tiangolo/fastapi/pull/2839) by [@aitoehigie](https://github.com/aitoehigie). * ✏ Fix code highlighted line in: `body-nested-models.md`. PR [#3463](https://github.com/tiangolo/fastapi/pull/3463) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo in `body-nested-models.md`. PR [#3462](https://github.com/tiangolo/fastapi/pull/3462) by [@jaystone776](https://github.com/jaystone776). From 684c0077cc0ef48364cd3241b80a135213376d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 19:54:08 +0200 Subject: [PATCH 120/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20`data?= =?UTF-8?q?classes`=20in=20request=20bodies=20and=20`response=5Fmodel`=20(?= =?UTF-8?q?#3577)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/dataclasses.md | 98 ++++++++++ .../docs/img/tutorial/dataclasses/image01.png | Bin 0 -> 72574 bytes docs/en/mkdocs.yml | 1 + docs_src/dataclasses/tutorial001.py | 20 ++ docs_src/dataclasses/tutorial002.py | 26 +++ docs_src/dataclasses/tutorial003.py | 55 ++++++ fastapi/dependencies/utils.py | 2 + .../test_dataclasses/test_tutorial001.py | 113 +++++++++++ .../test_dataclasses/test_tutorial002.py | 66 +++++++ .../test_dataclasses/test_tutorial003.py | 181 ++++++++++++++++++ 10 files changed, 562 insertions(+) create mode 100644 docs/en/docs/advanced/dataclasses.md create mode 100644 docs/en/docs/img/tutorial/dataclasses/image01.png create mode 100644 docs_src/dataclasses/tutorial001.py create mode 100644 docs_src/dataclasses/tutorial002.py create mode 100644 docs_src/dataclasses/tutorial003.py create mode 100644 tests/test_tutorial/test_dataclasses/test_tutorial001.py create mode 100644 tests/test_tutorial/test_dataclasses/test_tutorial002.py create mode 100644 tests/test_tutorial/test_dataclasses/test_tutorial003.py diff --git a/docs/en/docs/advanced/dataclasses.md b/docs/en/docs/advanced/dataclasses.md new file mode 100644 index 000000000..80a063bb8 --- /dev/null +++ b/docs/en/docs/advanced/dataclasses.md @@ -0,0 +1,98 @@ +# Using Dataclasses + +FastAPI is built on top of **Pydantic**, and I have been showing you how to use Pydantic models to declare requests and responses. + +But FastAPI also supports using `dataclasses` the same way: + +```Python hl_lines="1 7-12 19-20" +{!../../../docs_src/dataclasses/tutorial001.py!} +``` + +This is still thanks to **Pydantic**, as it has internal support for `dataclasses`. + +So, even with the code above that doesn't use Pydantic explicitly, FastAPI is using Pydantic to convert those standard dataclasses to Pydantic's own flavor of dataclasses. + +And of course, it supports the same: + +* data validation +* data serialization +* data documentation, etc. + +This works the same way as with Pydantic models. And it is actually achieved in the same way underneath, using Pydantic. + +!!! info + Have in mind that dataclasses can't do everything Pydantic models can do. + + So, you might still need to use Pydantic models. + + But if you have a bunch of dataclasses laying around, this is a nice trick to use them to power a web API using FastAPI. 🤓 + +## Dataclasses in `response_model` + +You can also use `dataclasses` in the `response_model` parameter: + +```Python hl_lines="1 7-13 19" +{!../../../docs_src/dataclasses/tutorial002.py!} +``` + +The dataclass will be automatically converted to a Pydantic dataclass. + +This way, its schema will show up in the API docs user interface: + + + +## Dataclasses in Nested Data Structures + +You can also combine `dataclasses` with other type annotations to make nested data structures. + +In some cases, you might still have to use Pydantic's version of `dataclasses`. For example, if you have errors with the automatically generated API documentation. + +In that case, you can simply swap the standard `dataclasses` with `pydantic.dataclasses`, which is a drop-in replacement: + +```{ .python .annotate hl_lines="1 5 8-11 14-17 23-25 28" } +{!../../../docs_src/dataclasses/tutorial003.py!} +``` + +1. We still import `field` from standard `dataclasses`. + +2. `pydantic.dataclasses` is a drop-in replacement for `dataclasses`. + +3. The `Author` dataclass includes a list of `Item` dataclasses. + +4. The `Author` dataclass is used as the `response_model` parameter. + +5. You can use other standard type annotations with dataclasses as the request body. + + In this case, it's a list of `Item` dataclasses. + +6. Here we are returning a dictionary that contains `items` which is a list of dataclasses. + + FastAPI is still capable of serializing the data to JSON. + +7. Here the `response_model` is using a type annotation of a list of `Author` dataclasses. + + Again, you can combine `dataclasses` with standard type annotations. + +8. Notice that this *path operation function* uses regular `def` instead of `async def`. + + As always, in FastAPI you can combine `def` and `async def` as needed. + + If you need a refresher about when to use which, check out the section _"In a hurry?"_ in the docs about `async` and `await`. + +9. This *path operation function* is not returning dataclasses (although it could), but a list of dictionaries with internal data. + + FastAPI will use the `response_model` parameter (that includes dataclasses) to convert the response. + +You can combine `dataclasses` with other type annotations in many different combinations to form complex data structures. + +Check the in-code annotation tips above to see more specific details. + +## Learn More + +You can also combine `dataclasses` with other Pydantic models, inherit from them, include them in your own models, etc. + +To learn more, check the Pydantic docs about dataclasses. + +## Version + +This is available since FastAPI version `0.67.0`. 🔖 diff --git a/docs/en/docs/img/tutorial/dataclasses/image01.png b/docs/en/docs/img/tutorial/dataclasses/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..7815f40adf065b51cd1a1e9fb2cd0221db2bcba7 GIT binary patch literal 72574 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 bool: field.shape == SHAPE_SINGLETON and not lenient_issubclass(field.type_, BaseModel) and not lenient_issubclass(field.type_, sequence_types + (dict,)) + and not dataclasses.is_dataclass(field.type_) and not isinstance(field_info, params.Body) ): return False diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial001.py b/tests/test_tutorial/test_dataclasses/test_tutorial001.py new file mode 100644 index 000000000..3e3fc9acf --- /dev/null +++ b/tests/test_tutorial/test_dataclasses/test_tutorial001.py @@ -0,0 +1,113 @@ +from fastapi.testclient import TestClient + +from docs_src.dataclasses.tutorial001 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + "description": {"title": "Description", "type": "string"}, + "tax": {"title": "Tax", "type": "number"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_schema + + +def test_post_item(): + response = client.post("/items/", json={"name": "Foo", "price": 3}) + assert response.status_code == 200 + assert response.json() == { + "name": "Foo", + "price": 3, + "description": None, + "tax": None, + } + + +def test_post_invalid_item(): + response = client.post("/items/", json={"name": "Foo", "price": "invalid price"}) + assert response.status_code == 422 + assert response.json() == { + "detail": [ + { + "loc": ["body", "price"], + "msg": "value is not a valid float", + "type": "type_error.float", + } + ] + } diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial002.py b/tests/test_tutorial/test_dataclasses/test_tutorial002.py new file mode 100644 index 000000000..10d8d227d --- /dev/null +++ b/tests/test_tutorial/test_dataclasses/test_tutorial002.py @@ -0,0 +1,66 @@ +from fastapi.testclient import TestClient + +from docs_src.dataclasses.tutorial002 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/next": { + "get": { + "summary": "Read Next Item", + "operationId": "read_next_item_items_next_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + } + }, + } + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "required": ["name", "price", "tags"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + "tags": { + "title": "Tags", + "type": "array", + "items": {"type": "string"}, + }, + "description": {"title": "Description", "type": "string"}, + "tax": {"title": "Tax", "type": "number"}, + }, + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_schema + + +def test_get_item(): + response = client.get("/items/next") + assert response.status_code == 200 + assert response.json() == { + "name": "Island In The Moon", + "price": 12.99, + "description": "A place to be be playin' and havin' fun", + "tags": ["breater"], + "tax": None, + } diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py new file mode 100644 index 000000000..dd0f1f2c0 --- /dev/null +++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py @@ -0,0 +1,181 @@ +from fastapi.testclient import TestClient + +from docs_src.dataclasses.tutorial003 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "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": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_schema + + +def test_post_authors_item(): + response = client.post( + "/authors/foo/items/", + json=[{"name": "Bar"}, {"name": "Baz", "description": "Drop the Baz"}], + ) + assert response.status_code == 200 + assert response.json() == { + "name": "foo", + "items": [ + {"name": "Bar", "description": None}, + {"name": "Baz", "description": "Drop the Baz"}, + ], + } + + +def test_get_authors(): + response = client.get("/authors/") + assert response.status_code == 200 + assert response.json() == [ + { + "name": "Breaters", + "items": [ + { + "name": "Island In The Moon", + "description": "A place to be be playin' and havin' fun", + }, + {"name": "Holy Buddies", "description": None}, + ], + }, + { + "name": "System of an Up", + "items": [ + { + "name": "Salt", + "description": "The kombucha mushroom people's favorite", + }, + {"name": "Pad Thai", "description": None}, + { + "name": "Lonely Night", + "description": "The mostests lonliest nightiest of allest", + }, + ], + }, + ] From 7dc5b94d452a114b12fd3aaaeb9b5520ece7da84 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 17:54:42 +0000 Subject: [PATCH 121/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 83506539c..b4744f421 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for `dataclasses` in request bodies and `response_model`. PR [#3577](https://github.com/tiangolo/fastapi/pull/3577) by [@tiangolo](https://github.com/tiangolo). * ✨ Support `dataclasses` in responses. PR [#3576](https://github.com/tiangolo/fastapi/pull/3576) by [@tiangolo](https://github.com/tiangolo). * 📝 Add external link: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI. PR [#2839](https://github.com/tiangolo/fastapi/pull/2839) by [@aitoehigie](https://github.com/aitoehigie). * ✏ Fix code highlighted line in: `body-nested-models.md`. PR [#3463](https://github.com/tiangolo/fastapi/pull/3463) by [@jaystone776](https://github.com/jaystone776). From 099aab79e6727c349bd788615cae34c635bb0b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 19:59:38 +0200 Subject: [PATCH 122/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b4744f421..b8e3c5841 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,8 +2,13 @@ ## Latest Changes -* ✨ Add support for `dataclasses` in request bodies and `response_model`. PR [#3577](https://github.com/tiangolo/fastapi/pull/3577) by [@tiangolo](https://github.com/tiangolo). -* ✨ Support `dataclasses` in responses. PR [#3576](https://github.com/tiangolo/fastapi/pull/3576) by [@tiangolo](https://github.com/tiangolo). +### Features + +* ✨ Add support for `dataclasses` in request bodies and `response_model`. New documentation: [Advanced User Guide - Using Dataclasses](https://fastapi.tiangolo.com/advanced/dataclasses/). PR [#3577](https://github.com/tiangolo/fastapi/pull/3577) by [@tiangolo](https://github.com/tiangolo). +* ✨ Support `dataclasses` in responses. PR [#3576](https://github.com/tiangolo/fastapi/pull/3576) by [@tiangolo](https://github.com/tiangolo), continuation from initial PR [#2722](https://github.com/tiangolo/fastapi/pull/2722) by [@amitlissack](https://github.com/amitlissack). + +### Docs + * 📝 Add external link: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI. PR [#2839](https://github.com/tiangolo/fastapi/pull/2839) by [@aitoehigie](https://github.com/aitoehigie). * ✏ Fix code highlighted line in: `body-nested-models.md`. PR [#3463](https://github.com/tiangolo/fastapi/pull/3463) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo in `body-nested-models.md`. PR [#3462](https://github.com/tiangolo/fastapi/pull/3462) by [@jaystone776](https://github.com/jaystone776). @@ -11,14 +16,18 @@ * 📝 Add external link: Building simple E-Commerce with NuxtJS and FastAPI. PR [#3271](https://github.com/tiangolo/fastapi/pull/3271) by [@ShahriyarR](https://github.com/ShahriyarR). * 📝 Add external link: Serve a machine learning model using Sklearn, FastAPI and Docker. PR [#2974](https://github.com/tiangolo/fastapi/pull/2974) by [@rodrigo-arenas](https://github.com/rodrigo-arenas). * ✏️ Fix typo on docstring in datastructures file. PR [#2887](https://github.com/tiangolo/fastapi/pull/2887) by [@Kludex](https://github.com/Kludex). -* 🎨 Improve style for sponsors, add radius border. PR [#2388](https://github.com/tiangolo/fastapi/pull/2388) by [@Kludex](https://github.com/Kludex). * 📝 Add External Link: Deploy FastAPI on Ubuntu and Serve using Caddy 2 Web Server. PR [#3572](https://github.com/tiangolo/fastapi/pull/3572) by [@tiangolo](https://github.com/tiangolo). +* 📝 Add External Link, replaces #1898. PR [#3571](https://github.com/tiangolo/fastapi/pull/3571) by [@tiangolo](https://github.com/tiangolo). + +### Internal + +* 🎨 Improve style for sponsors, add radius border. PR [#2388](https://github.com/tiangolo/fastapi/pull/2388) by [@Kludex](https://github.com/Kludex). * 👷 Update GitHub Action latest-changes. PR [#3574](https://github.com/tiangolo/fastapi/pull/3574) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes. PR [#3573](https://github.com/tiangolo/fastapi/pull/3573) by [@tiangolo](https://github.com/tiangolo). -* 🔧 Add External Link, replaces #1898. PR [#3571](https://github.com/tiangolo/fastapi/pull/3571) by [@tiangolo](https://github.com/tiangolo). * 👷 Rename and clarify CI workflow job names. PR [#3570](https://github.com/tiangolo/fastapi/pull/3570) by [@tiangolo](https://github.com/tiangolo). * 👷 Update GitHub Action latest-changes, strike 2 ⚾. PR [#3575](https://github.com/tiangolo/fastapi/pull/3575) by [@tiangolo](https://github.com/tiangolo). * 🔧 Sort external links in docs to have the most recent at the top. PR [#3568](https://github.com/tiangolo/fastapi/pull/3568) by [@tiangolo](https://github.com/tiangolo). + ## 0.66.1 ### Translations From a0209a0d2c26628809fd885a4c211c6248082921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 20:00:39 +0200 Subject: [PATCH 123/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.67?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b8e3c5841..e35d6f3c4 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.67.0 + ### Features * ✨ Add support for `dataclasses` in request bodies and `response_model`. New documentation: [Advanced User Guide - Using Dataclasses](https://fastapi.tiangolo.com/advanced/dataclasses/). PR [#3577](https://github.com/tiangolo/fastapi/pull/3577) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 7ae93ef8c..61737d47f 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.66.1" +__version__ = "0.67.0" from starlette import status as status From dbfd3f7e18f8152c133a3f4836297253acedd5d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 21:13:58 +0200 Subject: [PATCH 124/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20official=20FastAPI?= =?UTF-8?q?=20Twitter=20to=20docs=20(#3578)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/de/mkdocs.yml | 2 +- docs/en/docs/css/custom.css | 4 ++++ docs/en/docs/help-fastapi.md | 23 ++++++++++++++--------- docs/en/mkdocs.yml | 2 +- docs/en/overrides/main.html | 7 +++++++ docs/es/mkdocs.yml | 2 +- docs/fr/mkdocs.yml | 2 +- docs/id/mkdocs.yml | 2 +- docs/id/overrides/.gitignore | 0 docs/id/overrides/main.html | 13 ------------- docs/it/mkdocs.yml | 2 +- docs/ja/mkdocs.yml | 2 +- docs/ko/mkdocs.yml | 2 +- docs/pl/mkdocs.yml | 2 +- docs/pt/mkdocs.yml | 2 +- docs/ru/mkdocs.yml | 2 +- docs/sq/mkdocs.yml | 2 +- docs/tr/mkdocs.yml | 2 +- docs/uk/mkdocs.yml | 2 +- docs/zh/mkdocs.yml | 2 +- 20 files changed, 40 insertions(+), 37 deletions(-) create mode 100644 docs/id/overrides/.gitignore delete mode 100644 docs/id/overrides/main.html diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index a00316687..033326486 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -76,7 +76,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css index 9449f0a79..2b6d55173 100644 --- a/docs/en/docs/css/custom.css +++ b/docs/en/docs/css/custom.css @@ -99,3 +99,7 @@ a.announce-link:hover { display: flex; align-items: center; } + +.twitter { + color: #00acee; +} diff --git a/docs/en/docs/help-fastapi.md b/docs/en/docs/help-fastapi.md index 561db2d38..394bccab7 100644 --- a/docs/en/docs/help-fastapi.md +++ b/docs/en/docs/help-fastapi.md @@ -20,6 +20,10 @@ You can subscribe to the (infrequent) [**FastAPI and friends** newsletter](/news * Breaking changes 🚨 * Tips and tricks ✅ +## Follow FastAPI on Twitter + +Follow @fastapi on **Twitter** to get the latest news about **FastAPI**. 🐦 + ## Star **FastAPI** in GitHub You can "star" FastAPI in GitHub (clicking the star button at the top right): https://github.com/tiangolo/fastapi. ⭐️ @@ -32,7 +36,7 @@ You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right) There you can select "Releases only". -Doing it, you will receive notifications (in your email) whenever there's a new release (a new version) of **FastAPI** with bug fixes and new features. +By doing it, you will receive notifications (in your email) whenever there's a new release (a new version) of **FastAPI** with bug fixes and new features. ## Connect with the author @@ -46,17 +50,18 @@ You can: * Follow me on **Twitter**. * Tell me how you use FastAPI (I love to hear that). * Hear when I make announcements or release new tools. + * You can also follow @fastapi on Twitter (a separate account). * Connect with me on **Linkedin**. * Hear when I make announcements or release new tools (although I use Twitter more often 🤷‍♂). * Read what I write (or follow me) on **Dev.to** or **Medium**. - * Read other ideas, articles, and about tools I have created. + * Read other ideas, articles, and read about tools I have created. * Follow me to read when I publish something new. ## Tweet about **FastAPI** -Tweet about **FastAPI** and let me and others know why you like it. 🎉 +Tweet about **FastAPI** and let me and others know why you like it. 🎉 -I love to hear about how **FastAPI** is being used, what have you liked in it, in which project/company are you using it, etc. +I love to hear about how **FastAPI** is being used, what you have liked in it, in which project/company are you using it, etc. ## Vote for FastAPI @@ -67,15 +72,15 @@ I love to hear about how **FastAPI** is being used, what have you liked in it, i You can see existing issues and try and help others, most of the times they are questions that you might already know the answer for. 🤓 -If you are helping a lot of people on issues you might become an official [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}. 🎉 +If you are helping a lot of people with issues, you might become an official [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}. 🎉 ## Watch the GitHub repository You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): https://github.com/tiangolo/fastapi. 👀 -If you select "Watching" instead of "Releases only", you will receive notifications when someone creates a new issue. +If you select "Watching" instead of "Releases only" you will receive notifications when someone creates a new issue. -Then you can try and help them solving those issues. +Then you can try and help them solve those issues. ## Create issues @@ -84,7 +89,7 @@ You can . * Make sure you add your link to the start of the corresponding section. * To help [translate the documentation](contributing.md#translations){.internal-link target=_blank} to your language. - * You can also help reviewing the translations created by others. + * You can also help to review the translations created by others. * To propose new documentation sections. * To fix an existing issue/bug. * To add a new feature. diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index a927bdb3b..d2fe2acaf 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -180,7 +180,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 8e698bffd..eca89a553 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -3,6 +3,13 @@ {% block announce %}
+
diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 40c7c0ec4..e9e651148 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -86,7 +86,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 3b98e3e3f..88b3fe02e 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -84,7 +84,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index ed716124f..983bbd62b 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -76,7 +76,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/id/overrides/.gitignore b/docs/id/overrides/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/docs/id/overrides/main.html b/docs/id/overrides/main.html deleted file mode 100644 index abf6f3108..000000000 --- a/docs/id/overrides/main.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base.html" %} - -{% block announce %} - - - {% include ".icons/material/email.svg" %} - Subscribe to the FastAPI and friends newsletter 🎉 - - -{% endblock %} diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index 11f7fe357..bfe2dfe83 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -76,7 +76,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index ee69e49f8..c1c284316 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -115,7 +115,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index f11333f3e..8d2119db8 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -82,7 +82,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 749d22938..9f12413d9 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -76,7 +76,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index b1fa273cf..617204515 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -89,7 +89,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 6db8fe33d..c737bb2b5 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -76,7 +76,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index 8ebf80358..c5ce8003f 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -76,7 +76,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 660cb9238..d94b527f2 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -76,7 +76,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index 3fdd9825e..4b8983c57 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -76,7 +76,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 5cfc07c6c..b7312b917 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -122,7 +122,7 @@ extra: - icon: fontawesome/brands/discord link: https://discord.gg/VQjSZaeJmf - icon: fontawesome/brands/twitter - link: https://twitter.com/tiangolo + link: https://twitter.com/fastapi - icon: fontawesome/brands/linkedin link: https://www.linkedin.com/in/tiangolo - icon: fontawesome/brands/dev From 0a1dd7894ca8750007e703d64dc8ec38f595d032 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 21 Jul 2021 19:14:32 +0000 Subject: [PATCH 125/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e35d6f3c4..523e507a8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add official FastAPI Twitter to docs. PR [#3578](https://github.com/tiangolo/fastapi/pull/3578) by [@tiangolo](https://github.com/tiangolo). ## 0.67.0 From 996dfd05bde74d8778cf7ad7b5e0dd3588eef9db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 21 Jul 2021 21:15:58 +0200 Subject: [PATCH 126/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 523e507a8..c8230ede2 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,7 @@ ## Latest Changes -* 📝 Add official FastAPI Twitter to docs. PR [#3578](https://github.com/tiangolo/fastapi/pull/3578) by [@tiangolo](https://github.com/tiangolo). +* 📝 Add official FastAPI Twitter to docs: [@fastapi](https://twitter.com/fastapi). PR [#3578](https://github.com/tiangolo/fastapi/pull/3578) by [@tiangolo](https://github.com/tiangolo). ## 0.67.0 From 3f40c379058a92edb0b3215ab684bb98cad1b0ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 27 Jul 2021 12:23:09 +0200 Subject: [PATCH 127/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20new=20GitHub=20tem?= =?UTF-8?q?plates=20with=20forms=20for=20new=20issues=20(#3612)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/config.yml | 3 + .github/ISSUE_TEMPLATE/feature-request.yml | 181 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 104 ------------ .github/ISSUE_TEMPLATE/question.md | 81 --------- .github/ISSUE_TEMPLATE/question.yml | 146 +++++++++++++++++ 5 files changed, 330 insertions(+), 185 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/ISSUE_TEMPLATE/question.md create mode 100644 .github/ISSUE_TEMPLATE/question.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3ba13e0ce..55749398f 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1,4 @@ blank_issues_enabled: false +contact_links: + - name: Security Contact + about: Please report security vulnerabilities to security@tiangolo.com diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 000000000..8176602a7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,181 @@ +name: Feature Request +description: Suggest an idea or ask for a feature that you would like to have in FastAPI +labels: [enhancement] +body: + - type: markdown + attributes: + value: | + Thanks for your interest in FastAPI! 🚀 + + Please follow these instructions, fill every question, and do every step. 🙏 + + I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time. + + I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues. + + All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others. + + That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅). + + By asking questions in a structured way (following this) it will be much easier to help you. + + And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎 + + As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓 + - type: checkboxes + id: checks + attributes: + label: First Check + description: Please confirm and check all the following options. + options: + - label: I added a very descriptive title to this issue. + required: true + - label: I used the GitHub search to find a similar issue and didn't find it. + required: true + - label: I searched the FastAPI documentation, with the integrated search. + required: true + - label: I already searched in Google "How to X in FastAPI" and didn't find any information. + required: true + - label: I already read and followed all the tutorial in the docs and didn't find an answer. + required: true + - label: I already checked if it is not related to FastAPI but to [Pydantic](https://github.com/samuelcolvin/pydantic). + required: true + - label: I already checked if it is not related to FastAPI but to [Swagger UI](https://github.com/swagger-api/swagger-ui). + required: true + - label: I already checked if it is not related to FastAPI but to [ReDoc](https://github.com/Redocly/redoc). + required: true + - type: checkboxes + id: help + attributes: + label: Commit to Help + description: | + After submitting this, I commit to one of: + + * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. + * I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. + * Implement a Pull Request for a confirmed bug. + + options: + - label: I commit to help with one of those options 👆 + required: true + - type: textarea + id: example + attributes: + label: Example Code + description: | + Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case. + + If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you. + + placeholder: | + from fastapi import FastAPI + + app = FastAPI() + + + @app.get("/") + def read_root(): + return {"Hello": "World"} + render: python + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: | + What is your feature request? + + Write a short description telling me what you are trying to solve and what you are currently doing. + placeholder: | + * Open the browser and call the endpoint `/`. + * It returns a JSON with `{"Hello": "World"}`. + * I would like it to have an extra parameter to teleport me to the moon and back. + validations: + required: true + - type: textarea + id: wanted-solution + attributes: + label: Wanted Solution + description: | + Tell me what's the solution you would like. + placeholder: | + I would like it to have a `teleport_to_moon` parameter that defaults to `False`, and can be set to `True` to teleport me. + validations: + required: true + - type: textarea + id: wanted-code + attributes: + label: Wanted Code + description: Show me an example of how you would want the code to look like. + placeholder: | + from fastapi import FastAPI + + app = FastAPI() + + + @app.get("/", teleport_to_moon=True) + def read_root(): + return {"Hello": "World"} + render: python + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives + description: | + Tell me about alternatives you've considered. + placeholder: | + To wait for Space X moon travel plans to drop down long after they release them. But I would rather teleport. + - type: dropdown + id: os + attributes: + label: Operating System + description: What operating system are you on? + multiple: true + options: + - Linux + - Windows + - macOS + - Other + validations: + required: true + - type: textarea + id: os-details + attributes: + label: Operating System Details + description: You can add more details about your operating system here, in particular if you chose "Other". + - type: input + id: fastapi-version + attributes: + label: FastAPI Version + description: | + What FastAPI version are you using? + + You can find the FastAPI version with: + + ```bash + python -c "import fastapi; print(fastapi.__version__)" + ``` + validations: + required: true + - type: input + id: python-version + attributes: + label: Python Version + description: | + What Python version are you using? + + You can find the Python version with: + + ```bash + python --version + ``` + validations: + required: true + - type: textarea + id: context + attributes: + label: Additional Context + description: Add any additional context information or screenshots you think are useful. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 75c02cc1f..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: "" -labels: enhancement -assignees: '' - ---- - -### First check - -* [ ] I added a very descriptive title to this issue. -* [ ] I used the GitHub search to find a similar issue and didn't find it. -* [ ] I searched the FastAPI documentation, with the integrated search. -* [ ] I already searched in Google "How to X in FastAPI" and didn't find any information. -* [ ] I already read and followed all the tutorial in the docs and didn't find an answer. -* [ ] I already checked if it is not related to FastAPI but to [Pydantic](https://github.com/samuelcolvin/pydantic). -* [ ] I already checked if it is not related to FastAPI but to [Swagger UI](https://github.com/swagger-api/swagger-ui). -* [ ] I already checked if it is not related to FastAPI but to [ReDoc](https://github.com/Redocly/redoc). -* [ ] After submitting this, I commit to: - * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. - * Or, I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. - * Implement a Pull Request for a confirmed bug. - - - -### Example - -Here's a self-contained [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with my use case: - - - -```Python -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} -``` - -### Description - - - -* Open the browser and call the endpoint `/`. -* It returns a JSON with `{"Hello": "World"}`. -* I would like it to have an extra parameter to teleport me to the moon and back. - -### The solution you would like - - - -I would like it to have a `teleport_to_moon` parameter that defaults to `False`, and can be set to `True` to teleport me: - -```Python -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/", teleport_to_moon=True) -def read_root(): - return {"Hello": "World"} -``` - -### Describe alternatives you've considered - - - -To wait for Space X moon travel plans to drop down long after they release them. But I would rather teleport. - -### Environment - -* OS: [e.g. Linux / Windows / macOS]: -* FastAPI Version [e.g. 0.3.0]: - -To know the FastAPI version use: - -```bash -python -c "import fastapi; print(fastapi.__version__)" -``` - -* Python version: - -To know the Python version use: - -```bash -python --version -``` - -### Additional context - - diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index c49538916..000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -name: Question or Problem -about: Ask a question or ask about a problem -title: "" -labels: question -assignees: "" - ---- - -### First check - -* [ ] I added a very descriptive title to this issue. -* [ ] I used the GitHub search to find a similar issue and didn't find it. -* [ ] I searched the FastAPI documentation, with the integrated search. -* [ ] I already searched in Google "How to X in FastAPI" and didn't find any information. -* [ ] I already read and followed all the tutorial in the docs and didn't find an answer. -* [ ] I already checked if it is not related to FastAPI but to [Pydantic](https://github.com/samuelcolvin/pydantic). -* [ ] I already checked if it is not related to FastAPI but to [Swagger UI](https://github.com/swagger-api/swagger-ui). -* [ ] I already checked if it is not related to FastAPI but to [ReDoc](https://github.com/Redocly/redoc). -* [ ] After submitting this, I commit to one of: - * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. - * I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. - * Implement a Pull Request for a confirmed bug. - - - -### Example - -Here's a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with my use case: - - - -```Python -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} -``` - -### Description - - - -* Open the browser and call the endpoint `/`. -* It returns a JSON with `{"Hello": "World"}`. -* But I expected it to return `{"Hello": "Sara"}`. - -### Environment - -* OS: [e.g. Linux / Windows / macOS]: -* FastAPI Version [e.g. 0.3.0]: - -To know the FastAPI version use: - -```bash -python -c "import fastapi; print(fastapi.__version__)" -``` - -* Python version: - -To know the Python version use: - -```bash -python --version -``` - -### Additional context - - diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml new file mode 100644 index 000000000..5c76fd17e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -0,0 +1,146 @@ +name: Question or Problem +description: Ask a question or ask about a problem +labels: [question] +body: + - type: markdown + attributes: + value: | + Thanks for your interest in FastAPI! 🚀 + + Please follow these instructions, fill every question, and do every step. 🙏 + + I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time. + + I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues. + + All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others. + + That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅). + + By asking questions in a structured way (following this) it will be much easier to help you. + + And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎 + + As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓 + - type: checkboxes + id: checks + attributes: + label: First Check + description: Please confirm and check all the following options. + options: + - label: I added a very descriptive title to this issue. + required: true + - label: I used the GitHub search to find a similar issue and didn't find it. + required: true + - label: I searched the FastAPI documentation, with the integrated search. + required: true + - label: I already searched in Google "How to X in FastAPI" and didn't find any information. + required: true + - label: I already read and followed all the tutorial in the docs and didn't find an answer. + required: true + - label: I already checked if it is not related to FastAPI but to [Pydantic](https://github.com/samuelcolvin/pydantic). + required: true + - label: I already checked if it is not related to FastAPI but to [Swagger UI](https://github.com/swagger-api/swagger-ui). + required: true + - label: I already checked if it is not related to FastAPI but to [ReDoc](https://github.com/Redocly/redoc). + required: true + - type: checkboxes + id: help + attributes: + label: Commit to Help + description: | + After submitting this, I commit to one of: + + * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. + * I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. + * Implement a Pull Request for a confirmed bug. + + options: + - label: I commit to help with one of those options 👆 + required: true + - type: textarea + id: example + attributes: + label: Example Code + description: | + Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case. + + If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you. + + placeholder: | + from fastapi import FastAPI + + app = FastAPI() + + + @app.get("/") + def read_root(): + return {"Hello": "World"} + render: python + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: | + What is the problem, question, or error? + + Write a short description telling me what you are doing, what you expect to happen, and what is currently happening. + placeholder: | + * Open the browser and call the endpoint `/`. + * It returns a JSON with `{"Hello": "World"}`. + * But I expected it to return `{"Hello": "Sara"}`. + validations: + required: true + - type: dropdown + id: os + attributes: + label: Operating System + description: What operating system are you on? + multiple: true + options: + - Linux + - Windows + - macOS + - Other + validations: + required: true + - type: textarea + id: os-details + attributes: + label: Operating System Details + description: You can add more details about your operating system here, in particular if you chose "Other". + - type: input + id: fastapi-version + attributes: + label: FastAPI Version + description: | + What FastAPI version are you using? + + You can find the FastAPI version with: + + ```bash + python -c "import fastapi; print(fastapi.__version__)" + ``` + validations: + required: true + - type: input + id: python-version + attributes: + label: Python Version + description: | + What Python version are you using? + + You can find the Python version with: + + ```bash + python --version + ``` + validations: + required: true + - type: textarea + id: context + attributes: + label: Additional Context + description: Add any additional context information or screenshots you think are useful. From 1a5273773e7b7bc0a42bb81bf8b2cb1c2d3aa72a Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 27 Jul 2021 10:23:49 +0000 Subject: [PATCH 128/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c8230ede2..06cc0c343 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add new GitHub templates with forms for new issues. PR [#3612](https://github.com/tiangolo/fastapi/pull/3612) by [@tiangolo](https://github.com/tiangolo). * 📝 Add official FastAPI Twitter to docs: [@fastapi](https://twitter.com/fastapi). PR [#3578](https://github.com/tiangolo/fastapi/pull/3578) by [@tiangolo](https://github.com/tiangolo). ## 0.67.0 From bb6c6ed5d1aa98044b8fcd3bbde5a08162ca007d Mon Sep 17 00:00:00 2001 From: Yuya Sato Date: Thu, 29 Jul 2021 00:35:25 +0900 Subject: [PATCH 129/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Japanese=20transla?= =?UTF-8?q?tion=20for=20`docs/tutorial/security/oauth2-jwt.md`=20(#3526)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: tokusumi <41147016+tokusumi@users.noreply.github.com> Co-authored-by: Sho Nakamura --- docs/ja/docs/tutorial/security/oauth2-jwt.md | 266 +++++++++++++++++++ docs/ja/mkdocs.yml | 1 + 2 files changed, 267 insertions(+) create mode 100644 docs/ja/docs/tutorial/security/oauth2-jwt.md diff --git a/docs/ja/docs/tutorial/security/oauth2-jwt.md b/docs/ja/docs/tutorial/security/oauth2-jwt.md new file mode 100644 index 000000000..348ffda01 --- /dev/null +++ b/docs/ja/docs/tutorial/security/oauth2-jwt.md @@ -0,0 +1,266 @@ +# パスワード(およびハッシュ化)によるOAuth2、JWTトークンによるBearer + +これでセキュリティの流れが全てわかったので、JWTトークンと安全なパスワードのハッシュ化を使用して、実際にアプリケーションを安全にしてみましょう。 + +このコードは、アプリケーションで実際に使用したり、パスワードハッシュをデータベースに保存するといった用途に利用できます。 + +本章では、前章の続きから始めて、コードをアップデートしていきます。 + +## JWT について + +JWTとは「JSON Web Tokens」の略称です。 + +JSONオブジェクトをスペースのない長く密集した文字列で表現したトークンの仕様です。例えば次のようになります: + +``` +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c +``` + +これらは暗号化されていないので、誰でもコンテンツから情報を復元できてしまいます。 + +しかし、トークンは署名されているため、あなたが発行したトークンを受け取った人は、あなたが実際に発行したということを検証できます。 + +例えば、1週間の有効期限を持つトークンを作成したとします。ユーザーが翌日そのトークンを持って戻ってきたとき、そのユーザーはまだシステムにログインしていることがわかります。 + +1週間後、トークンが期限切れとなるとどうなるでしょうか?ユーザーは認可されず、新しいトークンを得るために再びサインインしなければなりません。また、ユーザー(または第三者)がトークンを修正して有効期限を変更しようとした場合、署名が一致しないため、トークンの修正を検知できます。 + +JWT トークンを使って遊んでみたいという方は、https://jwt.io をチェックしてください。 + +## `python-jose` のインストール + +PythonでJWTトークンの生成と検証を行うために、`python-jose`をインストールする必要があります: + +
+ +```console +$ pip install python-jose[cryptography] + +---> 100% +``` + +
+ +また、Python-joseだけではなく、暗号を扱うためのパッケージを追加で必要とします。 + +ここでは、推奨されているものを使用します:pyca/cryptography。 + +!!! tip "豆知識" + このチュートリアルでは以前、PyJWTを使用していました。 + + しかし、Python-joseは、PyJWTのすべての機能に加えて、後に他のツールと統合して構築する際におそらく必要となる可能性のあるいくつかの追加機能を提供しています。そのため、代わりにPython-joseを使用するように更新されました。 + +## パスワードのハッシュ化 + +「ハッシュ化」とは、あるコンテンツ(ここではパスワード)を、規則性のないバイト列(単なる文字列)に変換することです。 + +特徴として、全く同じ内容(全く同じパスワード)を渡すと、全く同じ規則性のないバイト列に変換されます。 + +しかし、規則性のないバイト列から元のパスワードに戻すことはできません。 + +### パスワードのハッシュ化を使う理由 + +データベースが盗まれても、ユーザーの平文のパスワードは盗まれず、ハッシュ値だけが盗まれます。 + +したがって、泥棒はそのパスワードを別のシステムで使えません(多くのユーザーはどこでも同じパスワードを使用しているため、危険性があります)。 + +## `passlib` のインストール + +PassLib は、パスワードのハッシュを処理するための優れたPythonパッケージです。 + +このパッケージは、多くの安全なハッシュアルゴリズムとユーティリティをサポートします。 + +推奨されるアルゴリズムは「Bcrypt」です。 + +そのため、Bcryptを指定してPassLibをインストールします: + +
+ +```console +$ pip install passlib[bcrypt] + +---> 100% +``` + +
+ +!!! tip "豆知識" + `passlib`を使用すると、**Django**や**Flask**のセキュリティプラグインなどで作成されたパスワードを読み取れるように設定できます。 + + 例えば、Djangoアプリケーションからデータベース内の同じデータをFastAPIアプリケーションと共有できるだけではなく、同じデータベースを使用してDjangoアプリケーションを徐々に移行することもできます。 + + また、ユーザーはDjangoアプリまたは**FastAPI**アプリからも、同時にログインできるようになります。 + + +## パスワードのハッシュ化と検証 + +必要なツールを `passlib`からインポートします。 + +PassLib の「context」を作成します。これは、パスワードのハッシュ化と検証に使用されるものです。 + +!!! tip "豆知識" + PassLibのcontextには、検証だけが許された非推奨の古いハッシュアルゴリズムを含む、様々なハッシュアルゴリズムを使用した検証機能もあります。 + + 例えば、この機能を使用して、別のシステム(Djangoなど)によって生成されたパスワードを読み取って検証し、Bcryptなどの別のアルゴリズムを使用して新しいパスワードをハッシュするといったことができます。 + + そして、同時にそれらはすべてに互換性があります。 + +ユーザーから送られてきたパスワードをハッシュ化するユーティリティー関数を作成します。 + +また、受け取ったパスワードが保存されているハッシュと一致するかどうかを検証するユーティリティも作成します。 + +さらに、ユーザーを認証して返す関数も作成します。 + +```Python hl_lines="7 48 55-56 59-60 69-75" +{!../../../docs_src/security/tutorial004.py!} +``` + +!!! note "備考" + 新しい(偽の)データベース`fake_users_db`を確認すると、ハッシュ化されたパスワードが次のようになっていることがわかります:`"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"` + +## JWTトークンの取り扱い + +インストールした複数のモジュールをインポートします。 + +JWTトークンの署名に使用されるランダムな秘密鍵を生成します。 + +安全なランダム秘密鍵を生成するには、次のコマンドを使用します: + +
+ +```console +$ openssl rand -hex 32 + +09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7 +``` + +
+ +そして、出力された文字列を変数`SECRET_KEY`にコピーします。(例に記載している秘密鍵は実際に使用しないでください) + +JWTトークンの署名に使用するアルゴリズム`"HS256"`を指定した変数`ALGORITHM`を作成します。 + +トークンの有効期限を指定した変数`ACCESS_TOKEN_EXPIRE_MINUTES`を作成します。 + +レスポンスのトークンエンドポイントで使用するPydanticモデルを定義します。 + +新しいアクセストークンを生成するユーティリティ関数を作成します。 + +```Python hl_lines="6 12-14 28-30 78-86" +{!../../../docs_src/security/tutorial004.py!} +``` + +## 依存関係の更新 + +`get_current_user`を更新して、先ほどと同じトークンを受け取るようにしますが、今回はJWTトークンを使用します。 + +受け取ったトークンを復号して検証し、現在のユーザーを返します。 + +トークンが無効な場合は、すぐにHTTPエラーを返します。 + +```Python hl_lines="89-106" +{!../../../docs_src/security/tutorial004.py!} +``` + +## `/token` パスオペレーションの更新 + +トークンの有効期限を表す`timedelta`を作成します。 + +JWTアクセストークンを作成し、それを返します。 + +```Python hl_lines="115-128" +{!../../../docs_src/security/tutorial004.py!} +``` + +### JWTの"subject" `sub` についての技術的な詳細 + +JWTの仕様では、トークンのsubjectを表すキー`sub`があるとされています。 + +使用するかどうかは任意ですが、`sub`はユーザーの識別情報を入れるように規定されているので、ここで使用します。 + +JWTは、ユーザーを識別して、そのユーザーがAPI上で直接操作を実行できるようにする以外にも、他の用途で使用されることがあります。 + +例えば、「車」や「ブログ記事」を識別することができます。 + +そして、「ドライブ」(車の場合)や「編集」(ブログの場合)など、そのエンティティに関する権限も追加できます。 + +また、JWTトークンをユーザー(またはボット)に渡すことができます。ユーザーは、JWTトークンを使用するだけで、アカウントを持っていなくても、APIが生成したJWTトークンを使ってそれらの行動(車の運転、ブログ投稿の編集)を実行できるのです。 + +これらのアイデアを使用すると、JWTをより高度なシナリオに使用できます。 + +しかしながら、それらのエンティティのいくつかが同じIDを持つ可能性があります。例えば、`foo`(ユーザー`foo`、車 `foo`、ブログ投稿`foo`)などです。 + +IDの衝突を回避するために、ユーザーのJWTトークンを作成するとき、subキーの値にプレフィックスを付けることができます(例えば、`username:`)。したがって、この例では、`sub`の値は次のようになっている可能性があります:`username:johndoe` + +覚えておくべき重要なことは、`sub`キーはアプリケーション全体で一意の識別子を持ち、文字列である必要があるということです。 + +## 確認 + +サーバーを実行し、ドキュメントに移動します:http://127.0.0.1:8000/docs + +次のようなユーザーインターフェイスが表示されます: + + + +前回と同じ方法でアプリケーションの認可を行います。 + +次の認証情報を使用します: + +Username: `johndoe` +Password: `secret` + +!!! check "確認" + コードのどこにも平文のパスワード"`secret`"はなく、ハッシュ化されたものしかないことを確認してください。 + + + +エンドポイント`/users/me/`を呼び出すと、次のようなレスポンスが得られます: + +```JSON +{ + "username": "johndoe", + "email": "johndoe@example.com", + "full_name": "John Doe", + "disabled": false +} +``` + + + +開発者ツールを開くと、送信されるデータにはトークンだけが含まれており、パスワードはユーザーを認証してアクセストークンを取得する最初のリクエストでのみ送信され、その後は送信されないことがわかります。 + + + +!!! note "備考" + ヘッダーの`Authorization`には、`Bearer`で始まる値があります。 + +## `scopes` を使った高度なユースケース + +OAuth2には、「スコープ」という概念があります。 + +これらを利用して、JWTトークンに特定の権限セットを追加することができます。 + +そして、このトークンをユーザーに直接、または第三者に与えて、制限付きでAPIを操作できます。 + +これらの使用方法や**FastAPI**への統合方法については、**高度なユーザーガイド**で後ほど説明します。 + +## まとめ + +ここまでの説明で、OAuth2やJWTなどの規格を使った安全な**FastAPI**アプリケーションを設定することができます。 + +ほとんどのフレームワークにおいて、セキュリティを扱うことは非常に複雑な課題となります。 + +簡略化しすぎたパッケージの多くは、データモデルやデータベース、利用可能な機能について多くの妥協をしなければなりません。そして、あまりにも単純化されたパッケージの中には、実はセキュリティ上の欠陥があるものもあります。 + +--- + +**FastAPI**は、どのようなデータベース、データモデル、ツールに対しても妥協することはありません。 + +そのため、プロジェクトに合わせて自由に選択することができます。 + +また、**FastAPI**は外部パッケージを統合するために複雑な仕組みを必要としないため、`passlib`や`python-jose`のようなよく整備され広く使われている多くのパッケージを直接使用することができます。 + +しかし、柔軟性、堅牢性、セキュリティを損なうことなく、可能な限りプロセスを簡素化するためのツールを提供します。 + +また、OAuth2のような安全で標準的なプロトコルを比較的簡単な方法で使用できるだけではなく、実装することもできます。 + +OAuth2の「スコープ」を使って、同じ基準でより細かい権限システムを実現する方法については、**高度なユーザーガイド**で詳しく説明しています。スコープ付きのOAuth2は、Facebook、Google、GitHub、Microsoft、Twitterなど、多くの大手認証プロバイダが、サードパーティのアプリケーションと自社のAPIとのやり取りをユーザーに代わって認可するために使用している仕組みです。 diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index c1c284316..d92871029 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -68,6 +68,7 @@ nav: - tutorial/body-updates.md - セキュリティ: - tutorial/security/first-steps.md + - tutorial/security/oauth2-jwt.md - tutorial/middleware.md - tutorial/cors.md - tutorial/static-files.md From 29e7b31ee62a65101c49a9354954bf1f83046e99 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 28 Jul 2021 15:36:03 +0000 Subject: [PATCH 130/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 06cc0c343..b877e2a4d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Japanese translation for `docs/tutorial/security/oauth2-jwt.md`. PR [#3526](https://github.com/tiangolo/fastapi/pull/3526) by [@sattosan](https://github.com/sattosan). * 🔧 Add new GitHub templates with forms for new issues. PR [#3612](https://github.com/tiangolo/fastapi/pull/3612) by [@tiangolo](https://github.com/tiangolo). * 📝 Add official FastAPI Twitter to docs: [@fastapi](https://twitter.com/fastapi). PR [#3578](https://github.com/tiangolo/fastapi/pull/3578) by [@tiangolo](https://github.com/tiangolo). From fa2c750443e4c12ce3c8940f3043c36d218550ab Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 29 Jul 2021 11:26:07 +0200 Subject: [PATCH 131/814] =?UTF-8?q?=E2=9C=85=20Add=20=20the=20`docs=5Fsrc`?= =?UTF-8?q?=20directory=20to=20test=20coverage=20and=20update=20tests=20(#?= =?UTF-8?q?1904)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/settings.md | 6 +++--- docs_src/settings/app01/main.py | 8 ++++---- docs_src/settings/app02/main.py | 6 +++--- docs_src/settings/app02/test_main.py | 10 +++++----- scripts/test.sh | 2 +- .../test_bigger_applications/test_main.py | 12 ++++++++++++ .../test_conditional_openapi/test_tutorial001.py | 7 +++++++ tests/test_tutorial/test_settings/test_app02.py | 10 +++++++++- tests/test_tutorial/test_testing/test_main_b.py | 10 ++++++++++ .../test_websockets/test_tutorial003.py | 7 ++++++- 10 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 tests/test_tutorial/test_testing/test_main_b.py diff --git a/docs/en/docs/advanced/settings.md b/docs/en/docs/advanced/settings.md index 706a71173..d5151b585 100644 --- a/docs/en/docs/advanced/settings.md +++ b/docs/en/docs/advanced/settings.md @@ -235,7 +235,7 @@ And then we can require it from the *path operation function* as a dependency an Then it would be very easy to provide a different settings object during testing by creating a dependency override for `get_settings`: -```Python hl_lines="8-9 12 21" +```Python hl_lines="9-10 13 21" {!../../../docs_src/settings/app02/test_main.py!} ``` @@ -288,7 +288,7 @@ Reading a file from disk is normally a costly (slow) operation, so you probably But every time we do: ```Python -config.Settings() +Settings() ``` a new `Settings` object would be created, and at creation it would read the `.env` file again. @@ -297,7 +297,7 @@ If the dependency function was just like: ```Python def get_settings(): - return config.Settings() + return Settings() ``` we would create that object for each request, and we would be reading the `.env` file for each request. ⚠️ diff --git a/docs_src/settings/app01/main.py b/docs_src/settings/app01/main.py index 53503797e..4a3a86ce2 100644 --- a/docs_src/settings/app01/main.py +++ b/docs_src/settings/app01/main.py @@ -1,6 +1,6 @@ from fastapi import FastAPI -from . import config +from .config import settings app = FastAPI() @@ -8,7 +8,7 @@ app = FastAPI() @app.get("/info") async def info(): return { - "app_name": config.settings.app_name, - "admin_email": config.settings.admin_email, - "items_per_user": config.settings.items_per_user, + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, } diff --git a/docs_src/settings/app02/main.py b/docs_src/settings/app02/main.py index 69bc8c6e0..163aa2614 100644 --- a/docs_src/settings/app02/main.py +++ b/docs_src/settings/app02/main.py @@ -2,18 +2,18 @@ from functools import lru_cache from fastapi import Depends, FastAPI -from . import config +from .config import Settings app = FastAPI() @lru_cache() def get_settings(): - return config.Settings() + return Settings() @app.get("/info") -async def info(settings: config.Settings = Depends(get_settings)): +async def info(settings: Settings = Depends(get_settings)): return { "app_name": settings.app_name, "admin_email": settings.admin_email, diff --git a/docs_src/settings/app02/test_main.py b/docs_src/settings/app02/test_main.py index 44d9f8379..7a04d7e8e 100644 --- a/docs_src/settings/app02/test_main.py +++ b/docs_src/settings/app02/test_main.py @@ -1,19 +1,19 @@ from fastapi.testclient import TestClient -from . import config, main +from .config import Settings +from .main import app, get_settings -client = TestClient(main.app) +client = TestClient(app) def get_settings_override(): - return config.Settings(admin_email="testing_admin@example.com") + return Settings(admin_email="testing_admin@example.com") -main.app.dependency_overrides[main.get_settings] = get_settings_override +app.dependency_overrides[get_settings] = get_settings_override def test_app(): - response = client.get("/info") data = response.json() assert data == { diff --git a/scripts/test.sh b/scripts/test.sh index b593133d8..74ed7a1f1 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -7,4 +7,4 @@ bash ./scripts/lint.sh # Check README.md is up to date python ./scripts/docs.py verify-readme export PYTHONPATH=./docs_src -pytest --cov=fastapi --cov=tests --cov=docs/src --cov-report=term-missing --cov-report=xml tests ${@} +pytest --cov=fastapi --cov=tests --cov=docs_src --cov-report=term-missing:skip-covered --cov-report=xml tests ${@} diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py index 3670e25cf..7eb675179 100644 --- a/tests/test_tutorial/test_bigger_applications/test_main.py +++ b/tests/test_tutorial/test_bigger_applications/test_main.py @@ -359,6 +359,12 @@ no_jessica = { ("/users/foo", 422, no_jessica, {}), ("/users/me?token=jessica", 200, {"username": "fakecurrentuser"}, {}), ("/users/me", 422, no_jessica, {}), + ( + "/users?token=monica", + 400, + {"detail": "No Jessica token provided"}, + {}, + ), ( "/items?token=jessica", 200, @@ -372,6 +378,12 @@ no_jessica = { {"name": "Plumbus", "item_id": "plumbus"}, {"X-Token": "fake-super-secret-token"}, ), + ( + "/items/bar?token=jessica", + 404, + {"detail": "Item not found"}, + {"X-Token": "fake-super-secret-token"}, + ), ("/items/plumbus", 422, no_jessica, {"X-Token": "fake-super-secret-token"}), ( "/items?token=jessica", diff --git a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py index 828cd62c1..93c8775ce 100644 --- a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py +++ b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py @@ -44,3 +44,10 @@ def test_disable_openapi(monkeypatch): assert response.status_code == 404, response.text response = client.get("/redoc") assert response.status_code == 404, response.text + + +def test_root(): + client = TestClient(tutorial001.app) + response = client.get("/") + assert response.status_code == 200 + assert response.json() == {"message": "Hello World"} diff --git a/tests/test_tutorial/test_settings/test_app02.py b/tests/test_tutorial/test_settings/test_app02.py index 2fb371202..fd32b8766 100644 --- a/tests/test_tutorial/test_settings/test_app02.py +++ b/tests/test_tutorial/test_settings/test_app02.py @@ -1,9 +1,17 @@ from fastapi.testclient import TestClient +from pytest import MonkeyPatch from docs_src.settings.app02 import main, test_main client = TestClient(main.app) -def test_setting_override(): +def test_settings(monkeypatch: MonkeyPatch): + monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com") + settings = main.get_settings() + assert settings.app_name == "Awesome API" + assert settings.items_per_user == 50 + + +def test_override_settings(): test_main.test_app() diff --git a/tests/test_tutorial/test_testing/test_main_b.py b/tests/test_tutorial/test_testing/test_main_b.py new file mode 100644 index 000000000..820e4856d --- /dev/null +++ b/tests/test_tutorial/test_testing/test_main_b.py @@ -0,0 +1,10 @@ +from docs_src.app_testing import test_main_b + + +def test_app(): + test_main_b.test_create_existing_item() + test_main_b.test_create_item() + test_main_b.test_create_item_bad_token() + test_main_b.test_read_inexistent_item() + test_main_b.test_read_item() + test_main_b.test_read_item_bad_token() diff --git a/tests/test_tutorial/test_websockets/test_tutorial003.py b/tests/test_tutorial/test_websockets/test_tutorial003.py index adc2cdae7..dbcad3b02 100644 --- a/tests/test_tutorial/test_websockets/test_tutorial003.py +++ b/tests/test_tutorial/test_websockets/test_tutorial003.py @@ -1,10 +1,15 @@ from fastapi.testclient import TestClient -from docs_src.websockets.tutorial003 import app +from docs_src.websockets.tutorial003 import app, html client = TestClient(app) +def test_get(): + response = client.get("/") + assert response.text == html + + def test_websocket_handle_disconnection(): with client.websocket_connect("/ws/1234") as connection, client.websocket_connect( "/ws/5678" From 9121fccf55a65108b022d7e245940b5b7731e031 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 09:26:40 +0000 Subject: [PATCH 132/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b877e2a4d..e418d0879 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✅ Add the `docs_src` directory to test coverage and update tests. PR [#1904](https://github.com/tiangolo/fastapi/pull/1904) by [@Kludex](https://github.com/Kludex). * 🌐 Add Japanese translation for `docs/tutorial/security/oauth2-jwt.md`. PR [#3526](https://github.com/tiangolo/fastapi/pull/3526) by [@sattosan](https://github.com/sattosan). * 🔧 Add new GitHub templates with forms for new issues. PR [#3612](https://github.com/tiangolo/fastapi/pull/3612) by [@tiangolo](https://github.com/tiangolo). * 📝 Add official FastAPI Twitter to docs: [@fastapi](https://twitter.com/fastapi). PR [#3578](https://github.com/tiangolo/fastapi/pull/3578) by [@tiangolo](https://github.com/tiangolo). From 3b2e891917dd2739659643cedb5258e65d54934d Mon Sep 17 00:00:00 2001 From: Hylke Postma <20515386+hylkepostma@users.noreply.github.com> Date: Thu, 29 Jul 2021 12:30:48 +0200 Subject: [PATCH 133/814] =?UTF-8?q?=E2=9C=A8=20Add=20`description`=20param?= =?UTF-8?q?eter=20to=20all=20the=20security=20scheme=20classes,=20e.g.=20`?= =?UTF-8?q?APIKeyQuery(name=3D"key",=20description=3D"A=20very=20cool=20AP?= =?UTF-8?q?I=20key")`=20(#1757)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hylke Postma Co-authored-by: Sebastián Ramírez --- fastapi/security/api_key.py | 33 ++- fastapi/security/http.py | 25 +- fastapi/security/oauth2.py | 19 +- fastapi/security/open_id_connect_url.py | 5 +- ...est_security_api_key_cookie_description.py | 73 +++++ ...est_security_api_key_header_description.py | 73 +++++ ...test_security_api_key_query_description.py | 73 +++++ tests/test_security_http_base_description.py | 62 +++++ ...t_security_http_basic_realm_description.py | 85 ++++++ .../test_security_http_bearer_description.py | 68 +++++ .../test_security_http_digest_description.py | 70 +++++ ...2_authorization_code_bearer_description.py | 81 ++++++ ...st_security_oauth2_optional_description.py | 255 ++++++++++++++++++ ...h2_password_bearer_optional_description.py | 76 ++++++ ...est_security_openid_connect_description.py | 80 ++++++ 15 files changed, 1062 insertions(+), 16 deletions(-) create mode 100644 tests/test_security_api_key_cookie_description.py create mode 100644 tests/test_security_api_key_header_description.py create mode 100644 tests/test_security_api_key_query_description.py create mode 100644 tests/test_security_http_base_description.py create mode 100644 tests/test_security_http_basic_realm_description.py create mode 100644 tests/test_security_http_bearer_description.py create mode 100644 tests/test_security_http_digest_description.py create mode 100644 tests/test_security_oauth2_authorization_code_bearer_description.py create mode 100644 tests/test_security_oauth2_optional_description.py create mode 100644 tests/test_security_oauth2_password_bearer_optional_description.py create mode 100644 tests/test_security_openid_connect_description.py diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py index e4dacb389..36ab60e30 100644 --- a/fastapi/security/api_key.py +++ b/fastapi/security/api_key.py @@ -13,9 +13,16 @@ class APIKeyBase(SecurityBase): class APIKeyQuery(APIKeyBase): def __init__( - self, *, name: str, scheme_name: Optional[str] = None, auto_error: bool = True + self, + *, + name: str, + scheme_name: Optional[str] = None, + description: Optional[str] = None, + auto_error: bool = True ): - self.model: APIKey = APIKey(**{"in": APIKeyIn.query}, name=name) + self.model: APIKey = APIKey( + **{"in": APIKeyIn.query}, name=name, description=description + ) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error @@ -33,9 +40,16 @@ class APIKeyQuery(APIKeyBase): class APIKeyHeader(APIKeyBase): def __init__( - self, *, name: str, scheme_name: Optional[str] = None, auto_error: bool = True + self, + *, + name: str, + scheme_name: Optional[str] = None, + description: Optional[str] = None, + auto_error: bool = True ): - self.model: APIKey = APIKey(**{"in": APIKeyIn.header}, name=name) + self.model: APIKey = APIKey( + **{"in": APIKeyIn.header}, name=name, description=description + ) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error @@ -53,9 +67,16 @@ class APIKeyHeader(APIKeyBase): class APIKeyCookie(APIKeyBase): def __init__( - self, *, name: str, scheme_name: Optional[str] = None, auto_error: bool = True + self, + *, + name: str, + scheme_name: Optional[str] = None, + description: Optional[str] = None, + auto_error: bool = True ): - self.model: APIKey = APIKey(**{"in": APIKeyIn.cookie}, name=name) + self.model: APIKey = APIKey( + **{"in": APIKeyIn.cookie}, name=name, description=description + ) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error diff --git a/fastapi/security/http.py b/fastapi/security/http.py index 3258bd058..1b473c69e 100644 --- a/fastapi/security/http.py +++ b/fastapi/security/http.py @@ -24,9 +24,14 @@ class HTTPAuthorizationCredentials(BaseModel): class HTTPBase(SecurityBase): def __init__( - self, *, scheme: str, scheme_name: Optional[str] = None, auto_error: bool = True + self, + *, + scheme: str, + scheme_name: Optional[str] = None, + description: Optional[str] = None, + auto_error: bool = True, ): - self.model = HTTPBaseModel(scheme=scheme) + self.model = HTTPBaseModel(scheme=scheme, description=description) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error @@ -51,9 +56,10 @@ class HTTPBasic(HTTPBase): *, scheme_name: Optional[str] = None, realm: Optional[str] = None, + description: Optional[str] = None, auto_error: bool = True, ): - self.model = HTTPBaseModel(scheme="basic") + self.model = HTTPBaseModel(scheme="basic", description=description) self.scheme_name = scheme_name or self.__class__.__name__ self.realm = realm self.auto_error = auto_error @@ -97,9 +103,10 @@ class HTTPBearer(HTTPBase): *, bearerFormat: Optional[str] = None, scheme_name: Optional[str] = None, + description: Optional[str] = None, auto_error: bool = True, ): - self.model = HTTPBearerModel(bearerFormat=bearerFormat) + self.model = HTTPBearerModel(bearerFormat=bearerFormat, description=description) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error @@ -127,8 +134,14 @@ class HTTPBearer(HTTPBase): class HTTPDigest(HTTPBase): - def __init__(self, *, scheme_name: Optional[str] = None, auto_error: bool = True): - self.model = HTTPBaseModel(scheme="digest") + def __init__( + self, + *, + scheme_name: Optional[str] = None, + description: Optional[str] = None, + auto_error: bool = True, + ): + self.model = HTTPBaseModel(scheme="digest", description=description) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py index 46571ad53..bdc6e2ea9 100644 --- a/fastapi/security/oauth2.py +++ b/fastapi/security/oauth2.py @@ -118,9 +118,10 @@ class OAuth2(SecurityBase): *, flows: Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]] = OAuthFlowsModel(), scheme_name: Optional[str] = None, + description: Optional[str] = None, auto_error: Optional[bool] = True ): - self.model = OAuth2Model(flows=flows) + self.model = OAuth2Model(flows=flows, description=description) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error @@ -142,12 +143,18 @@ class OAuth2PasswordBearer(OAuth2): tokenUrl: str, scheme_name: Optional[str] = None, scopes: Optional[Dict[str, str]] = None, + description: Optional[str] = None, auto_error: bool = True, ): if not scopes: scopes = {} flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes}) - super().__init__(flows=flows, scheme_name=scheme_name, auto_error=auto_error) + super().__init__( + flows=flows, + scheme_name=scheme_name, + description=description, + auto_error=auto_error, + ) async def __call__(self, request: Request) -> Optional[str]: authorization: str = request.headers.get("Authorization") @@ -172,6 +179,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2): refreshUrl: Optional[str] = None, scheme_name: Optional[str] = None, scopes: Optional[Dict[str, str]] = None, + description: Optional[str] = None, auto_error: bool = True, ): if not scopes: @@ -184,7 +192,12 @@ class OAuth2AuthorizationCodeBearer(OAuth2): "scopes": scopes, } ) - super().__init__(flows=flows, scheme_name=scheme_name, auto_error=auto_error) + super().__init__( + flows=flows, + scheme_name=scheme_name, + description=description, + auto_error=auto_error, + ) async def __call__(self, request: Request) -> Optional[str]: authorization: str = request.headers.get("Authorization") diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py index a98c13f8a..dfe9f7b25 100644 --- a/fastapi/security/open_id_connect_url.py +++ b/fastapi/security/open_id_connect_url.py @@ -13,9 +13,12 @@ class OpenIdConnect(SecurityBase): *, openIdConnectUrl: str, scheme_name: Optional[str] = None, + description: Optional[str] = None, auto_error: bool = True ): - self.model = OpenIdConnectModel(openIdConnectUrl=openIdConnectUrl) + self.model = OpenIdConnectModel( + openIdConnectUrl=openIdConnectUrl, description=description + ) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error diff --git a/tests/test_security_api_key_cookie_description.py b/tests/test_security_api_key_cookie_description.py new file mode 100644 index 000000000..2cd3565b4 --- /dev/null +++ b/tests/test_security_api_key_cookie_description.py @@ -0,0 +1,73 @@ +from fastapi import Depends, FastAPI, Security +from fastapi.security import APIKeyCookie +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + +api_key = APIKeyCookie(name="key", description="An API Cookie Key") + + +class User(BaseModel): + username: str + + +def get_current_user(oauth_header: str = Security(api_key)): + user = User(username=oauth_header) + return user + + +@app.get("/users/me") +def read_current_user(current_user: User = Depends(get_current_user)): + return current_user + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/users/me": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Current User", + "operationId": "read_current_user_users_me_get", + "security": [{"APIKeyCookie": []}], + } + } + }, + "components": { + "securitySchemes": { + "APIKeyCookie": { + "type": "apiKey", + "name": "key", + "in": "cookie", + "description": "An API Cookie Key", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_security_api_key(): + response = client.get("/users/me", cookies={"key": "secret"}) + assert response.status_code == 200, response.text + assert response.json() == {"username": "secret"} + + +def test_security_api_key_no_key(): + response = client.get("/users/me") + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Not authenticated"} diff --git a/tests/test_security_api_key_header_description.py b/tests/test_security_api_key_header_description.py new file mode 100644 index 000000000..cc9802708 --- /dev/null +++ b/tests/test_security_api_key_header_description.py @@ -0,0 +1,73 @@ +from fastapi import Depends, FastAPI, Security +from fastapi.security import APIKeyHeader +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + +api_key = APIKeyHeader(name="key", description="An API Key Header") + + +class User(BaseModel): + username: str + + +def get_current_user(oauth_header: str = Security(api_key)): + user = User(username=oauth_header) + return user + + +@app.get("/users/me") +def read_current_user(current_user: User = Depends(get_current_user)): + return current_user + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/users/me": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Current User", + "operationId": "read_current_user_users_me_get", + "security": [{"APIKeyHeader": []}], + } + } + }, + "components": { + "securitySchemes": { + "APIKeyHeader": { + "type": "apiKey", + "name": "key", + "in": "header", + "description": "An API Key Header", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_security_api_key(): + response = client.get("/users/me", headers={"key": "secret"}) + assert response.status_code == 200, response.text + assert response.json() == {"username": "secret"} + + +def test_security_api_key_no_key(): + response = client.get("/users/me") + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Not authenticated"} diff --git a/tests/test_security_api_key_query_description.py b/tests/test_security_api_key_query_description.py new file mode 100644 index 000000000..9b608233a --- /dev/null +++ b/tests/test_security_api_key_query_description.py @@ -0,0 +1,73 @@ +from fastapi import Depends, FastAPI, Security +from fastapi.security import APIKeyQuery +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + +api_key = APIKeyQuery(name="key", description="API Key Query") + + +class User(BaseModel): + username: str + + +def get_current_user(oauth_header: str = Security(api_key)): + user = User(username=oauth_header) + return user + + +@app.get("/users/me") +def read_current_user(current_user: User = Depends(get_current_user)): + return current_user + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/users/me": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Current User", + "operationId": "read_current_user_users_me_get", + "security": [{"APIKeyQuery": []}], + } + } + }, + "components": { + "securitySchemes": { + "APIKeyQuery": { + "type": "apiKey", + "name": "key", + "in": "query", + "description": "API Key Query", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_security_api_key(): + response = client.get("/users/me?key=secret") + assert response.status_code == 200, response.text + assert response.json() == {"username": "secret"} + + +def test_security_api_key_no_key(): + response = client.get("/users/me") + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Not authenticated"} diff --git a/tests/test_security_http_base_description.py b/tests/test_security_http_base_description.py new file mode 100644 index 000000000..5855e8df4 --- /dev/null +++ b/tests/test_security_http_base_description.py @@ -0,0 +1,62 @@ +from fastapi import FastAPI, Security +from fastapi.security.http import HTTPAuthorizationCredentials, HTTPBase +from fastapi.testclient import TestClient + +app = FastAPI() + +security = HTTPBase(scheme="Other", description="Other Security Scheme") + + +@app.get("/users/me") +def read_current_user(credentials: HTTPAuthorizationCredentials = Security(security)): + return {"scheme": credentials.scheme, "credentials": credentials.credentials} + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/users/me": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Current User", + "operationId": "read_current_user_users_me_get", + "security": [{"HTTPBase": []}], + } + } + }, + "components": { + "securitySchemes": { + "HTTPBase": { + "type": "http", + "scheme": "Other", + "description": "Other Security Scheme", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_security_http_base(): + response = client.get("/users/me", headers={"Authorization": "Other foobar"}) + assert response.status_code == 200, response.text + assert response.json() == {"scheme": "Other", "credentials": "foobar"} + + +def test_security_http_base_no_credentials(): + response = client.get("/users/me") + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Not authenticated"} diff --git a/tests/test_security_http_basic_realm_description.py b/tests/test_security_http_basic_realm_description.py new file mode 100644 index 000000000..6ff9d9d07 --- /dev/null +++ b/tests/test_security_http_basic_realm_description.py @@ -0,0 +1,85 @@ +from base64 import b64encode + +from fastapi import FastAPI, Security +from fastapi.security import HTTPBasic, HTTPBasicCredentials +from fastapi.testclient import TestClient +from requests.auth import HTTPBasicAuth + +app = FastAPI() + +security = HTTPBasic(realm="simple", description="HTTPBasic scheme") + + +@app.get("/users/me") +def read_current_user(credentials: HTTPBasicCredentials = Security(security)): + return {"username": credentials.username, "password": credentials.password} + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/users/me": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Current User", + "operationId": "read_current_user_users_me_get", + "security": [{"HTTPBasic": []}], + } + } + }, + "components": { + "securitySchemes": { + "HTTPBasic": { + "type": "http", + "scheme": "basic", + "description": "HTTPBasic scheme", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_security_http_basic(): + auth = HTTPBasicAuth(username="john", password="secret") + response = client.get("/users/me", auth=auth) + assert response.status_code == 200, response.text + assert response.json() == {"username": "john", "password": "secret"} + + +def test_security_http_basic_no_credentials(): + response = client.get("/users/me") + assert response.json() == {"detail": "Not authenticated"} + assert response.status_code == 401, response.text + assert response.headers["WWW-Authenticate"] == 'Basic realm="simple"' + + +def test_security_http_basic_invalid_credentials(): + response = client.get( + "/users/me", headers={"Authorization": "Basic notabase64token"} + ) + assert response.status_code == 401, response.text + assert response.headers["WWW-Authenticate"] == 'Basic realm="simple"' + assert response.json() == {"detail": "Invalid authentication credentials"} + + +def test_security_http_basic_non_basic_credentials(): + payload = b64encode(b"johnsecret").decode("ascii") + auth_header = f"Basic {payload}" + response = client.get("/users/me", headers={"Authorization": auth_header}) + assert response.status_code == 401, response.text + assert response.headers["WWW-Authenticate"] == 'Basic realm="simple"' + assert response.json() == {"detail": "Invalid authentication credentials"} diff --git a/tests/test_security_http_bearer_description.py b/tests/test_security_http_bearer_description.py new file mode 100644 index 000000000..132e720fc --- /dev/null +++ b/tests/test_security_http_bearer_description.py @@ -0,0 +1,68 @@ +from fastapi import FastAPI, Security +from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer +from fastapi.testclient import TestClient + +app = FastAPI() + +security = HTTPBearer(description="HTTP Bearer token scheme") + + +@app.get("/users/me") +def read_current_user(credentials: HTTPAuthorizationCredentials = Security(security)): + return {"scheme": credentials.scheme, "credentials": credentials.credentials} + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/users/me": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Current User", + "operationId": "read_current_user_users_me_get", + "security": [{"HTTPBearer": []}], + } + } + }, + "components": { + "securitySchemes": { + "HTTPBearer": { + "type": "http", + "scheme": "bearer", + "description": "HTTP Bearer token scheme", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_security_http_bearer(): + response = client.get("/users/me", headers={"Authorization": "Bearer foobar"}) + assert response.status_code == 200, response.text + assert response.json() == {"scheme": "Bearer", "credentials": "foobar"} + + +def test_security_http_bearer_no_credentials(): + response = client.get("/users/me") + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Not authenticated"} + + +def test_security_http_bearer_incorrect_scheme_credentials(): + response = client.get("/users/me", headers={"Authorization": "Basic notreally"}) + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Invalid authentication credentials"} diff --git a/tests/test_security_http_digest_description.py b/tests/test_security_http_digest_description.py new file mode 100644 index 000000000..d00aa1b6e --- /dev/null +++ b/tests/test_security_http_digest_description.py @@ -0,0 +1,70 @@ +from fastapi import FastAPI, Security +from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest +from fastapi.testclient import TestClient + +app = FastAPI() + +security = HTTPDigest(description="HTTPDigest scheme") + + +@app.get("/users/me") +def read_current_user(credentials: HTTPAuthorizationCredentials = Security(security)): + return {"scheme": credentials.scheme, "credentials": credentials.credentials} + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/users/me": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Current User", + "operationId": "read_current_user_users_me_get", + "security": [{"HTTPDigest": []}], + } + } + }, + "components": { + "securitySchemes": { + "HTTPDigest": { + "type": "http", + "scheme": "digest", + "description": "HTTPDigest scheme", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_security_http_digest(): + response = client.get("/users/me", headers={"Authorization": "Digest foobar"}) + assert response.status_code == 200, response.text + assert response.json() == {"scheme": "Digest", "credentials": "foobar"} + + +def test_security_http_digest_no_credentials(): + response = client.get("/users/me") + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Not authenticated"} + + +def test_security_http_digest_incorrect_scheme_credentials(): + response = client.get( + "/users/me", headers={"Authorization": "Other invalidauthorization"} + ) + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Invalid authentication credentials"} diff --git a/tests/test_security_oauth2_authorization_code_bearer_description.py b/tests/test_security_oauth2_authorization_code_bearer_description.py new file mode 100644 index 000000000..bdaa543fc --- /dev/null +++ b/tests/test_security_oauth2_authorization_code_bearer_description.py @@ -0,0 +1,81 @@ +from typing import Optional + +from fastapi import FastAPI, Security +from fastapi.security import OAuth2AuthorizationCodeBearer +from fastapi.testclient import TestClient + +app = FastAPI() + +oauth2_scheme = OAuth2AuthorizationCodeBearer( + authorizationUrl="authorize", + tokenUrl="token", + description="OAuth2 Code Bearer", + auto_error=True, +) + + +@app.get("/items/") +async def read_items(token: Optional[str] = Security(oauth2_scheme)): + return {"token": token} + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "security": [{"OAuth2AuthorizationCodeBearer": []}], + } + } + }, + "components": { + "securitySchemes": { + "OAuth2AuthorizationCodeBearer": { + "type": "oauth2", + "flows": { + "authorizationCode": { + "authorizationUrl": "authorize", + "tokenUrl": "token", + "scopes": {}, + } + }, + "description": "OAuth2 Code Bearer", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_no_token(): + response = client.get("/items") + assert response.status_code == 401, response.text + assert response.json() == {"detail": "Not authenticated"} + + +def test_incorrect_token(): + response = client.get("/items", headers={"Authorization": "Non-existent testtoken"}) + assert response.status_code == 401, response.text + assert response.json() == {"detail": "Not authenticated"} + + +def test_token(): + response = client.get("/items", headers={"Authorization": "Bearer testtoken"}) + assert response.status_code == 200, response.text + assert response.json() == {"token": "testtoken"} diff --git a/tests/test_security_oauth2_optional_description.py b/tests/test_security_oauth2_optional_description.py new file mode 100644 index 000000000..011db65ec --- /dev/null +++ b/tests/test_security_oauth2_optional_description.py @@ -0,0 +1,255 @@ +from typing import Optional + +import pytest +from fastapi import Depends, FastAPI, Security +from fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + +reusable_oauth2 = OAuth2( + flows={ + "password": { + "tokenUrl": "token", + "scopes": {"read:users": "Read the users", "write:users": "Create users"}, + } + }, + description="OAuth2 security scheme", + auto_error=False, +) + + +class User(BaseModel): + username: str + + +def get_current_user(oauth_header: Optional[str] = Security(reusable_oauth2)): + if oauth_header is None: + return None + user = User(username=oauth_header) + return user + + +@app.post("/login") +def login(form_data: OAuth2PasswordRequestFormStrict = Depends()): + return form_data + + +@app.get("/users/me") +def read_users_me(current_user: Optional[User] = Depends(get_current_user)): + if current_user is None: + return {"msg": "Create an account first"} + return current_user + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/login": { + "post": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Login", + "operationId": "login_login_post", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Body_login_login_post" + } + } + }, + "required": True, + }, + } + }, + "/users/me": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Users Me", + "operationId": "read_users_me_users_me_get", + "security": [{"OAuth2": []}], + } + }, + }, + "components": { + "schemas": { + "Body_login_login_post": { + "title": "Body_login_login_post", + "required": ["grant_type", "username", "password"], + "type": "object", + "properties": { + "grant_type": { + "title": "Grant Type", + "pattern": "password", + "type": "string", + }, + "username": {"title": "Username", "type": "string"}, + "password": {"title": "Password", "type": "string"}, + "scope": {"title": "Scope", "type": "string", "default": ""}, + "client_id": {"title": "Client Id", "type": "string"}, + "client_secret": {"title": "Client Secret", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + }, + "securitySchemes": { + "OAuth2": { + "type": "oauth2", + "flows": { + "password": { + "scopes": { + "read:users": "Read the users", + "write:users": "Create users", + }, + "tokenUrl": "token", + } + }, + "description": "OAuth2 security scheme", + } + }, + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_security_oauth2(): + response = client.get("/users/me", headers={"Authorization": "Bearer footokenbar"}) + assert response.status_code == 200, response.text + assert response.json() == {"username": "Bearer footokenbar"} + + +def test_security_oauth2_password_other_header(): + response = client.get("/users/me", headers={"Authorization": "Other footokenbar"}) + assert response.status_code == 200, response.text + assert response.json() == {"username": "Other footokenbar"} + + +def test_security_oauth2_password_bearer_no_header(): + response = client.get("/users/me") + assert response.status_code == 200, response.text + assert response.json() == {"msg": "Create an account first"} + + +required_params = { + "detail": [ + { + "loc": ["body", "grant_type"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["body", "username"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["body", "password"], + "msg": "field required", + "type": "value_error.missing", + }, + ] +} + +grant_type_required = { + "detail": [ + { + "loc": ["body", "grant_type"], + "msg": "field required", + "type": "value_error.missing", + } + ] +} + +grant_type_incorrect = { + "detail": [ + { + "loc": ["body", "grant_type"], + "msg": 'string does not match regex "password"', + "type": "value_error.str.regex", + "ctx": {"pattern": "password"}, + } + ] +} + + +@pytest.mark.parametrize( + "data,expected_status,expected_response", + [ + (None, 422, required_params), + ({"username": "johndoe", "password": "secret"}, 422, grant_type_required), + ( + {"username": "johndoe", "password": "secret", "grant_type": "incorrect"}, + 422, + grant_type_incorrect, + ), + ( + {"username": "johndoe", "password": "secret", "grant_type": "password"}, + 200, + { + "grant_type": "password", + "username": "johndoe", + "password": "secret", + "scopes": [], + "client_id": None, + "client_secret": None, + }, + ), + ], +) +def test_strict_login(data, expected_status, expected_response): + response = client.post("/login", data=data) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_security_oauth2_password_bearer_optional_description.py b/tests/test_security_oauth2_password_bearer_optional_description.py new file mode 100644 index 000000000..9d6a862e3 --- /dev/null +++ b/tests/test_security_oauth2_password_bearer_optional_description.py @@ -0,0 +1,76 @@ +from typing import Optional + +from fastapi import FastAPI, Security +from fastapi.security import OAuth2PasswordBearer +from fastapi.testclient import TestClient + +app = FastAPI() + +oauth2_scheme = OAuth2PasswordBearer( + tokenUrl="/token", + description="OAuth2PasswordBearer security scheme", + auto_error=False, +) + + +@app.get("/items/") +async def read_items(token: Optional[str] = Security(oauth2_scheme)): + if token is None: + return {"msg": "Create an account first"} + return {"token": token} + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "security": [{"OAuth2PasswordBearer": []}], + } + } + }, + "components": { + "securitySchemes": { + "OAuth2PasswordBearer": { + "type": "oauth2", + "flows": {"password": {"scopes": {}, "tokenUrl": "/token"}}, + "description": "OAuth2PasswordBearer security scheme", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_no_token(): + response = client.get("/items") + assert response.status_code == 200, response.text + assert response.json() == {"msg": "Create an account first"} + + +def test_token(): + response = client.get("/items", headers={"Authorization": "Bearer testtoken"}) + assert response.status_code == 200, response.text + assert response.json() == {"token": "testtoken"} + + +def test_incorrect_token(): + response = client.get("/items", headers={"Authorization": "Notexistent testtoken"}) + assert response.status_code == 200, response.text + assert response.json() == {"msg": "Create an account first"} diff --git a/tests/test_security_openid_connect_description.py b/tests/test_security_openid_connect_description.py new file mode 100644 index 000000000..218cbfc8f --- /dev/null +++ b/tests/test_security_openid_connect_description.py @@ -0,0 +1,80 @@ +from fastapi import Depends, FastAPI, Security +from fastapi.security.open_id_connect_url import OpenIdConnect +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + +oid = OpenIdConnect( + openIdConnectUrl="/openid", description="OpenIdConnect security scheme" +) + + +class User(BaseModel): + username: str + + +def get_current_user(oauth_header: str = Security(oid)): + user = User(username=oauth_header) + return user + + +@app.get("/users/me") +def read_current_user(current_user: User = Depends(get_current_user)): + return current_user + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/users/me": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Current User", + "operationId": "read_current_user_users_me_get", + "security": [{"OpenIdConnect": []}], + } + } + }, + "components": { + "securitySchemes": { + "OpenIdConnect": { + "type": "openIdConnect", + "openIdConnectUrl": "/openid", + "description": "OpenIdConnect security scheme", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_security_oauth2(): + response = client.get("/users/me", headers={"Authorization": "Bearer footokenbar"}) + assert response.status_code == 200, response.text + assert response.json() == {"username": "Bearer footokenbar"} + + +def test_security_oauth2_password_other_header(): + response = client.get("/users/me", headers={"Authorization": "Other footokenbar"}) + assert response.status_code == 200, response.text + assert response.json() == {"username": "Other footokenbar"} + + +def test_security_oauth2_password_bearer_no_header(): + response = client.get("/users/me") + assert response.status_code == 403, response.text + assert response.json() == {"detail": "Not authenticated"} From 6c80e9a8e0af97ecddbaab8c5fd696a28abd5162 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 10:31:22 +0000 Subject: [PATCH 134/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e418d0879..acec6cb55 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add `description` parameter to all the security scheme classes, e.g. `APIKeyQuery(name="key", description="A very cool API key")`. PR [#1757](https://github.com/tiangolo/fastapi/pull/1757) by [@hylkepostma](https://github.com/hylkepostma). * ✅ Add the `docs_src` directory to test coverage and update tests. PR [#1904](https://github.com/tiangolo/fastapi/pull/1904) by [@Kludex](https://github.com/Kludex). * 🌐 Add Japanese translation for `docs/tutorial/security/oauth2-jwt.md`. PR [#3526](https://github.com/tiangolo/fastapi/pull/3526) by [@sattosan](https://github.com/sattosan). * 🔧 Add new GitHub templates with forms for new issues. PR [#3612](https://github.com/tiangolo/fastapi/pull/3612) by [@tiangolo](https://github.com/tiangolo). From 6f45f437099c743f5adb8fd7268fe41a768a7a6d Mon Sep 17 00:00:00 2001 From: dkreeft <37153972+dkreeft@users.noreply.github.com> Date: Thu, 29 Jul 2021 15:10:22 +0000 Subject: [PATCH 135/814] =?UTF-8?q?=E2=9C=A8=20Add=20additonal=20OpenAPI?= =?UTF-8?q?=20metadata=20parameters=20to=20`FastAPI`=20class,=20shown=20on?= =?UTF-8?q?=20the=20automatic=20API=20docs=20UI=20(#1812)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marcelo Trylesinski Co-authored-by: dkreeft Co-authored-by: Sebastián Ramírez --- .../en/docs/img/tutorial/metadata/image01.png | Bin 38068 -> 90062 bytes docs/en/docs/tutorial/metadata.md | 23 +++++++----- docs_src/metadata/tutorial001.py | 33 +++++++++++++++--- fastapi/applications.py | 9 +++++ fastapi/openapi/utils.py | 11 +++++- .../test_metadata/test_tutorial001.py | 22 ++++++++---- 6 files changed, 79 insertions(+), 19 deletions(-) diff --git a/docs/en/docs/img/tutorial/metadata/image01.png b/docs/en/docs/img/tutorial/metadata/image01.png index e9800d532f072ddda5e99a23e5449dd1cabd5e68..b7708a3fd98ad2170d880781896623ec8ed80204 100644 GIT binary patch literal 90062 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 literal 38068 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

1ztJr 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 diff --git a/docs/en/docs/tutorial/metadata.md b/docs/en/docs/tutorial/metadata.md index 7ec305421..78f17031a 100644 --- a/docs/en/docs/tutorial/metadata.md +++ b/docs/en/docs/tutorial/metadata.md @@ -2,21 +2,28 @@ You can customize several metadata configurations in your **FastAPI** application. -## Title, description, and version +## Metadata for API -You can set the: +You can set the following fields that are used in the OpenAPI specification and the automatic API docs UIs: -* **Title**: used as your API's title/name, in OpenAPI and the automatic API docs UIs. -* **Description**: the description of your API, in OpenAPI and the automatic API docs UIs. -* **Version**: the version of your API, e.g. `v2` or `2.5.0`. - * Useful for example if you had a previous version of the application, also using OpenAPI. +| Parameter | Type | Description | +|------------|------|-------------| +| `title` | `str` | The title of the API. | +| `description` | `str` | A short description of the API. It can use Markdown. | +| `version` | `string` | The version of the API. This is the version of your own application, not of OpenAPI. For example `2.5.0`. | +| `terms_of_service` | `str` | A URL to the Terms of Service for the API. If provided, this has to be a URL. | +| `contact` | `dict` | The contact information for the exposed API. It can contain several fields.

contact fields
ParameterTypeDescription
namestrThe identifying name of the contact person/organization.
urlstrThe URL pointing to the contact information. MUST be in the format of a URL.
emailstrThe email address of the contact person/organization. MUST be in the format of an email address.
| +| `license_info` | `dict` | The license information for the exposed API. It can contain several fields.
license_info fields
ParameterTypeDescription
namestrREQUIRED (if a license_info is set). The license name used for the API.
urlstrA URL to the license used for the API. MUST be in the format of a URL.
| -To set them, use the parameters `title`, `description`, and `version`: +You can set them as follows: -```Python hl_lines="4-6" +```Python hl_lines="3-16 19-31" {!../../../docs_src/metadata/tutorial001.py!} ``` +!!! tip + You can write Markdown in the `description` field and it will be rendered in the output. + With this configuration, the automatic API docs would look like: diff --git a/docs_src/metadata/tutorial001.py b/docs_src/metadata/tutorial001.py index 16bab8a0c..3fba9e7d1 100644 --- a/docs_src/metadata/tutorial001.py +++ b/docs_src/metadata/tutorial001.py @@ -1,12 +1,37 @@ from fastapi import FastAPI +description = """ +ChimichangApp API helps you do awesome stuff. 🚀 + +## Items + +You can **read items**. + +## Users + +You will be able to: + +* **Create users** (_not implemented_). +* **Read users** (_not implemented_). +""" + app = FastAPI( - title="My Super Project", - description="This is a very fancy project, with auto docs for the API and everything", - version="2.5.0", + title="ChimichangApp", + description=description, + version="0.0.1", + terms_of_service="http://example.com/terms/", + contact={ + "name": "Deadpoolio the Amazing", + "url": "http://x-force.example.com/contact/", + "email": "dp@x-force.example.com", + }, + license_info={ + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html", + }, ) @app.get("/items/") async def read_items(): - return [{"name": "Foo"}] + return [{"name": "Katana"}] diff --git a/fastapi/applications.py b/fastapi/applications.py index 3f78238d6..b013e7b46 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -55,6 +55,9 @@ class FastAPI(Starlette): ] = None, on_startup: Optional[Sequence[Callable[[], Any]]] = None, on_shutdown: Optional[Sequence[Callable[[], Any]]] = None, + terms_of_service: Optional[str] = None, + contact: Optional[Dict[str, Union[str, Any]]] = None, + license_info: Optional[Dict[str, Union[str, Any]]] = None, openapi_prefix: str = "", root_path: str = "", root_path_in_servers: bool = True, @@ -97,6 +100,9 @@ class FastAPI(Starlette): self.title = title self.description = description self.version = version + self.terms_of_service = terms_of_service + self.contact = contact + self.license_info = license_info self.servers = servers or [] self.openapi_url = openapi_url self.openapi_tags = openapi_tags @@ -132,6 +138,9 @@ class FastAPI(Starlette): version=self.version, openapi_version=self.openapi_version, description=self.description, + terms_of_service=self.terms_of_service, + contact=self.contact, + license_info=self.license_info, routes=self.routes, tags=self.openapi_tags, servers=self.servers, diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 8dbe3902b..604ba5b00 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -362,10 +362,19 @@ def get_openapi( routes: Sequence[BaseRoute], tags: Optional[List[Dict[str, Any]]] = None, servers: Optional[List[Dict[str, Union[str, Any]]]] = None, + terms_of_service: Optional[str] = None, + contact: Optional[Dict[str, Union[str, Any]]] = None, + license_info: Optional[Dict[str, Union[str, Any]]] = None, ) -> Dict[str, Any]: - info = {"title": title, "version": version} + info: Dict[str, Any] = {"title": title, "version": version} if description: info["description"] = description + if terms_of_service: + info["termsOfService"] = terms_of_service + if contact: + info["contact"] = contact + if license_info: + info["license"] = license_info output: Dict[str, Any] = {"openapi": openapi_version, "info": info} if servers: output["servers"] = servers diff --git a/tests/test_tutorial/test_metadata/test_tutorial001.py b/tests/test_tutorial/test_metadata/test_tutorial001.py index aae79dcc4..b7281e293 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial001.py +++ b/tests/test_tutorial/test_metadata/test_tutorial001.py @@ -7,21 +7,31 @@ client = TestClient(app) openapi_schema = { "openapi": "3.0.2", "info": { - "title": "My Super Project", - "version": "2.5.0", - "description": "This is a very fancy project, with auto docs for the API and everything", + "title": "ChimichangApp", + "description": "\nChimichangApp API helps you do awesome stuff. 🚀\n\n## Items\n\nYou can **read items**.\n\n## Users\n\nYou will be able to:\n\n* **Create users** (_not implemented_).\n* **Read users** (_not implemented_).\n", + "termsOfService": "http://example.com/terms/", + "contact": { + "name": "Deadpoolio the Amazing", + "url": "http://x-force.example.com/contact/", + "email": "dp@x-force.example.com", + }, + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html", + }, + "version": "0.0.1", }, "paths": { "/items/": { "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", "responses": { "200": { "description": "Successful Response", "content": {"application/json": {"schema": {}}}, } }, - "summary": "Read Items", - "operationId": "read_items_items__get", } } }, @@ -37,4 +47,4 @@ def test_openapi_schema(): def test_items(): response = client.get("/items/") assert response.status_code == 200, response.text - assert response.json() == [{"name": "Foo"}] + assert response.json() == [{"name": "Katana"}] From 27e26b5939d837997f2132f4e181656d5450cd2f Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 15:10:59 +0000 Subject: [PATCH 136/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index acec6cb55..ed0aa1c9d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add additonal OpenAPI metadata parameters to `FastAPI` class, shown on the automatic API docs UI. PR [#1812](https://github.com/tiangolo/fastapi/pull/1812) by [@dkreeft](https://github.com/dkreeft). * ✨ Add `description` parameter to all the security scheme classes, e.g. `APIKeyQuery(name="key", description="A very cool API key")`. PR [#1757](https://github.com/tiangolo/fastapi/pull/1757) by [@hylkepostma](https://github.com/hylkepostma). * ✅ Add the `docs_src` directory to test coverage and update tests. PR [#1904](https://github.com/tiangolo/fastapi/pull/1904) by [@Kludex](https://github.com/Kludex). * 🌐 Add Japanese translation for `docs/tutorial/security/oauth2-jwt.md`. PR [#3526](https://github.com/tiangolo/fastapi/pull/3526) by [@sattosan](https://github.com/sattosan). From daa0765653805689170f919deb3c3097a2298d5f Mon Sep 17 00:00:00 2001 From: Edward Knight Date: Thu, 29 Jul 2021 16:18:20 +0100 Subject: [PATCH 137/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20docs=20about=20?= =?UTF-8?q?async=20and=20response-model=20with=20more=20gender=20neutral?= =?UTF-8?q?=20language=20(#1869)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/async.md | 12 +++++++----- docs/en/docs/tutorial/response-model.md | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index 81ab93026..7fadee87f 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -102,13 +102,15 @@ To see the difference, imagine the following story about burgers: ### Concurrent Burgers + + You go with your crush 😍 to get fast food 🍔, you stand in line while the cashier 💁 takes the orders from the people in front of you. Then it's your turn, you place your order of 2 very fancy burgers 🍔 for your crush 😍 and you. You pay 💸. -The cashier 💁 says something to the guy in the kitchen 👨‍🍳 so he knows he has to prepare your burgers 🍔 (even though he is currently preparing the ones for the previous clients). +The cashier 💁 says something to the cook in the kitchen 👨‍🍳 so they know they have to prepare your burgers 🍔 (even though they are currently preparing the ones for the previous clients). The cashier 💁 gives you the number of your turn. @@ -146,9 +148,9 @@ Now let's imagine these aren't "Concurrent Burgers", but "Parallel Burgers". You go with your crush 😍 to get parallel fast food 🍔. -You stand in line while several (let's say 8) cashiers that at the same time are cooks 👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳 take the orders from the people in front of you. +You stand in line while several (let's say 8) cashiers that at the same time are cooks 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳 take the orders from the people in front of you. -Everyone before you is waiting 🕙 for their burgers 🍔 to be ready before leaving the counter because each of the 8 cashiers goes himself and prepares the burger right away before getting the next order. +Everyone before you is waiting 🕙 for their burgers 🍔 to be ready before leaving the counter because each of the 8 cashiers goes and prepares the burger right away before getting the next order. Then it's finally your turn, you place your order of 2 very fancy burgers 🍔 for your crush 😍 and you. @@ -174,7 +176,7 @@ There was not much talk or flirting as most of the time was spent waiting 🕙 i In this scenario of the parallel burgers, you are a computer / program 🤖 with two processors (you and your crush 😍), both waiting 🕙 and dedicating their attention ⏯ to be "waiting on the counter" 🕙 for a long time. -The fast food store has 8 processors (cashiers/cooks) 👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳. While the concurrent burgers store might have had only 2 (one cashier and one cook) 💁 👨‍🍳. +The fast food store has 8 processors (cashiers/cooks) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳. While the concurrent burgers store might have had only 2 (one cashier and one cook) 💁 👨‍🍳. But still, the final experience is not the best 😞. @@ -236,7 +238,7 @@ You could have turns as in the burgers example, first the living room, then the It would take the same amount of time to finish with or without turns (concurrency) and you would have done the same amount of work. -But in this case, if you could bring the 8 ex-cashier/cooks/now-cleaners 👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳, and each one of them (plus you) could take a zone of the house to clean it, you could do all the work in **parallel**, with the extra help, and finish much sooner. +But in this case, if you could bring the 8 ex-cashier/cooks/now-cleaners 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, and each one of them (plus you) could take a zone of the house to clean it, you could do all the work in **parallel**, with the extra help, and finish much sooner. In this scenario, each one of the cleaners (including you) would be a processor, doing their part of the job. diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md index fdf661134..e2b89ca9e 100644 --- a/docs/en/docs/tutorial/response-model.md +++ b/docs/en/docs/tutorial/response-model.md @@ -47,7 +47,7 @@ And we are using this model to declare our input and the same model to declare o Now, whenever a browser is creating a user with a password, the API will return the same password in the response. -In this case, it might not be a problem, because the user himself is sending the password. +In this case, it might not be a problem, because the user themself is sending the password. But if we use the same model for another *path operation*, we could be sending our user's passwords to every client. From 6a74f3a0c1abd81904dbcbe9250a449eb165eb8c Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 15:18:55 +0000 Subject: [PATCH 138/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ed0aa1c9d..3fa27c82f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update docs about async and response-model with more gender neutral language. PR [#1869](https://github.com/tiangolo/fastapi/pull/1869) by [@Edward-Knight](https://github.com/Edward-Knight). * ✨ Add additonal OpenAPI metadata parameters to `FastAPI` class, shown on the automatic API docs UI. PR [#1812](https://github.com/tiangolo/fastapi/pull/1812) by [@dkreeft](https://github.com/dkreeft). * ✨ Add `description` parameter to all the security scheme classes, e.g. `APIKeyQuery(name="key", description="A very cool API key")`. PR [#1757](https://github.com/tiangolo/fastapi/pull/1757) by [@hylkepostma](https://github.com/hylkepostma). * ✅ Add the `docs_src` directory to test coverage and update tests. PR [#1904](https://github.com/tiangolo/fastapi/pull/1904) by [@Kludex](https://github.com/Kludex). From 4eada92883e97ea3d01ce716abfa34079c691d84 Mon Sep 17 00:00:00 2001 From: James Curtin Date: Thu, 29 Jul 2021 11:30:18 -0400 Subject: [PATCH 139/814] =?UTF-8?q?=E2=9C=A8=20Import=20and=20re-export=20?= =?UTF-8?q?data=20structures=20from=20Starlette,=20used=20by=20Request=20p?= =?UTF-8?q?roperties,=20on=20`fastapi.datastructures`=20(#1872)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/datastructures.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py index 6a44a7df4..b13171287 100644 --- a/fastapi/datastructures.py +++ b/fastapi/datastructures.py @@ -1,5 +1,10 @@ from typing import Any, Callable, Iterable, Type, TypeVar +from starlette.datastructures import URL as URL # noqa: F401 +from starlette.datastructures import Address as Address # noqa: F401 +from starlette.datastructures import FormData as FormData # noqa: F401 +from starlette.datastructures import Headers as Headers # noqa: F401 +from starlette.datastructures import QueryParams as QueryParams # noqa: F401 from starlette.datastructures import State as State # noqa: F401 from starlette.datastructures import UploadFile as StarletteUploadFile From 7db359182da8717478e5d2c4745a1c9148495564 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 15:30:57 +0000 Subject: [PATCH 140/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3fa27c82f..e5eacfc8a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Import and re-export data structures from Starlette, used by Request properties, on `fastapi.datastructures`. PR [#1872](https://github.com/tiangolo/fastapi/pull/1872) by [@jamescurtin](https://github.com/jamescurtin). * 📝 Update docs about async and response-model with more gender neutral language. PR [#1869](https://github.com/tiangolo/fastapi/pull/1869) by [@Edward-Knight](https://github.com/Edward-Knight). * ✨ Add additonal OpenAPI metadata parameters to `FastAPI` class, shown on the automatic API docs UI. PR [#1812](https://github.com/tiangolo/fastapi/pull/1812) by [@dkreeft](https://github.com/dkreeft). * ✨ Add `description` parameter to all the security scheme classes, e.g. `APIKeyQuery(name="key", description="A very cool API key")`. PR [#1757](https://github.com/tiangolo/fastapi/pull/1757) by [@hylkepostma](https://github.com/hylkepostma). From 836bb97a2d343937205a01a9829b975c48cdfcad Mon Sep 17 00:00:00 2001 From: Edouard Lavery-Plante Date: Thu, 29 Jul 2021 16:01:13 -0400 Subject: [PATCH 141/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20exten?= =?UTF-8?q?sions=20and=20updates=20to=20the=20OpenAPI=20schema=20in=20path?= =?UTF-8?q?=20operations=20(#1922)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../path-operation-advanced-configuration.md | 120 +++++++++++++++++- .../image01.png | Bin 0 -> 68080 bytes .../tutorial005.py | 8 ++ .../tutorial006.py | 41 ++++++ .../tutorial007.py | 34 +++++ fastapi/applications.py | 20 +++ fastapi/openapi/models.py | 3 + fastapi/openapi/utils.py | 2 + fastapi/routing.py | 23 ++++ tests/test_openapi_route_extensions.py | 45 +++++++ .../test_tutorial005.py | 36 ++++++ .../test_tutorial006.py | 59 +++++++++ .../test_tutorial007.py | 97 ++++++++++++++ 13 files changed, 487 insertions(+), 1 deletion(-) create mode 100644 docs/en/docs/img/tutorial/path-operation-advanced-configuration/image01.png create mode 100644 docs_src/path_operation_advanced_configuration/tutorial005.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial006.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial007.py create mode 100644 tests/test_openapi_route_extensions.py create mode 100644 tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py create mode 100644 tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py create mode 100644 tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py diff --git a/docs/en/docs/advanced/path-operation-advanced-configuration.md b/docs/en/docs/advanced/path-operation-advanced-configuration.md index 8d085d754..352fe0764 100644 --- a/docs/en/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/en/docs/advanced/path-operation-advanced-configuration.md @@ -33,7 +33,7 @@ You should do it after adding all your *path operations*. ## Exclude from OpenAPI -To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`; +To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`: ```Python hl_lines="6" {!../../../docs_src/path_operation_advanced_configuration/tutorial003.py!} @@ -50,3 +50,121 @@ It won't show up in the documentation, but other tools (such as Sphinx) will be ```Python hl_lines="19-29" {!../../../docs_src/path_operation_advanced_configuration/tutorial004.py!} ``` + +## Additional Responses + +You probably have seen how to declare the `response_model` and `status_code` for a *path operation*. + +That defines the metadata about the main response of a *path operation*. + +You can also declare additional responses with their models, status codes, etc. + +There's a whole chapter here in the documentation about it, you can read it at [Additional Responses in OpenAPI](./additional-responses.md){.internal-link target=_blank}. + +## OpenAPI Extra + +When you declare a *path operation* in your application, **FastAPI** automatically generates the relevant metadata about that *path operation* to be included in the OpenAPI schema. + +!!! note "Technical details" + In the OpenAPI specification it is called the
Operation Object. + +It has all the information about the *path operation* and is used to generate the automatic documentation. + +It includes the `tags`, `parameters`, `requestBody`, `responses`, etc. + +This *path operation*-specific OpenAPI schema is normally generated automatically by **FastAPI**, but you can also extend it. + +!!! tip + This is a low level extension point. + + If you only need to declare additonal responses, a more convenient way to do it is with [Additional Responses in OpenAPI](./additional-responses.md){.internal-link target=_blank}. + +You can extend the OpenAPI schema for a *path operation* using the parameter `openapi_extra`. + +### OpenAPI Extensions + +This `openapi_extra` can be helpful, for example, to declare [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions): + +```Python hl_lines="6" +{!../../../docs_src/path_operation_advanced_configuration/tutorial005.py!} +``` + +If you open the automatic API docs, your extension will show up at the bottom of the specific *path operation*. + + + +And if you see the resulting OpenAPI (at `/openapi.json` in your API), you will see your extension as part of the specific *path operation* too: + +```JSON hl_lines="22" +{ + "openapi": "3.0.2", + "info": { + "title": "FastAPI", + "version": "0.1.0" + }, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "x-aperture-labs-portal": "blue" + } + } + } +} +``` + +### Custom OpenAPI *path operation* schema + +The dictionary in `openapi_extra` will be deeply merged with the automatically generated OpenAPI schema for the *path operation*. + +So, you could add additional data to the automatically generated schema. + +For example, you could decide to read and validate the request with your own code, without using the automatic features of FastAPI with Pydantic, but you could still want to define the request in the OpenAPI schema. + +You could do that with `openapi_extra`: + +```Python hl_lines="20-37 39-40" +{!../../../docs_src/path_operation_advanced_configuration/tutorial006.py!} +``` + +In this example, we didn't declare any Pydantic model. In fact, the request body is not even parsed as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way. + +Nevertheless, we can declare the expected schema for the request body. + +### Custom OpenAPI content type + +Using this same trick, you could use a Pydantic model to define the JSON Schema that is then included in the custom OpenAPI schema section for the *path operation*. + +And you could do this even if the data type in the request is not JSON. + +For example, in this application we don't use FastAPI's integrated functionality to extract the JSON Schema from Pydantic models nor the automatic validation for JSON. In fact, we are declaring the request content type as YAML, not JSON: + +```Python hl_lines="17-22 24" +{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!} +``` + +Nevertheless, although we are not using the default integrated functionality, we are still using a Pydantic model to manually generate the JSON Schema for the data that we want to receive in YAML. + +Then we use the request directly, and extract the body as `bytes`. This means that FastAPI won't even try to parse the request payload as JSON. + +And then in our code, we parse that YAML content directly, and then we are again using the same Pydantic model to validate the YAML content: + +```Python hl_lines="26-33" +{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!} +``` + +!!! tip + Here we re-use the same Pydantic model. + + But the same way, we could have validated it in some other way. diff --git a/docs/en/docs/img/tutorial/path-operation-advanced-configuration/image01.png b/docs/en/docs/img/tutorial/path-operation-advanced-configuration/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..554e7c45664e4a8d12b2ac28712553f99f6ece49 GIT binary patch literal 68080 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 literal 0 HcmV?d00001 diff --git a/docs_src/path_operation_advanced_configuration/tutorial005.py b/docs_src/path_operation_advanced_configuration/tutorial005.py new file mode 100644 index 000000000..5837ad835 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial005.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/", openapi_extra={"x-aperture-labs-portal": "blue"}) +async def read_items(): + return [{"item_id": "portal-gun"}] diff --git a/docs_src/path_operation_advanced_configuration/tutorial006.py b/docs_src/path_operation_advanced_configuration/tutorial006.py new file mode 100644 index 000000000..403c3ee3f --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial006.py @@ -0,0 +1,41 @@ +from fastapi import FastAPI, Request + +app = FastAPI() + + +def magic_data_reader(raw_body: bytes): + return { + "size": len(raw_body), + "content": { + "name": "Maaaagic", + "price": 42, + "description": "Just kiddin', no magic here. ✨", + }, + } + + +@app.post( + "/items/", + openapi_extra={ + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"type": "string"}, + "price": {"type": "number"}, + "description": {"type": "string"}, + }, + } + } + }, + "required": True, + }, + }, +) +async def create_item(request: Request): + raw_body = await request.body() + data = magic_data_reader(raw_body) + return data diff --git a/docs_src/path_operation_advanced_configuration/tutorial007.py b/docs_src/path_operation_advanced_configuration/tutorial007.py new file mode 100644 index 000000000..d51752bb8 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial007.py @@ -0,0 +1,34 @@ +from typing import List + +import yaml +from fastapi import FastAPI, HTTPException, Request +from pydantic import BaseModel, ValidationError + +app = FastAPI() + + +class Item(BaseModel): + name: str + tags: List[str] + + +@app.post( + "/items/", + openapi_extra={ + "requestBody": { + "content": {"application/x-yaml": {"schema": Item.schema()}}, + "required": True, + }, + }, +) +async def create_item(request: Request): + raw_body = await request.body() + try: + data = yaml.safe_load(raw_body) + except yaml.YAMLError: + raise HTTPException(status_code=422, detail="Invalid YAML") + try: + item = Item.parse_obj(data) + except ValidationError as e: + raise HTTPException(status_code=422, detail=e.errors()) + return item diff --git a/fastapi/applications.py b/fastapi/applications.py index b013e7b46..0c25026e2 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -236,6 +236,7 @@ class FastAPI(Starlette): JSONResponse ), name: Optional[str] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> None: self.router.add_api_route( path, @@ -260,6 +261,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class, name=name, + openapi_extra=openapi_extra, ) def api_route( @@ -286,6 +288,7 @@ class FastAPI(Starlette): include_in_schema: bool = True, response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: self.router.add_api_route( @@ -311,6 +314,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, response_class=response_class, name=name, + openapi_extra=openapi_extra, ) return func @@ -379,6 +383,7 @@ class FastAPI(Starlette): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.get( path, @@ -402,6 +407,7 @@ class FastAPI(Starlette): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def put( @@ -428,6 +434,7 @@ class FastAPI(Starlette): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.put( path, @@ -451,6 +458,7 @@ class FastAPI(Starlette): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def post( @@ -477,6 +485,7 @@ class FastAPI(Starlette): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.post( path, @@ -500,6 +509,7 @@ class FastAPI(Starlette): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def delete( @@ -526,6 +536,7 @@ class FastAPI(Starlette): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.delete( path, @@ -549,6 +560,7 @@ class FastAPI(Starlette): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def options( @@ -575,6 +587,7 @@ class FastAPI(Starlette): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.options( path, @@ -598,6 +611,7 @@ class FastAPI(Starlette): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def head( @@ -624,6 +638,7 @@ class FastAPI(Starlette): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.head( path, @@ -647,6 +662,7 @@ class FastAPI(Starlette): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def patch( @@ -673,6 +689,7 @@ class FastAPI(Starlette): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.patch( path, @@ -696,6 +713,7 @@ class FastAPI(Starlette): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def trace( @@ -722,6 +740,7 @@ class FastAPI(Starlette): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.trace( path, @@ -745,4 +764,5 @@ class FastAPI(Starlette): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index efbd88ad7..4f55aa001 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -227,6 +227,9 @@ class Operation(BaseModel): security: Optional[List[Dict[str, List[str]]]] = None servers: Optional[List[Server]] = None + class Config: + extra = "allow" + class PathItem(BaseModel): ref: Optional[str] = Field(None, alias="$ref") diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 604ba5b00..0e73e21bf 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -317,6 +317,8 @@ def get_openapi_path( "HTTPValidationError": validation_error_response_definition, } ) + if route.openapi_extra: + deep_dict_update(operation, route.openapi_extra) path[method.lower()] = operation return path, security_schemes, definitions diff --git a/fastapi/routing.py b/fastapi/routing.py index f5fe0c0bd..0ad082341 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -320,6 +320,7 @@ class APIRoute(routing.Route): ), dependency_overrides_provider: Optional[Any] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> None: # normalise enums e.g. http.HTTPStatus if isinstance(status_code, enum.IntEnum): @@ -406,6 +407,7 @@ class APIRoute(routing.Route): self.dependency_overrides_provider = dependency_overrides_provider self.callbacks = callbacks self.app = request_response(self.get_route_handler()) + self.openapi_extra = openapi_extra def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]: return get_request_handler( @@ -496,6 +498,7 @@ class APIRouter(routing.Router): name: Optional[str] = None, route_class_override: Optional[Type[APIRoute]] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> None: route_class = route_class_override or self.route_class responses = responses or {} @@ -537,6 +540,7 @@ class APIRouter(routing.Router): name=name, dependency_overrides_provider=self.dependency_overrides_provider, callbacks=current_callbacks, + openapi_extra=openapi_extra, ) self.routes.append(route) @@ -565,6 +569,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_api_route( @@ -591,6 +596,7 @@ class APIRouter(routing.Router): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) return func @@ -695,6 +701,7 @@ class APIRouter(routing.Router): name=route.name, route_class_override=type(route), callbacks=current_callbacks, + openapi_extra=route.openapi_extra, ) elif isinstance(route, routing.Route): methods = list(route.methods or []) # type: ignore # in Starlette @@ -742,6 +749,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -766,6 +774,7 @@ class APIRouter(routing.Router): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def put( @@ -792,6 +801,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -816,6 +826,7 @@ class APIRouter(routing.Router): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def post( @@ -842,6 +853,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -866,6 +878,7 @@ class APIRouter(routing.Router): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def delete( @@ -892,6 +905,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -916,6 +930,7 @@ class APIRouter(routing.Router): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def options( @@ -942,6 +957,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -966,6 +982,7 @@ class APIRouter(routing.Router): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def head( @@ -992,6 +1009,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -1016,6 +1034,7 @@ class APIRouter(routing.Router): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def patch( @@ -1042,6 +1061,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -1066,6 +1086,7 @@ class APIRouter(routing.Router): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) def trace( @@ -1092,6 +1113,7 @@ class APIRouter(routing.Router): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, + openapi_extra: Optional[Dict[str, Any]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( @@ -1117,4 +1139,5 @@ class APIRouter(routing.Router): response_class=response_class, name=name, callbacks=callbacks, + openapi_extra=openapi_extra, ) diff --git a/tests/test_openapi_route_extensions.py b/tests/test_openapi_route_extensions.py new file mode 100644 index 000000000..8a1080d69 --- /dev/null +++ b/tests/test_openapi_route_extensions.py @@ -0,0 +1,45 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient + +app = FastAPI() + + +@app.get("/", openapi_extra={"x-custom-extension": "value"}) +def route_with_extras(): + return {} + + +client = TestClient(app) + + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + }, + "summary": "Route With Extras", + "operationId": "route_with_extras__get", + "x-custom-extension": "value", + } + }, + }, +} + + +def test_openapi(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_get_route(): + response = client.get("/") + assert response.status_code == 200, response.text + assert response.json() == {} diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py new file mode 100644 index 000000000..5042d1837 --- /dev/null +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py @@ -0,0 +1,36 @@ +from fastapi.testclient import TestClient + +from docs_src.path_operation_advanced_configuration.tutorial005 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "x-aperture-labs-portal": "blue", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_get(): + response = client.get("/items/") + assert response.status_code == 200, response.text diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py new file mode 100644 index 000000000..5533b2957 --- /dev/null +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py @@ -0,0 +1,59 @@ +from fastapi.testclient import TestClient + +from docs_src.path_operation_advanced_configuration.tutorial006 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"type": "string"}, + "price": {"type": "number"}, + "description": {"type": "string"}, + }, + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_post(): + response = client.post("/items/", data=b"this is actually not validated") + assert response.status_code == 200, response.text + assert response.json() == { + "size": 30, + "content": { + "name": "Maaaagic", + "price": 42, + "description": "Just kiddin', no magic here. ✨", + }, + } diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py new file mode 100644 index 000000000..cb5dbc8eb --- /dev/null +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py @@ -0,0 +1,97 @@ +from fastapi.testclient import TestClient + +from docs_src.path_operation_advanced_configuration.tutorial007 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/x-yaml": { + "schema": { + "title": "Item", + "required": ["name", "tags"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "tags": { + "title": "Tags", + "type": "array", + "items": {"type": "string"}, + }, + }, + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_post(): + yaml_data = """ + name: Deadpoolio + tags: + - x-force + - x-men + - x-avengers + """ + response = client.post("/items/", data=yaml_data) + assert response.status_code == 200, response.text + assert response.json() == { + "name": "Deadpoolio", + "tags": ["x-force", "x-men", "x-avengers"], + } + + +def test_post_broken_yaml(): + yaml_data = """ + name: Deadpoolio + tags: + x - x-force + x - x-men + x - x-avengers + """ + response = client.post("/items/", data=yaml_data) + assert response.status_code == 422, response.text + assert response.json() == {"detail": "Invalid YAML"} + + +def test_post_invalid(): + yaml_data = """ + name: Deadpoolio + tags: + - x-force + - x-men + - x-avengers + - sneaky: object + """ + response = client.post("/items/", data=yaml_data) + assert response.status_code == 422, response.text + assert response.json() == { + "detail": [ + {"loc": ["tags", 3], "msg": "str type expected", "type": "type_error.str"} + ] + } From b8c4149e89d1c97d204ac3f965e6144e3dc126a9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 20:01:49 +0000 Subject: [PATCH 142/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e5eacfc8a..91cfbe017 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for extensions and updates to the OpenAPI schema in path operations. PR [#1922](https://github.com/tiangolo/fastapi/pull/1922) by [@edouardlp](https://github.com/edouardlp). * ✨ Import and re-export data structures from Starlette, used by Request properties, on `fastapi.datastructures`. PR [#1872](https://github.com/tiangolo/fastapi/pull/1872) by [@jamescurtin](https://github.com/jamescurtin). * 📝 Update docs about async and response-model with more gender neutral language. PR [#1869](https://github.com/tiangolo/fastapi/pull/1869) by [@Edward-Knight](https://github.com/Edward-Knight). * ✨ Add additonal OpenAPI metadata parameters to `FastAPI` class, shown on the automatic API docs UI. PR [#1812](https://github.com/tiangolo/fastapi/pull/1812) by [@dkreeft](https://github.com/dkreeft). From fadfcfda4aa38513c30645c03b14e3076557751c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 29 Jul 2021 22:12:55 +0200 Subject: [PATCH 143/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 91cfbe017..5745d624b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,13 +2,24 @@ ## Latest Changes -* ✨ Add support for extensions and updates to the OpenAPI schema in path operations. PR [#1922](https://github.com/tiangolo/fastapi/pull/1922) by [@edouardlp](https://github.com/edouardlp). -* ✨ Import and re-export data structures from Starlette, used by Request properties, on `fastapi.datastructures`. PR [#1872](https://github.com/tiangolo/fastapi/pull/1872) by [@jamescurtin](https://github.com/jamescurtin). -* 📝 Update docs about async and response-model with more gender neutral language. PR [#1869](https://github.com/tiangolo/fastapi/pull/1869) by [@Edward-Knight](https://github.com/Edward-Knight). -* ✨ Add additonal OpenAPI metadata parameters to `FastAPI` class, shown on the automatic API docs UI. PR [#1812](https://github.com/tiangolo/fastapi/pull/1812) by [@dkreeft](https://github.com/dkreeft). +### Features + +* ✨ Add support for extensions and updates to the OpenAPI schema in each *path operation*. New docs: [FastAPI Path Operation Advanced Configuration - OpenAPI Extra](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#openapi-extra). Initial PR [#1922](https://github.com/tiangolo/fastapi/pull/1922) by [@edouardlp](https://github.com/edouardlp). +* ✨ Add additonal OpenAPI metadata parameters to `FastAPI` class, shown on the automatic API docs UI. New docs: [Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/). Initial PR [#1812](https://github.com/tiangolo/fastapi/pull/1812) by [@dkreeft](https://github.com/dkreeft). * ✨ Add `description` parameter to all the security scheme classes, e.g. `APIKeyQuery(name="key", description="A very cool API key")`. PR [#1757](https://github.com/tiangolo/fastapi/pull/1757) by [@hylkepostma](https://github.com/hylkepostma). -* ✅ Add the `docs_src` directory to test coverage and update tests. PR [#1904](https://github.com/tiangolo/fastapi/pull/1904) by [@Kludex](https://github.com/Kludex). +* ✨ Import and re-export data structures from Starlette, used by Request properties, on `fastapi.datastructures`. Initial PR [#1872](https://github.com/tiangolo/fastapi/pull/1872) by [@jamescurtin](https://github.com/jamescurtin). + +### Docs + +* 📝 Update docs about async and response-model with more gender neutral language. PR [#1869](https://github.com/tiangolo/fastapi/pull/1869) by [@Edward-Knight](https://github.com/Edward-Knight). + +### Translations + * 🌐 Add Japanese translation for `docs/tutorial/security/oauth2-jwt.md`. PR [#3526](https://github.com/tiangolo/fastapi/pull/3526) by [@sattosan](https://github.com/sattosan). + +### Internal + +* ✅ Add the `docs_src` directory to test coverage and update tests. Initial PR [#1904](https://github.com/tiangolo/fastapi/pull/1904) by [@Kludex](https://github.com/Kludex). * 🔧 Add new GitHub templates with forms for new issues. PR [#3612](https://github.com/tiangolo/fastapi/pull/3612) by [@tiangolo](https://github.com/tiangolo). * 📝 Add official FastAPI Twitter to docs: [@fastapi](https://twitter.com/fastapi). PR [#3578](https://github.com/tiangolo/fastapi/pull/3578) by [@tiangolo](https://github.com/tiangolo). From 8879757a8829562b40e2d23f72e72dd8ce2408d4 Mon Sep 17 00:00:00 2001 From: Lucas <61513630+lsglucas@users.noreply.github.com> Date: Thu, 29 Jul 2021 17:14:40 -0300 Subject: [PATCH 144/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/deployment/versions.md`=20(#3618)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marcelo Trylesinski --- docs/pt/docs/deployment/versions.md | 87 +++++++++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 88 insertions(+) create mode 100644 docs/pt/docs/deployment/versions.md diff --git a/docs/pt/docs/deployment/versions.md b/docs/pt/docs/deployment/versions.md new file mode 100644 index 000000000..77d9bab69 --- /dev/null +++ b/docs/pt/docs/deployment/versions.md @@ -0,0 +1,87 @@ +# Sobre as versões do FastAPI + +**FastAPI** já está sendo usado em produção em diversas aplicações e sistemas, a cobertura de testes é mantida em 100%, mas seu desenvolvimento está avançando rapidamente. + +Novos recursos são adicionados com frequência, bugs são corrigidos regularmente e o código está sempre melhorando. + +Esse é o motivo das versões atuais estarem em `0.x.x`, significando que em cada versão pode haver mudanças significativas, tudo isso seguindo as convenções de controle de versão semântica. + +Já é possível criar aplicativos de produção com **FastAPI** (e provavelmente você já faz isso há algum tempo), apenas precisando ter certeza de usar uma versão que funcione corretamente com o resto do seu código. + +## Fixe a sua versão de `fastapi` + +A primeira coisa que você deve fazer é "fixar" a versão do **FastAPI** que você está utilizando na mais atual, na qual você sabe que funciona corretamente para o seu aplicativo. + +Por exemplo, supondo que você está usando a versão `0.45.0` em sua aplicação. + +Caso você utilize o arquivo `requirements.txt`, você poderia especificar a versão com: + +```txt +fastapi==0.45.0 +``` + +Isso significa que você conseguiria utilizar a versão exata `0.45.0`. + +Ou, você poderia fixá-la com: + +```txt +fastapi>=0.45.0,<0.46.0 +``` + +isso significa que você iria usar as versões `0.45.0` ou acima, mas inferiores à `0.46.0`, por exemplo, a versão `0.45.2` ainda seria aceita. + +Se você usar qualquer outra ferramenta para gerenciar suas instalações, como Poetry, Pipenv ou outras, todas elas têm uma maneira que você pode usar para definir as versões específicas dos seus pacotes. + +## Versões disponíveis + +Você pode ver as versões disponíveis (por exemplo, para verificar qual é a versão atual) em [Release Notes](../release-notes.md){.internal-link target=\_blank}. + +## Sobre versões + +Seguindo as convenções de controle de versão semântica, qualquer versão abaixo de `1.0.0` pode adicionar mudanças significativas. + +FastAPI também segue a convenção de que qualquer alteração de versão "PATCH" é para correção de bugs e alterações não significativas. + +!!! tip "Dica" + O "PATCH" é o último número, por exemplo, em `0.2.3`, a versão PATCH é `3`. + +Logo, você deveria conseguir fixar a versão, como: + +```txt +fastapi>=0.45.0,<0.46.0 +``` + +Mudanças significativas e novos recursos são adicionados em versões "MINOR". + +!!! tip "Dica" + O "MINOR" é o número que está no meio, por exemplo, em `0.2.3`, a versão MINOR é `2`. + +## Atualizando as versões do FastAPI + +Você deve adicionar testes para a sua aplicação. + +Com **FastAPI** isso é muito fácil (graças a Starlette), verifique a documentação: [Testing](../tutorial/testing.md){.internal-link target=\_blank} + +Após a criação dos testes, você pode atualizar a sua versão do **FastAPI** para uma mais recente, execute os testes para se certificar de que todo o seu código está funcionando corretamente. + +Se tudo estiver funcionando, ou após você realizar as alterações necessárias e todos os testes estiverem passando, então você pode fixar sua versão de `FastAPI` para essa mais nova. + +## Sobre Starlette + +Não é recomendado fixar a versão de `starlette`. + +Versões diferentes de **FastAPI** utilizarão uma versão específica e mais recente de Starlette. + +Então, você pode deixar **FastAPI** escolher a versão compatível e correta de Starlette. + +## Sobre Pydantic + +Pydantic incluí os testes para **FastAPI** em seus próprios testes, então as novas versões de Pydantic (acima da `1.0.0`) sempre serão compatíveis com FastAPI. + +Você pode fixar qualquer versão de Pydantic que desejar, desde que seja acima da `1.0.0` e abaixo da `2.0.0`. + +Por exemplo: + +```txt +pydantic>=1.2.0,<2.0.0 +``` diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 617204515..fd2ac2190 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -62,6 +62,7 @@ nav: - tutorial/security/index.md - Implantação: - deployment/index.md + - deployment/versions.md - alternatives.md - history-design-future.md - external-links.md From 4eb9c606529263f3c5e65d7e71a86d21c82f31ff Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 20:15:22 +0000 Subject: [PATCH 145/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5745d624b..f33d1f649 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/deployment/versions.md`. PR [#3618](https://github.com/tiangolo/fastapi/pull/3618) by [@lsglucas](https://github.com/lsglucas). ### Features * ✨ Add support for extensions and updates to the OpenAPI schema in each *path operation*. New docs: [FastAPI Path Operation Advanced Configuration - OpenAPI Extra](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#openapi-extra). Initial PR [#1922](https://github.com/tiangolo/fastapi/pull/1922) by [@edouardlp](https://github.com/edouardlp). From 016c3f0d5b0e11ee9d97ebc63249de1ee4e71a48 Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Fri, 30 Jul 2021 04:15:54 +0800 Subject: [PATCH 146/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20`docs/tutorial/dependencies/global-dependencies.md`?= =?UTF-8?q?=20(#3493)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit as title --- .../dependencies/global-dependencies.md | 18 ++++++++++++++++++ docs/zh/mkdocs.yml | 2 ++ 2 files changed, 20 insertions(+) create mode 100644 docs/zh/docs/tutorial/dependencies/global-dependencies.md diff --git a/docs/zh/docs/tutorial/dependencies/global-dependencies.md b/docs/zh/docs/tutorial/dependencies/global-dependencies.md new file mode 100644 index 000000000..5c367ff09 --- /dev/null +++ b/docs/zh/docs/tutorial/dependencies/global-dependencies.md @@ -0,0 +1,18 @@ +# 全局依赖项 + +有时,我们要为整个应用添加依赖项。 + +通过与定义[*路径装饰器依赖项*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} 类似的方式,可以把依赖项添加至整个 `FastAPI` 应用。 + +这样一来,就可以为所有*路径操作*应用该依赖项: + +```Python hl_lines="15" +{!../../../docs_src/dependencies/tutorial012.py!} +``` + +[*路径装饰器依赖项*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} 一章的思路均适用于全局依赖项, 在本例中,这些依赖项可以用于应用中的所有*路径操作*。 + +## 为一组路径操作定义依赖项 + +稍后,[大型应用 - 多文件](../../tutorial/bigger-applications.md){.internal-link target=_blank}一章中会介绍如何使用多个文件创建大型应用程序,在这一章中,您将了解到如何为一组*路径操作*声明单个 `dependencies` 参数。 + diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index b7312b917..6fb6b191a 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -80,6 +80,8 @@ nav: - tutorial/request-forms-and-files.md - tutorial/handling-errors.md - tutorial/body-updates.md + - 依赖项: + - tutorial/dependencies/global-dependencies.md - 安全性: - tutorial/security/index.md - tutorial/security/get-current-user.md From b869c7c872d861692cc1646eb1f59cbc21922e64 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 20:16:29 +0000 Subject: [PATCH 147/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f33d1f649..ae9940d76 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for `docs/tutorial/dependencies/global-dependencies.md`. PR [#3493](https://github.com/tiangolo/fastapi/pull/3493) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Portuguese translation for `docs/deployment/versions.md`. PR [#3618](https://github.com/tiangolo/fastapi/pull/3618) by [@lsglucas](https://github.com/lsglucas). ### Features From 85cff591095cb86cb896608b42dedb3f8eecbc80 Mon Sep 17 00:00:00 2001 From: Urchin Date: Thu, 29 Jul 2021 23:21:06 +0300 Subject: [PATCH 148/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Russian=20translat?= =?UTF-8?q?ion=20for=20`docs/external-links.md`=20(#3036)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ru/docs/external-links.md | 82 ++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 docs/ru/docs/external-links.md diff --git a/docs/ru/docs/external-links.md b/docs/ru/docs/external-links.md new file mode 100644 index 000000000..4daf65898 --- /dev/null +++ b/docs/ru/docs/external-links.md @@ -0,0 +1,82 @@ +# Внешние ссылки и статьи + +**FastAPI** имеет отличное и постоянно растущее сообщество. + +Существует множество сообщений, статей, инструментов и проектов, связанных с **FastAPI**. + +Вот неполный список некоторых из них. + +!!! tip + Если у вас есть статья, проект, инструмент или что-либо, связанное с **FastAPI**, что еще не перечислено здесь, создайте Pull Request. + +## Статьи + +### На английском + +{% if external_links %} +{% for article in external_links.articles.english %} + +* {{ article.title }} by {{ article.author }}. +{% endfor %} +{% endif %} + +### На японском + +{% if external_links %} +{% for article in external_links.articles.japanese %} + +* {{ article.title }} by {{ article.author }}. +{% endfor %} +{% endif %} + +### На вьетнамском + +{% if external_links %} +{% for article in external_links.articles.vietnamese %} + +* {{ article.title }} by {{ article.author }}. +{% endfor %} +{% endif %} + +### На русском + +{% if external_links %} +{% for article in external_links.articles.russian %} + +* {{ article.title }} by {{ article.author }}. +{% endfor %} +{% endif %} + +### На немецком + +{% if external_links %} +{% for article in external_links.articles.german %} + +* {{ article.title }} by {{ article.author }}. +{% endfor %} +{% endif %} + +## Подкасты + +{% if external_links %} +{% for article in external_links.podcasts.english %} + +* {{ article.title }} by {{ article.author }}. +{% endfor %} +{% endif %} + +## Talks + +{% if external_links %} +{% for article in external_links.talks.english %} + +* {{ article.title }} by {{ article.author }}. +{% endfor %} +{% endif %} + +## Проекты + +Последние GitHub-проекты с пометкой `fastapi`: + +
+
From 962578bec2a66c1266f37e480553c9bc900bac72 Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Fri, 30 Jul 2021 04:21:38 +0800 Subject: [PATCH 149/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20`docs/tutorial/dependencies/index.md`=20(#3489)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/zh/docs/tutorial/dependencies/index.md | 212 ++++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 213 insertions(+) create mode 100644 docs/zh/docs/tutorial/dependencies/index.md diff --git a/docs/zh/docs/tutorial/dependencies/index.md b/docs/zh/docs/tutorial/dependencies/index.md new file mode 100644 index 000000000..82e9f536d --- /dev/null +++ b/docs/zh/docs/tutorial/dependencies/index.md @@ -0,0 +1,212 @@ +# 依赖项 - 第一步 + +FastAPI 提供了简单易用,但功能强大的**依赖注入**系统。 + +这个依赖系统设计的简单易用,可以让开发人员轻松地把组件集成至 **FastAPI**。 + +## 什么是「依赖注入」 + +编程中的**「依赖注入」**是声明代码(本文中为*路径操作函数* )运行所需的,或要使用的「依赖」的一种方式。 + +然后,由系统(本文中为 **FastAPI**)负责执行任意需要的逻辑,为代码提供这些依赖(「注入」依赖项)。 + +依赖注入常用于以下场景: + +* 共享业务逻辑(复用相同的代码逻辑) +* 共享数据库连接 +* 实现安全、验证、角色权限 +* 等…… + +上述场景均可以使用**依赖注入**,将代码重复最小化。 + +## 第一步 + +接下来,我们学习一个非常简单的例子,尽管它过于简单,不是很实用。 + +但通过这个例子,您可以初步了解「依赖注入」的工作机制。 + +### 创建依赖项 + +首先,要关注的是依赖项。 + +依赖项就是一个函数,且可以使用与*路径操作函数*相同的参数: + +```Python hl_lines="8-9" +{!../../../docs_src/dependencies/tutorial001.py!} +``` + +大功告成。 + +只用了**2 行**代码。 + +依赖项函数的形式和结构与*路径操作函数*一样。 + +因此,可以把依赖项当作没有「装饰器」(即,没有 `@app.get("/some-path")` )的路径操作函数。 + +依赖项可以返回各种内容。 + +本例中的依赖项预期接收如下参数: + +* 类型为 `str` 的可选查询参数 `q` +* 类型为 `int` 的可选查询参数 `skip`,默认值是 `0` +* 类型为 `int` 的可选查询参数 `limit`,默认值是 `100` + +然后,依赖项函数返回包含这些值的 `dict`。 + +### 导入 `Depends` + +```Python hl_lines="3" +{!../../../docs_src/dependencies/tutorial001.py!} +``` + +### 声明依赖项 + +与在*路径操作函数*参数中使用 `Body`、`Query` 的方式相同,声明依赖项需要使用 `Depends` 和一个新的参数: + +```Python hl_lines="13 18" +{!../../../docs_src/dependencies/tutorial001.py!} +``` + +虽然,在路径操作函数的参数中使用 `Depends` 的方式与 `Body`、`Query` 相同,但 `Depends` 的工作方式略有不同。 + +这里只能传给 Depends 一个参数。 + +且该参数必须是可调用对象,比如函数。 + +该函数接收的参数和*路径操作函数*的参数一样。 + +!!! tip "提示" + + 下一章介绍,除了函数还有哪些「对象」可以用作依赖项。 + +接收到新的请求时,**FastAPI** 执行如下操作: + +* 用正确的参数调用依赖项函数(「可依赖项」) +* 获取函数返回的结果 +* 把函数返回的结果赋值给*路径操作函数*的参数 + +```mermaid +graph TB + +common_parameters(["common_parameters"]) +read_items["/items/"] +read_users["/users/"] + +common_parameters --> read_items +common_parameters --> read_users +``` + +这样,只编写一次代码,**FastAPI** 就可以为多个*路径操作*共享这段代码 。 + +!!! check "检查" + + 注意,无需创建专门的类,并将之传递给 **FastAPI** 以进行「注册」或执行类似的操作。 + + 只要把它传递给 `Depends`,**FastAPI** 就知道该如何执行后续操作。 + +## 要不要使用 `async`? + +**FastAPI** 调用依赖项的方式与*路径操作函数*一样,因此,定义依赖项函数,也要应用与路径操作函数相同的规则。 + +即,既可以使用异步的 `async def`,也可以使用普通的 `def` 定义依赖项。 + +在普通的 `def` *路径操作函数*中,可以声明异步的 `async def` 依赖项;也可以在异步的 `async def` *路径操作函数*中声明普通的 `def` 依赖项。 + +上述这些操作都是可行的,**FastAPI** 知道该怎么处理。 + +!!! note "笔记" + + 如里不了解异步,请参阅[异步:*“着急了?”*](../../async.md){.internal-link target=_blank} 一章中 `async` 和 `await` 的内容。 + +## 与 OpenAPI 集成 + +依赖项及子依赖项的所有请求声明、验证和需求都可以集成至同一个 OpenAPI 概图。 + +所以,交互文档里也会显示依赖项的所有信息: + + + +## 简单用法 + +观察一下就会发现,只要*路径* 和*操作*匹配,就可以使用声明的路径操作函数。然后,**FastAPI** 会用正确的参数调用函数,并提取请求中的数据。 + +实际上,所有(或大多数)网络框架的工作方式都是这样的。 + +开发人员永远都不需要直接调用这些函数,这些函数是由框架(在此为 **FastAPI** )调用的。 + +通过依赖注入系统,只要告诉 **FastAPI** *路径操作函数* 还要「依赖」其他在*路径操作函数*之前执行的内容,**FastAPI** 就会执行函数代码,并「注入」函数返回的结果。 + +其他与「依赖注入」概念相同的术语为: + +* 资源(Resource) +* 提供方(Provider) +* 服务(Service) +* 可注入(Injectable) +* 组件(Component) + +## **FastAPI** 插件 + +**依赖注入**系统支持构建集成和「插件」。但实际上,FastAPI 根本**不需要创建「插件」**,因为使用依赖项可以声明不限数量的、可用于*路径操作函数*的集成与交互。 + +创建依赖项非常简单、直观,并且还支持导入 Python 包。毫不夸张地说,只要几行代码就可以把需要的 Python 包与 API 函数集成在一起。 + +下一章将详细介绍在关系型数据库、NoSQL 数据库、安全等方面使用依赖项的例子。 + +## **FastAPI** 兼容性 + +依赖注入系统如此简洁的特性,让 **FastAPI** 可以与下列系统兼容: + +* 关系型数据库 +* NoSQL 数据库 +* 外部支持库 +* 外部 API +* 认证和鉴权系统 +* API 使用监控系统 +* 响应数据注入系统 +* 等等…… + +## 简单而强大 + +虽然,**层级式依赖注入系统**的定义与使用十分简单,但它却非常强大。 + +比如,可以定义依赖其他依赖项的依赖项。 + +最后,依赖项层级树构建后,**依赖注入系统**会处理所有依赖项及其子依赖项,并为每一步操作提供(注入)结果。 + +比如,下面有 4 个 API 路径操作(*端点*): + +* `/items/public/` +* `/items/private/` +* `/users/{user_id}/activate` +* `/items/pro/` + +开发人员可以使用依赖项及其子依赖项为这些路径操作添加不同的权限: + +```mermaid +graph TB + +current_user(["current_user"]) +active_user(["active_user"]) +admin_user(["admin_user"]) +paying_user(["paying_user"]) + +public["/items/public/"] +private["/items/private/"] +activate_user["/users/{user_id}/activate"] +pro_items["/items/pro/"] + +current_user --> active_user +active_user --> admin_user +active_user --> paying_user + +current_user --> public +active_user --> private +admin_user --> activate_user +paying_user --> pro_items +``` + +## 与 **OpenAPI** 集成 + +在声明需求时,所有这些依赖项还会把参数、验证等功能添加至路径操作。 + +**FastAPI** 负责把上述内容全部添加到 OpenAPI 概图,并显示在交互文档中。 \ No newline at end of file diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 6fb6b191a..6a1ddb156 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -81,6 +81,7 @@ nav: - tutorial/handling-errors.md - tutorial/body-updates.md - 依赖项: + - tutorial/dependencies/index.md - tutorial/dependencies/global-dependencies.md - 安全性: - tutorial/security/index.md From 18daf8f301d5f0fdab28503f60a66886dd86a3b0 Mon Sep 17 00:00:00 2001 From: Urchin Date: Thu, 29 Jul 2021 23:22:43 +0300 Subject: [PATCH 150/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Russian=20translat?= =?UTF-8?q?ion=20for=20`docs/python-types.md`=20(#3039)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ru/docs/python-types.md | 314 +++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 docs/ru/docs/python-types.md diff --git a/docs/ru/docs/python-types.md b/docs/ru/docs/python-types.md new file mode 100644 index 000000000..99670363c --- /dev/null +++ b/docs/ru/docs/python-types.md @@ -0,0 +1,314 @@ +# Введение в аннотации типов Python + +Python имеет поддержку необязательных аннотаций типов. + +**Аннотации типов** являются специальным синтаксисом, который позволяет определять тип переменной. + +Объявление типов для переменных позволяет улучшить поддержку вашего кода редакторами и различными инструментами. + +Это просто **краткое руководство / напоминание** об аннотациях типов в Python. Оно охватывает только минимум, необходимый для их использования с **FastAPI**... что на самом деле очень мало. + +**FastAPI** целиком основан на аннотациях типов, у них много выгод и преимуществ. + +Но даже если вы никогда не используете **FastAPI**, вам будет полезно немного узнать о них. + +!!! note + Если вы являетесь экспертом в Python и уже знаете всё об аннотациях типов, переходите к следующему разделу. + +## Мотивация + +Давайте начнем с простого примера: + +```Python +{!../../../docs_src/python_types/tutorial001.py!} +``` + +Вызов этой программы выводит: + +``` +John Doe +``` + +Функция делает следующее: + +* Принимает `first_name` и `last_name`. +* Преобразует первую букву содержимого каждой переменной в верхний регистр с `title()`. +* Соединяет их через пробел. + +```Python hl_lines="2" +{!../../../docs_src/python_types/tutorial001.py!} +``` + +### Отредактируем пример + +Это очень простая программа. + +А теперь представьте, что вы пишете её с нуля. + +В какой-то момент вы бы начали определение функции, у вас были бы готовы параметры... + +Но затем вы должны вызвать «тот метод, который преобразует первую букву в верхний регистр». + +Было это `upper`? Или `uppercase`? `first_uppercase`? `capitalize`? + +Тогда вы попробуете с давним другом программиста: автодополнением редактора. + +Вы вводите первый параметр функции, `first_name`, затем точку (`.`), а затем нажимаете `Ctrl+Space`, чтобы запустить дополнение. + +Но, к сожалению, ничего полезного не выходит: + + + +### Добавим типы + +Давайте изменим одну строчку в предыдущей версии. + +Мы изменим именно этот фрагмент, параметры функции, с: + +```Python + first_name, last_name +``` + +на: + +```Python + first_name: str, last_name: str +``` + +Вот и все. + +Это аннотации типов: + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial002.py!} +``` + +Это не то же самое, что объявление значений по умолчанию, например: + +```Python + first_name="john", last_name="doe" +``` + +Это другая вещь. + +Мы используем двоеточия (`:`), а не равно (`=`). + +И добавление аннотаций типов обычно не меняет происходящего по сравнению с тем, что произошло бы без неё. + +Но теперь представьте, что вы снова находитесь в процессе создания этой функции, но уже с аннотациями типов. + +В тот же момент вы пытаетесь запустить автодополнение с помощью `Ctrl+Space` и вы видите: + + + +При этом вы можете просматривать варианты, пока не найдёте подходящий: + + + +## Больше мотивации + +Проверьте эту функцию, она уже имеет аннотации типов: + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial003.py!} +``` + +Поскольку редактор знает типы переменных, вы получаете не только дополнение, но и проверки ошибок: + + + +Теперь вы знаете, что вам нужно исправить, преобразовав `age` в строку с `str(age)`: + +```Python hl_lines="2" +{!../../../docs_src/python_types/tutorial004.py!} +``` + +## Объявление типов + +Вы только что видели основное место для объявления подсказок типов. В качестве параметров функции. + +Это также основное место, где вы можете использовать их с **FastAPI**. + +### Простые типы + +Вы можете объявить все стандартные типы Python, а не только `str`. + +Вы можете использовать, к примеру: + +* `int` +* `float` +* `bool` +* `bytes` + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial005.py!} +``` + +### Generic-типы с параметрами типов + +Существуют некоторые структуры данных, которые могут содержать другие значения, например, `dict`, `list`, `set` и `tuple`. И внутренние значения тоже могут иметь свой тип. + +Чтобы объявить эти типы и внутренние типы, вы можете использовать стандартный Python-модуль `typing`. + +Он существует специально для поддержки подсказок этих типов. + +#### `List` + +Например, давайте определим переменную как `list`, состоящий из `str`. + +Импортируйте `List` из `typing` (с заглавной `L`): + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial006.py!} +``` + +Объявите переменную с тем же синтаксисом двоеточия (`:`). + +В качестве типа укажите `List`. + +Поскольку список является типом, содержащим некоторые внутренние типы, вы помещаете их в квадратные скобки: + +```Python hl_lines="4" +{!../../../docs_src/python_types/tutorial006.py!} +``` + +!!! tip + Эти внутренние типы в квадратных скобках называются «параметрами типов». + + В этом случае `str` является параметром типа, передаваемым в `List`. + +Это означает: "переменная `items` является `list`, и каждый из элементов этого списка является `str`". + +Если вы будете так поступать, редактор может оказывать поддержку даже при обработке элементов списка: + + + +Без типов добиться этого практически невозможно. + +Обратите внимание, что переменная `item` является одним из элементов списка `items`. + +И все же редактор знает, что это `str`, и поддерживает это. + +#### `Tuple` и `Set` + +Вы бы сделали то же самое, чтобы объявить `tuple` и `set`: + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial007.py!} +``` + +Это означает: + +* Переменная `items_t` является `tuple` с 3 элементами: `int`, другим `int` и `str`. +* Переменная `items_s` является `set` и каждый элемент имеет тип `bytes`. + +#### `Dict` + +Чтобы определить `dict`, вы передаёте 2 параметра типов, разделённых запятыми. + +Первый параметр типа предназначен для ключей `dict`. + +Второй параметр типа предназначен для значений `dict`: + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial008.py!} +``` + +Это означает: + +* Переменная `prices` является `dict`: + * Ключи этого `dict` имеют тип `str` (скажем, название каждого элемента). + * Значения этого `dict` имеют тип `float` (скажем, цена каждой позиции). + +#### `Optional` + +Вы также можете использовать `Optional`, чтобы объявить, что переменная имеет тип, например, `str`, но это является «необязательным», что означает, что она также может быть `None`: + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial009.py!} +``` + +Использование `Optional[str]` вместо просто `str` позволит редактору помочь вам в обнаружении ошибок, в которых вы могли бы предположить, что значение всегда является `str`, хотя на самом деле это может быть и `None`. + +#### Generic-типы + +Эти типы принимают параметры в квадратных скобках: + +* `List` +* `Tuple` +* `Set` +* `Dict` +* `Optional` +* ...и др. + +называются **Generic-типами** или **Generics**. + +### Классы как типы + +Вы также можете объявить класс как тип переменной. + +Допустим, у вас есть класс `Person` с полем `name`: + +```Python hl_lines="1-3" +{!../../../docs_src/python_types/tutorial010.py!} +``` + +Тогда вы можете объявить переменную типа `Person`: + +```Python hl_lines="6" +{!../../../docs_src/python_types/tutorial010.py!} +``` + +И снова вы получаете полную поддержку редактора: + + + +## Pydantic-модели + +Pydantic является Python-библиотекой для выполнения валидации данных. + +Вы объявляете «форму» данных как классы с атрибутами. + +И каждый атрибут имеет тип. + +Затем вы создаете экземпляр этого класса с некоторыми значениями, и он проверяет значения, преобразует их в соответствующий тип (если все верно) и предоставляет вам объект со всеми данными. + +И вы получаете полную поддержку редактора для этого итогового объекта. + +Взято из официальной документации Pydantic: + +```Python +{!../../../docs_src/python_types/tutorial011.py!} +``` + +!!! info + Чтобы узнать больше о Pydantic, читайте его документацию. + +**FastAPI** целиком основан на Pydantic. + +Вы увидите намного больше всего этого на практике в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}. + +## Аннотации типов в **FastAPI** + +**FastAPI** получает преимущества аннотаций типов для выполнения определённых задач. + +С **FastAPI** вы объявляете параметры с аннотациями типов и получаете: + +* **Поддержку редактора**. +* **Проверки типов**. + +...и **FastAPI** использует тот же механизм для: + +* **Определения требований**: из параметров пути запроса, параметров запроса, заголовков, зависимостей и т.д. +* **Преобразования данных**: от запроса к нужному типу. +* **Валидации данных**: исходя из каждого запроса: + * Генерации **автоматических ошибок**, возвращаемых клиенту, когда данные не являются корректными. +* **Документирования** API с использованием OpenAPI: + * который затем используется пользовательскими интерфейсами автоматической интерактивной документации. + +Всё это может показаться абстрактным. Не волнуйтесь. Вы увидите всё это в действии в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}. + +Важно то, что при использовании стандартных типов Python в одном месте (вместо добавления дополнительных классов, декораторов и т.д.) **FastAPI** сделает за вас большую часть работы. + +!!! info + Если вы уже прошли всё руководство и вернулись, чтобы узнать больше о типах, хорошим ресурсом является «шпаргалка» от `mypy`. From 4093d9b22a2b196ddd53679a5bb8ec1e863ba0dc Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 20:23:19 +0000 Subject: [PATCH 151/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ae9940d76..9e25e9e39 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Russian translation for `docs/external-links.md`. PR [#3036](https://github.com/tiangolo/fastapi/pull/3036) by [@dukkee](https://github.com/dukkee). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/global-dependencies.md`. PR [#3493](https://github.com/tiangolo/fastapi/pull/3493) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Portuguese translation for `docs/deployment/versions.md`. PR [#3618](https://github.com/tiangolo/fastapi/pull/3618) by [@lsglucas](https://github.com/lsglucas). ### Features From 6a22b75afd5076365ada08737b183260f03d04b7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 20:25:17 +0000 Subject: [PATCH 152/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9e25e9e39..ce39ef2f0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for `docs/tutorial/dependencies/index.md`. PR [#3489](https://github.com/tiangolo/fastapi/pull/3489) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Russian translation for `docs/external-links.md`. PR [#3036](https://github.com/tiangolo/fastapi/pull/3036) by [@dukkee](https://github.com/dukkee). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/global-dependencies.md`. PR [#3493](https://github.com/tiangolo/fastapi/pull/3493) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Portuguese translation for `docs/deployment/versions.md`. PR [#3618](https://github.com/tiangolo/fastapi/pull/3618) by [@lsglucas](https://github.com/lsglucas). From e726b7b77133d9bc43891ca51ef2c83d8b02aab4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 20:28:25 +0000 Subject: [PATCH 153/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ce39ef2f0..2e6536f7f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Russian translation for `docs/python-types.md`. PR [#3039](https://github.com/tiangolo/fastapi/pull/3039) by [@dukkee](https://github.com/dukkee). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/index.md`. PR [#3489](https://github.com/tiangolo/fastapi/pull/3489) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Russian translation for `docs/external-links.md`. PR [#3036](https://github.com/tiangolo/fastapi/pull/3036) by [@dukkee](https://github.com/dukkee). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/global-dependencies.md`. PR [#3493](https://github.com/tiangolo/fastapi/pull/3493) by [@jaystone776](https://github.com/jaystone776). From 97fa743ecb5a716fa0223a7463cb83f3f0df494c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 29 Jul 2021 22:59:26 +0200 Subject: [PATCH 154/814] =?UTF-8?q?=E2=9C=A8=20Update=20OpenAPI=20models,?= =?UTF-8?q?=20supporting=20recursive=20models=20and=20extensions=20(#3628)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/openapi/models.py | 117 +++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 34 deletions(-) diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 4f55aa001..361c75005 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -30,11 +30,17 @@ class Contact(BaseModel): url: Optional[AnyUrl] = None email: Optional[EmailStr] = None + class Config: + extra = "allow" + class License(BaseModel): name: str url: Optional[AnyUrl] = None + class Config: + extra = "allow" + class Info(BaseModel): title: str @@ -44,18 +50,27 @@ class Info(BaseModel): license: Optional[License] = None version: str + class Config: + extra = "allow" + class ServerVariable(BaseModel): enum: Optional[List[str]] = None default: str description: Optional[str] = None + class Config: + extra = "allow" + class Server(BaseModel): url: Union[AnyUrl, str] description: Optional[str] = None variables: Optional[Dict[str, ServerVariable]] = None + class Config: + extra = "allow" + class Reference(BaseModel): ref: str = Field(..., alias="$ref") @@ -73,13 +88,19 @@ class XML(BaseModel): attribute: Optional[bool] = None wrapped: Optional[bool] = None + class Config: + extra = "allow" + class ExternalDocumentation(BaseModel): description: Optional[str] = None url: AnyUrl + class Config: + extra = "allow" -class SchemaBase(BaseModel): + +class Schema(BaseModel): ref: Optional[str] = Field(None, alias="$ref") title: Optional[str] = None multipleOf: Optional[float] = None @@ -98,13 +119,13 @@ class SchemaBase(BaseModel): required: Optional[List[str]] = None enum: Optional[List[Any]] = None type: Optional[str] = None - allOf: Optional[List[Any]] = None - oneOf: Optional[List[Any]] = None - anyOf: Optional[List[Any]] = None - not_: Optional[Any] = Field(None, alias="not") - items: Optional[Any] = None - properties: Optional[Dict[str, Any]] = None - additionalProperties: Optional[Union[Dict[str, Any], bool]] = None + allOf: Optional[List["Schema"]] = None + oneOf: Optional[List["Schema"]] = None + anyOf: Optional[List["Schema"]] = None + not_: Optional["Schema"] = Field(None, alias="not") + items: Optional["Schema"] = None + properties: Optional[Dict[str, "Schema"]] = None + additionalProperties: Optional[Union["Schema", Reference, bool]] = None description: Optional[str] = None format: Optional[str] = None default: Optional[Any] = None @@ -121,22 +142,15 @@ class SchemaBase(BaseModel): extra: str = "allow" -class Schema(SchemaBase): - allOf: Optional[List[SchemaBase]] = None - oneOf: Optional[List[SchemaBase]] = None - anyOf: Optional[List[SchemaBase]] = None - not_: Optional[SchemaBase] = Field(None, alias="not") - items: Optional[SchemaBase] = None - properties: Optional[Dict[str, SchemaBase]] = None - additionalProperties: Optional[Union[Dict[str, Any], bool]] = None - - class Example(BaseModel): summary: Optional[str] = None description: Optional[str] = None value: Optional[Any] = None externalValue: Optional[AnyUrl] = None + class Config: + extra = "allow" + class ParameterInType(Enum): query = "query" @@ -147,12 +161,14 @@ class ParameterInType(Enum): class Encoding(BaseModel): contentType: Optional[str] = None - # Workaround OpenAPI recursive reference, using Any - headers: Optional[Dict[str, Union[Any, Reference]]] = None + headers: Optional[Dict[str, Union["Header", Reference]]] = None style: Optional[str] = None explode: Optional[bool] = None allowReserved: Optional[bool] = None + class Config: + extra = "allow" + class MediaType(BaseModel): schema_: Optional[Union[Schema, Reference]] = Field(None, alias="schema") @@ -160,6 +176,9 @@ class MediaType(BaseModel): examples: Optional[Dict[str, Union[Example, Reference]]] = None encoding: Optional[Dict[str, Encoding]] = None + class Config: + extra = "allow" + class ParameterBase(BaseModel): description: Optional[str] = None @@ -175,6 +194,9 @@ class ParameterBase(BaseModel): # Serialization rules for more complex scenarios content: Optional[Dict[str, MediaType]] = None + class Config: + extra = "allow" + class Parameter(ParameterBase): name: str @@ -185,16 +207,14 @@ class Header(ParameterBase): pass -# Workaround OpenAPI recursive reference -class EncodingWithHeaders(Encoding): - headers: Optional[Dict[str, Union[Header, Reference]]] = None - - class RequestBody(BaseModel): description: Optional[str] = None content: Dict[str, MediaType] required: Optional[bool] = None + class Config: + extra = "allow" + class Link(BaseModel): operationRef: Optional[str] = None @@ -204,6 +224,9 @@ class Link(BaseModel): description: Optional[str] = None server: Optional[Server] = None + class Config: + extra = "allow" + class Response(BaseModel): description: str @@ -211,6 +234,9 @@ class Response(BaseModel): content: Optional[Dict[str, MediaType]] = None links: Optional[Dict[str, Union[Link, Reference]]] = None + class Config: + extra = "allow" + class Operation(BaseModel): tags: Optional[List[str]] = None @@ -220,9 +246,9 @@ class Operation(BaseModel): operationId: Optional[str] = None parameters: Optional[List[Union[Parameter, Reference]]] = None requestBody: Optional[Union[RequestBody, Reference]] = None - responses: Dict[str, Response] - # Workaround OpenAPI recursive reference - callbacks: Optional[Dict[str, Union[Dict[str, Any], Reference]]] = None + # Using Any for Specification Extensions + responses: Dict[str, Union[Response, Any]] + callbacks: Optional[Dict[str, Union[Dict[str, "PathItem"], Reference]]] = None deprecated: Optional[bool] = None security: Optional[List[Dict[str, List[str]]]] = None servers: Optional[List[Server]] = None @@ -246,10 +272,8 @@ class PathItem(BaseModel): servers: Optional[List[Server]] = None parameters: Optional[List[Union[Parameter, Reference]]] = None - -# Workaround OpenAPI recursive reference -class OperationWithCallbacks(BaseModel): - callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference]]] = None + class Config: + extra = "allow" class SecuritySchemeType(Enum): @@ -263,6 +287,9 @@ class SecurityBase(BaseModel): type_: SecuritySchemeType = Field(..., alias="type") description: Optional[str] = None + class Config: + extra = "allow" + class APIKeyIn(Enum): query = "query" @@ -290,6 +317,9 @@ class OAuthFlow(BaseModel): refreshUrl: Optional[str] = None scopes: Dict[str, str] = {} + class Config: + extra = "allow" + class OAuthFlowImplicit(OAuthFlow): authorizationUrl: str @@ -314,6 +344,9 @@ class OAuthFlows(BaseModel): clientCredentials: Optional[OAuthFlowClientCredentials] = None authorizationCode: Optional[OAuthFlowAuthorizationCode] = None + class Config: + extra = "allow" + class OAuth2(SecurityBase): type_ = Field(SecuritySchemeType.oauth2, alias="type") @@ -337,7 +370,11 @@ class Components(BaseModel): headers: Optional[Dict[str, Union[Header, Reference]]] = None securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None links: Optional[Dict[str, Union[Link, Reference]]] = None - callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference]]] = None + # Using Any for Specification Extensions + callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None + + class Config: + extra = "allow" class Tag(BaseModel): @@ -345,13 +382,25 @@ class Tag(BaseModel): description: Optional[str] = None externalDocs: Optional[ExternalDocumentation] = None + class Config: + extra = "allow" + class OpenAPI(BaseModel): openapi: str info: Info servers: Optional[List[Server]] = None - paths: Dict[str, PathItem] + # Using Any for Specification Extensions + paths: Dict[str, Union[PathItem, Any]] components: Optional[Components] = None security: Optional[List[Dict[str, List[str]]]] = None tags: Optional[List[Tag]] = None externalDocs: Optional[ExternalDocumentation] = None + + class Config: + extra = "allow" + + +Schema.update_forward_refs() +Operation.update_forward_refs() +Encoding.update_forward_refs() From 3788ca46401e7dd73f52f419cc5ebcfe2dbb2f5c Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 29 Jul 2021 21:00:53 +0000 Subject: [PATCH 155/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2e6536f7f..ae4568733 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Update OpenAPI models, supporting recursive models and extensions. PR [#3628](https://github.com/tiangolo/fastapi/pull/3628) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Russian translation for `docs/python-types.md`. PR [#3039](https://github.com/tiangolo/fastapi/pull/3039) by [@dukkee](https://github.com/dukkee). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/index.md`. PR [#3489](https://github.com/tiangolo/fastapi/pull/3489) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Russian translation for `docs/external-links.md`. PR [#3036](https://github.com/tiangolo/fastapi/pull/3036) by [@dukkee](https://github.com/dukkee). From eba2c66532472def5ad141f986899c27e277bb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 29 Jul 2021 23:02:42 +0200 Subject: [PATCH 156/814] =?UTF-8?q?=F0=9F=94=96=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ae4568733..a4aa3d1db 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,17 +2,12 @@ ## Latest Changes -* ✨ Update OpenAPI models, supporting recursive models and extensions. PR [#3628](https://github.com/tiangolo/fastapi/pull/3628) by [@tiangolo](https://github.com/tiangolo). -* 🌐 Add Russian translation for `docs/python-types.md`. PR [#3039](https://github.com/tiangolo/fastapi/pull/3039) by [@dukkee](https://github.com/dukkee). -* 🌐 Add Chinese translation for `docs/tutorial/dependencies/index.md`. PR [#3489](https://github.com/tiangolo/fastapi/pull/3489) by [@jaystone776](https://github.com/jaystone776). -* 🌐 Add Russian translation for `docs/external-links.md`. PR [#3036](https://github.com/tiangolo/fastapi/pull/3036) by [@dukkee](https://github.com/dukkee). -* 🌐 Add Chinese translation for `docs/tutorial/dependencies/global-dependencies.md`. PR [#3493](https://github.com/tiangolo/fastapi/pull/3493) by [@jaystone776](https://github.com/jaystone776). -* 🌐 Add Portuguese translation for `docs/deployment/versions.md`. PR [#3618](https://github.com/tiangolo/fastapi/pull/3618) by [@lsglucas](https://github.com/lsglucas). ### Features * ✨ Add support for extensions and updates to the OpenAPI schema in each *path operation*. New docs: [FastAPI Path Operation Advanced Configuration - OpenAPI Extra](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#openapi-extra). Initial PR [#1922](https://github.com/tiangolo/fastapi/pull/1922) by [@edouardlp](https://github.com/edouardlp). * ✨ Add additonal OpenAPI metadata parameters to `FastAPI` class, shown on the automatic API docs UI. New docs: [Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/). Initial PR [#1812](https://github.com/tiangolo/fastapi/pull/1812) by [@dkreeft](https://github.com/dkreeft). * ✨ Add `description` parameter to all the security scheme classes, e.g. `APIKeyQuery(name="key", description="A very cool API key")`. PR [#1757](https://github.com/tiangolo/fastapi/pull/1757) by [@hylkepostma](https://github.com/hylkepostma). +* ✨ Update OpenAPI models, supporting recursive models and extensions. PR [#3628](https://github.com/tiangolo/fastapi/pull/3628) by [@tiangolo](https://github.com/tiangolo). * ✨ Import and re-export data structures from Starlette, used by Request properties, on `fastapi.datastructures`. Initial PR [#1872](https://github.com/tiangolo/fastapi/pull/1872) by [@jamescurtin](https://github.com/jamescurtin). ### Docs @@ -21,6 +16,11 @@ ### Translations +* 🌐 Add Russian translation for `docs/python-types.md`. PR [#3039](https://github.com/tiangolo/fastapi/pull/3039) by [@dukkee](https://github.com/dukkee). +* 🌐 Add Chinese translation for `docs/tutorial/dependencies/index.md`. PR [#3489](https://github.com/tiangolo/fastapi/pull/3489) by [@jaystone776](https://github.com/jaystone776). +* 🌐 Add Russian translation for `docs/external-links.md`. PR [#3036](https://github.com/tiangolo/fastapi/pull/3036) by [@dukkee](https://github.com/dukkee). +* 🌐 Add Chinese translation for `docs/tutorial/dependencies/global-dependencies.md`. PR [#3493](https://github.com/tiangolo/fastapi/pull/3493) by [@jaystone776](https://github.com/jaystone776). +* 🌐 Add Portuguese translation for `docs/deployment/versions.md`. PR [#3618](https://github.com/tiangolo/fastapi/pull/3618) by [@lsglucas](https://github.com/lsglucas). * 🌐 Add Japanese translation for `docs/tutorial/security/oauth2-jwt.md`. PR [#3526](https://github.com/tiangolo/fastapi/pull/3526) by [@sattosan](https://github.com/sattosan). ### Internal From 717a1ec40992d00e34635f0b4c9b68ab5a6daef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 29 Jul 2021 23:03:57 +0200 Subject: [PATCH 157/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.68?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a4aa3d1db..ef29e9f23 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.68.0 + ### Features * ✨ Add support for extensions and updates to the OpenAPI schema in each *path operation*. New docs: [FastAPI Path Operation Advanced Configuration - OpenAPI Extra](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#openapi-extra). Initial PR [#1922](https://github.com/tiangolo/fastapi/pull/1922) by [@edouardlp](https://github.com/edouardlp). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 61737d47f..60f90b80d 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.67.0" +__version__ = "0.68.0" from starlette import status as status From e809bdc1709d9e05e156942ad766b5c67ea472f2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Aug 2021 15:42:02 +0200 Subject: [PATCH 158/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#3642)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/people.yml | 259 ++++++++++++++++++++++++---------------- 1 file changed, 153 insertions(+), 106 deletions(-) diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 6356a5073..3509ce152 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,12 +1,12 @@ maintainers: - login: tiangolo - answers: 1225 - prs: 232 + answers: 1229 + prs: 247 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=05f95ca7fdead36edd9c86be46b4ef6c3c71f876&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 267 + count: 273 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: dmontagu @@ -18,7 +18,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: Mause - count: 182 + count: 196 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause - login: euri10 @@ -30,11 +30,11 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 - login: ArcLightSlavik - count: 64 + count: 66 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik - login: falkben - count: 56 + count: 57 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 url: https://github.com/falkben - login: raphaelauv @@ -58,7 +58,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 url: https://github.com/Dustyposa - login: krishnardt - count: 30 + count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 url: https://github.com/krishnardt - login: insomnes @@ -78,7 +78,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak - login: chbndrhnns - count: 22 + count: 23 avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 url: https://github.com/chbndrhnns - login: acnebs @@ -114,13 +114,17 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4 url: https://github.com/nkhitrov - login: waynerv - count: 15 + count: 16 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 url: https://github.com/waynerv - login: haizaar count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar +- login: panla + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla - login: acidjunk count: 11 avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 @@ -129,6 +133,10 @@ experts: count: 11 avatarUrl: https://avatars.githubusercontent.com/u/40475662?u=e58ef61034e8d0d6a312cc956fb09b9c3332b449&v=4 url: https://github.com/zamiramir +- login: David-Lor + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4 + url: https://github.com/David-Lor - login: juntatalor count: 11 avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4 @@ -145,39 +153,43 @@ experts: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4 url: https://github.com/stefanondisponibile +- login: adriangb + count: 10 + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 + url: https://github.com/adriangb last_month_active: -- login: Kludex - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 - url: https://github.com/Kludex -- login: frankie567 - count: 9 - avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=72adf1cb1d29787305c99700d669561952cea0af&v=4 - url: https://github.com/frankie567 - login: Mause - count: 6 + count: 14 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause -- login: ArcLightSlavik - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 - url: https://github.com/ArcLightSlavik -- login: gyKa - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/1000842?v=4 - url: https://github.com/gyKa -- login: ricky-sb +- login: panla + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla +- login: Kludex + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + url: https://github.com/Kludex +- login: adriangb count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/10700079?v=4 - url: https://github.com/ricky-sb -- login: captainCapitalism + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 + url: https://github.com/adriangb +- login: rotten count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/32553875?v=4 - url: https://github.com/captainCapitalism -- login: acidjunk + avatarUrl: https://avatars.githubusercontent.com/u/717719?v=4 + url: https://github.com/rotten +- login: STeveShary count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 - url: https://github.com/acidjunk + avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 + url: https://github.com/STeveShary +- login: uricholiveira + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/48108280?u=347abd073ff99d18f8e3582db11fd7b7a297598c&v=4 + url: https://github.com/uricholiveira +- login: AlexanderPodorov + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/54511144?v=4 + url: https://github.com/AlexanderPodorov top_contributors: - login: waynerv count: 25 @@ -196,9 +208,13 @@ top_contributors: avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4 url: https://github.com/euri10 - login: mariacamilagl - count: 9 + count: 12 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 url: https://github.com/mariacamilagl +- login: jaystone776 + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 + url: https://github.com/jaystone776 - login: RunningIkkyu count: 7 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 @@ -215,6 +231,10 @@ top_contributors: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes +- login: Kludex + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + url: https://github.com/Kludex - login: SwftAlpc count: 5 avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4 @@ -225,11 +245,15 @@ top_contributors: url: https://github.com/Attsun1031 - login: jekirl count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/2546697?v=4 + avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4 url: https://github.com/jekirl +- login: jfunez + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/805749?v=4 + url: https://github.com/jfunez - login: komtaki count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=5a44657c0544111ee3c132d9bb9951c2804f7969&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki - login: Smlep count: 4 @@ -237,25 +261,25 @@ top_contributors: url: https://github.com/Smlep top_reviewers: - login: Kludex - count: 80 + count: 83 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex -- login: tokusumi - count: 44 - avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 - url: https://github.com/tokusumi - login: Laineyzhang55 - count: 42 + count: 47 avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4 url: https://github.com/Laineyzhang55 +- login: tokusumi + count: 46 + avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 + url: https://github.com/tokusumi +- login: waynerv + count: 43 + avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 + url: https://github.com/waynerv - login: ycd count: 41 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd -- login: waynerv - count: 38 - avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 - url: https://github.com/waynerv - login: AdrianDeAnda count: 28 avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4 @@ -266,14 +290,14 @@ top_reviewers: url: https://github.com/dmontagu - login: komtaki count: 21 - avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=5a44657c0544111ee3c132d9bb9951c2804f7969&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki - login: ArcLightSlavik count: 20 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik - login: cassiobotaro - count: 16 + count: 18 avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 url: https://github.com/cassiobotaro - login: yanever @@ -292,18 +316,22 @@ top_reviewers: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4 url: https://github.com/delhi09 +- login: lsglucas + count: 13 + avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 + url: https://github.com/lsglucas - login: RunningIkkyu count: 12 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 url: https://github.com/RunningIkkyu +- login: sh0nk + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4 + url: https://github.com/sh0nk - login: hard-coders count: 12 avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 url: https://github.com/hard-coders -- login: sh0nk - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4 - url: https://github.com/sh0nk - login: mariacamilagl count: 10 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 @@ -316,6 +344,14 @@ top_reviewers: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4 url: https://github.com/maoyibo +- login: rjNemo + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 + url: https://github.com/rjNemo +- login: Smlep + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 + url: https://github.com/Smlep - login: PandaHun count: 9 avatarUrl: https://avatars.githubusercontent.com/u/13096845?u=646eba44db720e37d0dbe8e98e77ab534ea78a20&v=4 @@ -324,14 +360,6 @@ top_reviewers: count: 9 avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4 url: https://github.com/bezaca -- login: lsglucas - count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 - url: https://github.com/lsglucas -- login: rjNemo - count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 - url: https://github.com/rjNemo - login: blt232018 count: 8 avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4 @@ -348,22 +376,22 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv +- login: graingert + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4 + url: https://github.com/graingert - login: NastasiaSaby count: 7 avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4 url: https://github.com/NastasiaSaby -- login: Smlep +- login: Mause count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 - url: https://github.com/Smlep + avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 + url: https://github.com/Mause - login: jovicon count: 6 avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 url: https://github.com/jovicon -- login: Mause - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 - url: https://github.com/Mause - login: nimctl count: 5 avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4 @@ -376,10 +404,22 @@ top_reviewers: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/63564282?u=0078826509dbecb2fdb543f4e881c9cd06157893&v=4 url: https://github.com/SnkSynthesis +- login: solomein-sv + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 + url: https://github.com/solomein-sv - login: anthonycepeda count: 5 avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 url: https://github.com/anthonycepeda +- login: ComicShrimp + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 + url: https://github.com/ComicShrimp +- login: oandersonmagalhaes + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/83456692?v=4 + url: https://github.com/oandersonmagalhaes - login: euri10 count: 4 avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4 @@ -392,6 +432,10 @@ top_reviewers: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/41201924?u=6883cc4fc13a7b2e60d4deddd4be06f9c5287880&v=4 url: https://github.com/aviramha +- login: Cajuteq + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/26676532?u=8ee0422981810e51480855de1c0d67b6b79cd3f2&v=4 + url: https://github.com/Cajuteq - login: Zxilly count: 4 avatarUrl: https://avatars.githubusercontent.com/u/31370133?v=4 @@ -407,9 +451,6 @@ sponsors_50: - login: wdwinslow avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 url: https://github.com/wdwinslow -- login: bingwu-chime - avatarUrl: https://avatars.githubusercontent.com/u/67026650?u=603a6b345f25c20c6706a8a6c7f71ae688d649a5&v=4 - url: https://github.com/bingwu-chime sponsors: - login: kamalgill avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4 @@ -423,9 +464,6 @@ sponsors: - login: jmaralc avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4 url: https://github.com/jmaralc -- login: psgandalf - avatarUrl: https://avatars.githubusercontent.com/u/8134158?v=4 - url: https://github.com/psgandalf - login: samuelcolvin avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4 url: https://github.com/samuelcolvin @@ -477,17 +515,17 @@ sponsors: - login: peterHoburg avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4 url: https://github.com/peterHoburg +- login: CINOAdam + avatarUrl: https://avatars.githubusercontent.com/u/4728508?u=34c3d58cb900fed475d0172b436c66a94ad739ed&v=4 + url: https://github.com/CINOAdam - login: dudil avatarUrl: https://avatars.githubusercontent.com/u/4785835?u=58b7ea39123e0507f3b2996448a27256b16fd697&v=4 url: https://github.com/dudil - login: ennui93 avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4 url: https://github.com/ennui93 -- login: sco1 - avatarUrl: https://avatars.githubusercontent.com/u/5323929?u=2b8434060d0c9d93de80a2a945baed94a412c31e&v=4 - url: https://github.com/sco1 - login: MacroPower - avatarUrl: https://avatars.githubusercontent.com/u/5648814?u=b2730000c9f9a471282b9849d2cc85711d7973d4&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/5648814?u=e13991efd1e03c44c911f919872e750530ded633&v=4 url: https://github.com/MacroPower - login: ginomempin avatarUrl: https://avatars.githubusercontent.com/u/6091865?v=4 @@ -525,9 +563,9 @@ sponsors: - login: ronaldnwilliams avatarUrl: https://avatars.githubusercontent.com/u/13632749?u=ac41a086d0728bf66a9d2bee9e5e377041ff44a4&v=4 url: https://github.com/ronaldnwilliams -- login: uselessscat - avatarUrl: https://avatars.githubusercontent.com/u/15332878?u=8485a1b7383c274b28f383370ee2d5f9a6cd423b&v=4 - url: https://github.com/uselessscat +- login: pablonnaoji + avatarUrl: https://avatars.githubusercontent.com/u/15187159?u=afc15bd5a4ba9c5c7206bbb1bcaeef606a0932e0&v=4 + url: https://github.com/pablonnaoji - login: natenka avatarUrl: https://avatars.githubusercontent.com/u/15850513?u=00d1083c980d0b4ce32835dc07eee7f43f34fd2f&v=4 url: https://github.com/natenka @@ -573,9 +611,6 @@ sponsors: - login: mauroalejandrojm avatarUrl: https://avatars.githubusercontent.com/u/31569442?u=cdada990a1527926a36e95f62c30a8b48bbc49a1&v=4 url: https://github.com/mauroalejandrojm -- login: public-daniel - avatarUrl: https://avatars.githubusercontent.com/u/32238294?u=0377e38dd023395c9643d5388b4e9489a24b4d34&v=4 - url: https://github.com/public-daniel - login: ybressler avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=6621dc9ab53b697912ab2a32211bb29ae90a9112&v=4 url: https://github.com/ybressler @@ -597,6 +632,9 @@ sponsors: - login: anthonycepeda avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 url: https://github.com/anthonycepeda +- login: an-tho-ny + avatarUrl: https://avatars.githubusercontent.com/u/74874159?v=4 + url: https://github.com/an-tho-ny - login: linux-china avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4 url: https://github.com/linux-china @@ -609,6 +647,9 @@ sponsors: - login: jmagnusson avatarUrl: https://avatars.githubusercontent.com/u/190835?v=4 url: https://github.com/jmagnusson +- login: sakti + avatarUrl: https://avatars.githubusercontent.com/u/196178?u=0110be74c4270244546f1b610334042cd16bb8ad&v=4 + url: https://github.com/sakti - login: slafs avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4 url: https://github.com/slafs @@ -627,18 +668,21 @@ sponsors: - login: rinckd avatarUrl: https://avatars.githubusercontent.com/u/546002?u=1fcc7e664dc86524a0af6837a0c222829c3fd4e5&v=4 url: https://github.com/rinckd +- login: hardbyte + avatarUrl: https://avatars.githubusercontent.com/u/855189?u=aa29e92f34708814d6b67fcd47ca4cf2ce1c04ed&v=4 + url: https://github.com/hardbyte - login: Pytlicek avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=169dba3bfbc04ed214a914640ff435969f19ddb3&v=4 url: https://github.com/Pytlicek - login: okken avatarUrl: https://avatars.githubusercontent.com/u/1568356?u=0a991a21bdc62e2bea9ad311652f2c45f453dc84&v=4 url: https://github.com/okken -- login: leogregianin - avatarUrl: https://avatars.githubusercontent.com/u/1684053?u=94ddd387601bd1805034dbe83e6eba0491c15323&v=4 - url: https://github.com/leogregianin - login: cbonoz avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4 url: https://github.com/cbonoz +- login: Abbe98 + avatarUrl: https://avatars.githubusercontent.com/u/2631719?u=8a064aba9a710229ad28c616549d81a24191a5df&v=4 + url: https://github.com/Abbe98 - login: rglsk avatarUrl: https://avatars.githubusercontent.com/u/2768101?u=e349c88673f2155fe021331377c656a9d74bcc25&v=4 url: https://github.com/rglsk @@ -651,6 +695,9 @@ sponsors: - login: igorcorrea avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4 url: https://github.com/igorcorrea +- login: anthcor + avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4 + url: https://github.com/anthcor - login: zsinx6 avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4 url: https://github.com/zsinx6 @@ -702,18 +749,15 @@ sponsors: - login: iPr0ger avatarUrl: https://avatars.githubusercontent.com/u/19322290?v=4 url: https://github.com/iPr0ger -- login: sadikkuzu - avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4 - url: https://github.com/sadikkuzu - login: ghandic avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 url: https://github.com/ghandic - login: MoronVV avatarUrl: https://avatars.githubusercontent.com/u/24293616?v=4 url: https://github.com/MoronVV -- login: AngusWG - avatarUrl: https://avatars.githubusercontent.com/u/26385612?u=f4d4c8bd2097cdd58eb9e385932b83c78777f3c0&v=4 - url: https://github.com/AngusWG +- login: fstau + avatarUrl: https://avatars.githubusercontent.com/u/24669867?u=60e7c8c09f8dafabee8fc3edcd6f9e19abbff918&v=4 + url: https://github.com/fstau - login: mertguvencli avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4 url: https://github.com/mertguvencli @@ -723,9 +767,6 @@ sponsors: - login: askurihin avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4 url: https://github.com/askurihin -- login: berrysauce - avatarUrl: https://avatars.githubusercontent.com/u/38889179?u=758ed15a5be8bbd03855f5a74f42c19f7946ee32&v=4 - url: https://github.com/berrysauce - login: JitPackJoyride avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=9638bfeacfa5940358188f8205ce662bba022b53&v=4 url: https://github.com/JitPackJoyride @@ -735,18 +776,24 @@ sponsors: - login: ilias-ant avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4 url: https://github.com/ilias-ant -- login: kbhatiya999 - avatarUrl: https://avatars.githubusercontent.com/u/47816034?v=4 - url: https://github.com/kbhatiya999 +- login: arrrrrmin + avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=05600727f1cfe75f440bb3fddd49bfea84b1e894&v=4 + url: https://github.com/arrrrrmin - login: akanz1 avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4 url: https://github.com/akanz1 -- login: rychardvale - avatarUrl: https://avatars.githubusercontent.com/u/54805553?u=3d20ab05301d05f9ac3500fb79a2bfee3842b753&v=4 - url: https://github.com/rychardvale - login: athemeart avatarUrl: https://avatars.githubusercontent.com/u/61623624?v=4 url: https://github.com/athemeart -- login: Rhythmicc - avatarUrl: https://avatars.githubusercontent.com/u/29839231?u=2100781089a259707c475c4547bd7995b0fc18ee&v=4 - url: https://github.com/Rhythmicc +- login: sadikkuzu + avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4 + url: https://github.com/sadikkuzu +- login: gabrielmbmb + avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=92084ed7242160dee4d20aece923a10c59758ee5&v=4 + url: https://github.com/gabrielmbmb +- login: pixel365 + avatarUrl: https://avatars.githubusercontent.com/u/53819609?u=9e0309c5420ec4624aececd3ca2d7105f7f68133&v=4 + url: https://github.com/pixel365 +- login: amjed-ali-k + avatarUrl: https://avatars.githubusercontent.com/u/86785660?u=8713ba29ed451d3469f303a9eb8f164488d47500&v=4 + url: https://github.com/amjed-ali-k From e9ba01dc59da2c9165d788b1ee83319a90381d26 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 2 Aug 2021 13:42:35 +0000 Subject: [PATCH 159/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ef29e9f23..06a46272c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#3642](https://github.com/tiangolo/fastapi/pull/3642) by [@github-actions[bot]](https://github.com/apps/github-actions). ## 0.68.0 From ab33ba27aff6189ec3b6cbadbc2e06da7922b55d Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Mon, 2 Aug 2021 16:02:34 +0200 Subject: [PATCH 160/814] =?UTF-8?q?=E2=AC=86=20Add=20support=20for=20Pytho?= =?UTF-8?q?n=203.9=20(#2298)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .github/workflows/test.yml | 4 ++-- pyproject.toml | 1 + .../test_sql_databases_peewee.py | 18 +++++++------- tests/test_typing_python39.py | 24 +++++++++++++++++++ tests/test_union_inherited_body.py | 8 +++---- tests/utils.py | 3 ++- 6 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 tests/test_typing_python39.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f346cab6b..1867cbb00 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,9 +10,9 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8, 3.9] fail-fast: false - + steps: - uses: actions/checkout@v2 - name: Set up Python diff --git a/pyproject.toml b/pyproject.toml index 45880cc31..d7014e8be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ classifiers = [ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Internet :: WWW/HTTP", ] diff --git a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py b/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py index 08cfa5ca9..2ebc31b95 100644 --- a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py +++ b/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py @@ -5,7 +5,7 @@ from unittest.mock import MagicMock import pytest from fastapi.testclient import TestClient -from ...utils import skip_py36 +from ...utils import needs_py37 openapi_schema = { "openapi": "3.0.2", @@ -340,14 +340,14 @@ def client(): test_db.unlink() -@skip_py36 +@needs_py37 def test_openapi_schema(client): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == openapi_schema -@skip_py36 +@needs_py37 def test_create_user(client): test_user = {"email": "johndoe@example.com", "password": "secret"} response = client.post("/users/", json=test_user) @@ -359,7 +359,7 @@ def test_create_user(client): assert response.status_code == 400, response.text -@skip_py36 +@needs_py37 def test_get_user(client): response = client.get("/users/1") assert response.status_code == 200, response.text @@ -368,13 +368,13 @@ def test_get_user(client): assert "id" in data -@skip_py36 +@needs_py37 def test_inexistent_user(client): response = client.get("/users/999") assert response.status_code == 404, response.text -@skip_py36 +@needs_py37 def test_get_users(client): response = client.get("/users/") assert response.status_code == 200, response.text @@ -386,7 +386,7 @@ def test_get_users(client): time.sleep = MagicMock() -@skip_py36 +@needs_py37 def test_get_slowusers(client): response = client.get("/slowusers/") assert response.status_code == 200, response.text @@ -395,7 +395,7 @@ def test_get_slowusers(client): assert "id" in data[0] -@skip_py36 +@needs_py37 def test_create_item(client): item = {"title": "Foo", "description": "Something that fights"} response = client.post("/users/1/items/", json=item) @@ -419,7 +419,7 @@ def test_create_item(client): assert item_to_check["description"] == item["description"] -@skip_py36 +@needs_py37 def test_read_items(client): response = client.get("/items/") assert response.status_code == 200, response.text diff --git a/tests/test_typing_python39.py b/tests/test_typing_python39.py new file mode 100644 index 000000000..b1ea635e7 --- /dev/null +++ b/tests/test_typing_python39.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient + +from .utils import needs_py39 + + +@needs_py39 +def test_typing(): + types = { + list[int]: [1, 2, 3], + dict[str, list[int]]: {"a": [1, 2, 3], "b": [4, 5, 6]}, + set[int]: [1, 2, 3], # `set` is converted to `list` + tuple[int, ...]: [1, 2, 3], # `tuple` is converted to `list` + } + for test_type, expect in types.items(): + app = FastAPI() + + @app.post("/", response_model=test_type) + def post_endpoint(input: test_type): + return input + + res = TestClient(app).post("/", json=expect) + assert res.status_code == 200, res.json() + assert res.json() == expect diff --git a/tests/test_union_inherited_body.py b/tests/test_union_inherited_body.py index a1a3f0ed5..e3d0acc99 100644 --- a/tests/test_union_inherited_body.py +++ b/tests/test_union_inherited_body.py @@ -4,7 +4,7 @@ from fastapi import FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel -from .utils import skip_py36 +from .utils import needs_py37 # In Python 3.6: # u = Union[ExtendedItem, Item] == __main__.Item @@ -118,21 +118,21 @@ inherited_item_openapi_schema = { } -@skip_py36 +@needs_py37 def test_inherited_item_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == inherited_item_openapi_schema -@skip_py36 +@needs_py37 def test_post_extended_item(): response = client.post("/items/", json={"name": "Foo", "age": 5}) assert response.status_code == 200, response.text assert response.json() == {"item": {"name": "Foo", "age": 5}} -@skip_py36 +@needs_py37 def test_post_item(): response = client.post("/items/", json={"name": "Foo"}) assert response.status_code == 200, response.text diff --git a/tests/utils.py b/tests/utils.py index 2c6c2067d..92d1c48e8 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -2,4 +2,5 @@ import sys import pytest -skip_py36 = pytest.mark.skipif(sys.version_info < (3, 7), reason="skip python3.6") +needs_py37 = pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7+") +needs_py39 = pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python3.9+") From 27fd954a453d0e1b9c2384b798721a5992106260 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 2 Aug 2021 14:03:15 +0000 Subject: [PATCH 161/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 06a46272c..0d9cabab9 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Add support for Python 3.9. PR [#2298](https://github.com/tiangolo/fastapi/pull/2298) by [@Kludex](https://github.com/Kludex). * 👥 Update FastAPI People. PR [#3642](https://github.com/tiangolo/fastapi/pull/3642) by [@github-actions[bot]](https://github.com/apps/github-actions). ## 0.68.0 From 9a33a0e24c7803b4bf42cc6a3e954875f39f4eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 2 Aug 2021 16:53:52 +0200 Subject: [PATCH 162/814] =?UTF-8?q?=E2=9E=95=20Update=20docs=20library=20t?= =?UTF-8?q?o=20include=20sources=20in=20Markdown=20(#3648)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/de/mkdocs.yml | 2 +- docs/en/mkdocs.yml | 2 +- docs/es/mkdocs.yml | 2 +- docs/fr/mkdocs.yml | 2 +- docs/id/mkdocs.yml | 2 +- docs/it/mkdocs.yml | 2 +- docs/ja/mkdocs.yml | 2 +- docs/ko/mkdocs.yml | 2 +- docs/pl/mkdocs.yml | 2 +- docs/pt/mkdocs.yml | 2 +- docs/ru/mkdocs.yml | 2 +- docs/sq/mkdocs.yml | 2 +- docs/tr/mkdocs.yml | 2 +- docs/uk/mkdocs.yml | 2 +- docs/zh/mkdocs.yml | 2 +- pyproject.toml | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 033326486..ae1443a17 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -58,7 +58,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index d2fe2acaf..0460f9f38 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -162,7 +162,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index e9e651148..9d47622b0 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -68,7 +68,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 88b3fe02e..6511f64d5 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -66,7 +66,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index 983bbd62b..63cc0ea4c 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -58,7 +58,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index bfe2dfe83..5edda0808 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -58,7 +58,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index d92871029..ade730953 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -98,7 +98,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 8d2119db8..78863dacb 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -64,7 +64,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 9f12413d9..d41e0677b 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -58,7 +58,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index fd2ac2190..89cd70ac5 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -72,7 +72,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index c737bb2b5..4775da1a8 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -58,7 +58,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index c5ce8003f..3ad529488 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -58,7 +58,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index d94b527f2..48aa790a3 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -58,7 +58,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index 4b8983c57..7f72e2ed3 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -58,7 +58,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 6a1ddb156..ded80378f 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -107,7 +107,7 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -- markdown_include.include: +- mdx_include: base_path: docs - admonition - codehilite diff --git a/pyproject.toml b/pyproject.toml index d7014e8be..eddbb92aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,7 +68,7 @@ test = [ doc = [ "mkdocs >=1.1.2,<2.0.0", "mkdocs-material >=7.1.9,<8.0.0", - "markdown-include >=0.6.0,<0.7.0", + "mdx-include >=1.4.1,<2.0.0", "mkdocs-markdownextradata-plugin >=0.1.7,<0.2.0", "typer-cli >=0.0.12,<0.0.13", "pyyaml >=5.3.1,<6.0.0" From 25a48287ed6043f7ee81417cef3c4d1f1dc56f72 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 2 Aug 2021 14:54:26 +0000 Subject: [PATCH 163/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0d9cabab9..bcb9ccf66 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ➕ Update docs library to include sources in Markdown. PR [#3648](https://github.com/tiangolo/fastapi/pull/3648) by [@tiangolo](https://github.com/tiangolo). * ⬆ Add support for Python 3.9. PR [#2298](https://github.com/tiangolo/fastapi/pull/2298) by [@Kludex](https://github.com/Kludex). * 👥 Update FastAPI People. PR [#3642](https://github.com/tiangolo/fastapi/pull/3642) by [@github-actions[bot]](https://github.com/apps/github-actions). From 4d4452ede5fde9257e7b945a7b6f6be18f39b08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 17 Aug 2021 22:00:29 +0200 Subject: [PATCH 164/814] =?UTF-8?q?=F0=9F=94=A5=20Remove/clean=20extra=20i?= =?UTF-8?q?mports=20from=20examples=20in=20docs=20for=20features=20(#3709)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/features.md | 1 - docs/es/docs/features.md | 1 - docs/fr/docs/features.md | 1 - docs/ja/docs/features.md | 1 - docs/pt/docs/features.md | 1 - docs/zh/docs/features.md | 1 - 6 files changed, 6 deletions(-) diff --git a/docs/en/docs/features.md b/docs/en/docs/features.md index 0ca7902aa..c92795d4a 100644 --- a/docs/en/docs/features.md +++ b/docs/en/docs/features.md @@ -32,7 +32,6 @@ If you need a 2 minute refresher of how to use Python types (even if you don't u You write standard Python with types: ```Python -from typing import List, Dict from datetime import date from pydantic import BaseModel diff --git a/docs/es/docs/features.md b/docs/es/docs/features.md index 4e7453566..945b2cc94 100644 --- a/docs/es/docs/features.md +++ b/docs/es/docs/features.md @@ -32,7 +32,6 @@ Si necesitas un repaso de 2 minutos de cómo usar los tipos de Python (así no u Escribes Python estándar con tipos así: ```Python -from typing import List, Dict from datetime import date from pydantic import BaseModel diff --git a/docs/fr/docs/features.md b/docs/fr/docs/features.md index d669220a6..4d8f18403 100644 --- a/docs/fr/docs/features.md +++ b/docs/fr/docs/features.md @@ -32,7 +32,6 @@ Si vous souhaitez un rappel de 2 minutes sur l'utilisation des types en Python ( Vous écrivez du python standard avec des annotations de types: ```Python -from typing import List, Dict from datetime import date from pydantic import BaseModel diff --git a/docs/ja/docs/features.md b/docs/ja/docs/features.md index 4ae9c71f6..2c406f481 100644 --- a/docs/ja/docs/features.md +++ b/docs/ja/docs/features.md @@ -31,7 +31,6 @@ FastAPIの機能はすべて、標準のPython 3.6型宣言に基づいていま 型を使用した標準的なPythonを記述します: ```Python -from typing import List, Dict from datetime import date from pydantic import BaseModel diff --git a/docs/pt/docs/features.md b/docs/pt/docs/features.md index 51a57d96e..20014fe2d 100644 --- a/docs/pt/docs/features.md +++ b/docs/pt/docs/features.md @@ -32,7 +32,6 @@ Se você precisa refrescar a memória rapidamente sobre como usar tipos do Pytho Você escreve Python padrão com tipos: ```Python -from typing import List, Dict from datetime import date from pydantic import BaseModel diff --git a/docs/zh/docs/features.md b/docs/zh/docs/features.md index d41509435..4752947a3 100644 --- a/docs/zh/docs/features.md +++ b/docs/zh/docs/features.md @@ -33,7 +33,6 @@ 编写带有类型标注的标准 Python: ```Python -from typing import List, Dict from datetime import date from pydantic import BaseModel From 84490a2160a63da23f1b27d74b0ed56eed82699d Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 17 Aug 2021 20:01:09 +0000 Subject: [PATCH 165/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bcb9ccf66..81078703a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔥 Remove/clean extra imports from examples in docs for features. PR [#3709](https://github.com/tiangolo/fastapi/pull/3709) by [@tiangolo](https://github.com/tiangolo). * ➕ Update docs library to include sources in Markdown. PR [#3648](https://github.com/tiangolo/fastapi/pull/3648) by [@tiangolo](https://github.com/tiangolo). * ⬆ Add support for Python 3.9. PR [#2298](https://github.com/tiangolo/fastapi/pull/2298) by [@Kludex](https://github.com/Kludex). * 👥 Update FastAPI People. PR [#3642](https://github.com/tiangolo/fastapi/pull/3642) by [@github-actions[bot]](https://github.com/apps/github-actions). From 30e742d566789f7855bd3a82e7ddbe91760a2074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 17 Aug 2021 22:47:05 +0200 Subject: [PATCH 166/814] =?UTF-8?q?=E2=9C=A8=20Enable=20recent=20Material?= =?UTF-8?q?=20for=20MkDocs=20Insiders=20features=20(#3710)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/de/mkdocs.yml | 4 ++-- docs/en/mkdocs.yml | 7 +++++-- docs/es/mkdocs.yml | 4 ++-- docs/fr/mkdocs.yml | 4 ++-- docs/id/mkdocs.yml | 4 ++-- docs/it/mkdocs.yml | 4 ++-- docs/ja/mkdocs.yml | 4 ++-- docs/ko/mkdocs.yml | 4 ++-- docs/pl/mkdocs.yml | 4 ++-- docs/pt/mkdocs.yml | 4 ++-- docs/ru/mkdocs.yml | 4 ++-- docs/sq/mkdocs.yml | 4 ++-- docs/tr/mkdocs.yml | 4 ++-- docs/uk/mkdocs.yml | 4 ++-- docs/zh/mkdocs.yml | 4 ++-- 15 files changed, 33 insertions(+), 30 deletions(-) diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index ae1443a17..49fad8ec4 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -67,7 +68,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -120,6 +121,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 0460f9f38..a11ac6871 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: img/icon-white.svg @@ -162,6 +163,9 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false +# Uncomment these 2 lines during development to more easily add highlights +# - pymdownx.highlight: +# linenums: true - mdx_include: base_path: docs - admonition @@ -171,7 +175,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -224,6 +228,5 @@ extra_css: - css/termynal.css - css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - js/termynal.js - js/custom.js diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 9d47622b0..3c0c65c87 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -77,7 +78,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -130,6 +131,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 6511f64d5..e9819b458 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -75,7 +76,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -128,6 +129,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index 63cc0ea4c..88028533e 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -67,7 +68,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -120,6 +121,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index 5edda0808..477f9c55a 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -67,7 +68,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -120,6 +121,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index ade730953..2617fec96 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -107,7 +108,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -160,6 +161,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 78863dacb..6ee22afba 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -73,7 +74,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -126,6 +127,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index d41e0677b..379957783 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -67,7 +68,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -120,6 +121,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 89cd70ac5..bd5ad59c1 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -81,7 +82,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -134,6 +135,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 4775da1a8..359cce8eb 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -67,7 +68,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -120,6 +121,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index 3ad529488..53019fea5 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -67,7 +68,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -120,6 +121,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 48aa790a3..5e429fdef 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -67,7 +68,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -120,6 +121,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index 7f72e2ed3..4d8636bd6 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -67,7 +68,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -120,6 +121,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index ded80378f..5f8fc30f8 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg @@ -116,7 +117,7 @@ markdown_extensions: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format '' + format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed extra: social: @@ -169,6 +170,5 @@ extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css extra_javascript: -- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js From 4ac310875d74da61d3dbb73bf25d4c74c8e94217 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 17 Aug 2021 20:47:40 +0000 Subject: [PATCH 167/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 81078703a..d0d442e9a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Enable recent Material for MkDocs Insiders features. PR [#3710](https://github.com/tiangolo/fastapi/pull/3710) by [@tiangolo](https://github.com/tiangolo). * 🔥 Remove/clean extra imports from examples in docs for features. PR [#3709](https://github.com/tiangolo/fastapi/pull/3709) by [@tiangolo](https://github.com/tiangolo). * ➕ Update docs library to include sources in Markdown. PR [#3648](https://github.com/tiangolo/fastapi/pull/3648) by [@tiangolo](https://github.com/tiangolo). * ⬆ Add support for Python 3.9. PR [#2298](https://github.com/tiangolo/fastapi/pull/2298) by [@Kludex](https://github.com/Kludex). From 53a86a885d223a0f73dec035ccca0918ac4f3f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 18 Aug 2021 11:47:39 +0200 Subject: [PATCH 168/814] =?UTF-8?q?=E2=9C=A8=20Update=20computation=20of?= =?UTF-8?q?=20FastAPI=20People=20and=20sponsors=20(#3714)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/people/app/main.py | 24 +- README.md | 3 +- docs/en/data/github_sponsors.yml | 379 ++++++++++++++++++++++++ docs/en/data/people.yml | 451 ++++------------------------- docs/en/data/sponsors.yml | 7 +- docs/en/data/sponsors_badge.yml | 6 + docs/en/docs/css/custom.css | 1 + docs/en/docs/fastapi-people.md | 29 +- docs/en/overrides/main.html | 4 +- docs/fr/docs/fastapi-people.md | 29 +- docs/ja/docs/fastapi-people.md | 29 +- docs/zh/docs/fastapi-people.md | 29 +- 12 files changed, 512 insertions(+), 479 deletions(-) create mode 100644 docs/en/data/github_sponsors.yml create mode 100644 docs/en/data/sponsors_badge.yml diff --git a/.github/actions/people/app/main.py b/.github/actions/people/app/main.py index 9630d55bc..dc0bbc4c0 100644 --- a/.github/actions/people/app/main.py +++ b/.github/actions/people/app/main.py @@ -476,21 +476,16 @@ if __name__ == "__main__": ) tiers = get_individual_sponsors(settings=settings) - sponsors_50 = [] - for login, sponsor in tiers[50].items(): - sponsors_50.append( - {"login": login, "avatarUrl": sponsor.avatarUrl, "url": sponsor.url} - ) keys = list(tiers.keys()) keys.sort(reverse=True) sponsors = [] for key in keys: - if key >= 50: - continue + sponsor_group = [] for login, sponsor in tiers[key].items(): - sponsors.append( + sponsor_group.append( {"login": login, "avatarUrl": sponsor.avatarUrl, "url": sponsor.url} ) + sponsors.append(sponsor_group) people = { "maintainers": maintainers, @@ -498,16 +493,21 @@ if __name__ == "__main__": "last_month_active": last_month_active, "top_contributors": top_contributors, "top_reviewers": top_reviewers, - "sponsors_50": sponsors_50, + } + github_sponsors = { "sponsors": sponsors, } people_path = Path("./docs/en/data/people.yml") + github_sponsors_path = Path("./docs/en/data/github_sponsors.yml") people_old_content = people_path.read_text(encoding="utf-8") - new_content = yaml.dump(people, sort_keys=False, width=200, allow_unicode=True) - if people_old_content == new_content: + github_sponsors_old_content = github_sponsors_path.read_text(encoding="utf-8") + new_people_content = yaml.dump(people, sort_keys=False, width=200, allow_unicode=True) + new_github_sponsors_content = yaml.dump(github_sponsors, sort_keys=False, width=200, allow_unicode=True) + if people_old_content == new_people_content and github_sponsors_old_content == new_github_sponsors_content: logging.info("The FastAPI People data hasn't changed, finishing.") sys.exit(0) - people_path.write_text(new_content, encoding="utf-8") + people_path.write_text(new_people_content, encoding="utf-8") + github_sponsors_path.write_text(new_github_sponsors_content, encoding="utf-8") logging.info("Setting up GitHub Actions git user") subprocess.run(["git", "config", "user.name", "github-actions"], check=True) subprocess.run( diff --git a/README.md b/README.md index 0fb7cc704..bdc8c3b07 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,12 @@ The key features are: - + + diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml new file mode 100644 index 000000000..162a8dbe2 --- /dev/null +++ b/docs/en/data/github_sponsors.yml @@ -0,0 +1,379 @@ +sponsors: +- - login: jina-ai + avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4 + url: https://github.com/jina-ai +- - login: mikeckennedy + avatarUrl: https://avatars.githubusercontent.com/u/2035561?v=4 + url: https://github.com/mikeckennedy + - login: RodneyU215 + avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4 + url: https://github.com/RodneyU215 + - login: Trivie + avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4 + url: https://github.com/Trivie + - login: deta + avatarUrl: https://avatars.githubusercontent.com/u/47275976?v=4 + url: https://github.com/deta + - login: investsuite + avatarUrl: https://avatars.githubusercontent.com/u/73833632?v=4 + url: https://github.com/investsuite + - login: vimsoHQ + avatarUrl: https://avatars.githubusercontent.com/u/77627231?v=4 + url: https://github.com/vimsoHQ +- - login: newrelic + avatarUrl: https://avatars.githubusercontent.com/u/31739?v=4 + url: https://github.com/newrelic + - login: qaas + avatarUrl: https://avatars.githubusercontent.com/u/8503759?u=10a6b4391ad6ab4cf9487ce54e3fcb61322d1efc&v=4 + url: https://github.com/qaas +- - login: johnadjei + avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4 + url: https://github.com/johnadjei + - login: wdwinslow + avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 + url: https://github.com/wdwinslow +- - login: kamalgill + avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4 + url: https://github.com/kamalgill + - login: grillazz + avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=16d7d0ffa5dfb99f8834f8f76d90e138ba09b94a&v=4 + url: https://github.com/grillazz + - login: tizz98 + avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4 + url: https://github.com/tizz98 + - login: jmaralc + avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4 + url: https://github.com/jmaralc + - login: AlexandruSimion + avatarUrl: https://avatars.githubusercontent.com/u/71321732?v=4 + url: https://github.com/AlexandruSimion +- - login: samuelcolvin + avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4 + url: https://github.com/samuelcolvin + - login: jokull + avatarUrl: https://avatars.githubusercontent.com/u/701?u=0532b62166893d5160ef795c4c8b7512d971af05&v=4 + url: https://github.com/jokull + - login: wshayes + avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 + url: https://github.com/wshayes + - login: koxudaxi + avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4 + url: https://github.com/koxudaxi + - login: falkben + avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 + url: https://github.com/falkben + - login: jqueguiner + avatarUrl: https://avatars.githubusercontent.com/u/690878?u=e4835b2a985a0f2d52018e4926cb5a58c26a62e8&v=4 + url: https://github.com/jqueguiner + - login: Mazyod + avatarUrl: https://avatars.githubusercontent.com/u/860511?v=4 + url: https://github.com/Mazyod + - login: ltieman + avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4 + url: https://github.com/ltieman + - login: mrmattwright + avatarUrl: https://avatars.githubusercontent.com/u/1277725?v=4 + url: https://github.com/mrmattwright + - login: westonsteimel + avatarUrl: https://avatars.githubusercontent.com/u/1593939?u=0f2c0e3647f916fe295d62fa70da7a4c177115e3&v=4 + url: https://github.com/westonsteimel + - login: timdrijvers + avatarUrl: https://avatars.githubusercontent.com/u/1694939?v=4 + url: https://github.com/timdrijvers + - login: mrgnw + avatarUrl: https://avatars.githubusercontent.com/u/2504532?u=7ec43837a6d0afa80f96f0788744ea6341b89f97&v=4 + url: https://github.com/mrgnw + - login: madisonmay + avatarUrl: https://avatars.githubusercontent.com/u/2645393?u=f22b93c6ea345a4d26a90a3834dfc7f0789fcb63&v=4 + url: https://github.com/madisonmay + - login: saivarunk + avatarUrl: https://avatars.githubusercontent.com/u/2976867?u=71f4385e781e9a9e871a52f2d4686f9a8d69ba2f&v=4 + url: https://github.com/saivarunk + - login: andre1sk + avatarUrl: https://avatars.githubusercontent.com/u/3148093?v=4 + url: https://github.com/andre1sk + - login: Shark009 + avatarUrl: https://avatars.githubusercontent.com/u/3163309?v=4 + url: https://github.com/Shark009 + - login: peterHoburg + avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4 + url: https://github.com/peterHoburg + - login: jaredtrog + avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4 + url: https://github.com/jaredtrog + - login: CINOAdam + avatarUrl: https://avatars.githubusercontent.com/u/4728508?u=34c3d58cb900fed475d0172b436c66a94ad739ed&v=4 + url: https://github.com/CINOAdam + - login: dudil + avatarUrl: https://avatars.githubusercontent.com/u/4785835?u=58b7ea39123e0507f3b2996448a27256b16fd697&v=4 + url: https://github.com/dudil + - login: ennui93 + avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4 + url: https://github.com/ennui93 + - login: MacroPower + avatarUrl: https://avatars.githubusercontent.com/u/5648814?u=e13991efd1e03c44c911f919872e750530ded633&v=4 + url: https://github.com/MacroPower + - login: ginomempin + avatarUrl: https://avatars.githubusercontent.com/u/6091865?v=4 + url: https://github.com/ginomempin + - login: iwpnd + avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=b2286006daafff5f991557344fee20b5da59639a&v=4 + url: https://github.com/iwpnd + - login: s3ich4n + avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=ba3025d698e1c986655e776ae383a3d60d9d578e&v=4 + url: https://github.com/s3ich4n + - login: Rehket + avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4 + url: https://github.com/Rehket + - login: christippett + avatarUrl: https://avatars.githubusercontent.com/u/7218120?u=434b9d29287d7de25772d94ddc74a9bd6d969284&v=4 + url: https://github.com/christippett + - login: Kludex + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + url: https://github.com/Kludex + - login: Shackelford-Arden + avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4 + url: https://github.com/Shackelford-Arden + - login: cristeaadrian + avatarUrl: https://avatars.githubusercontent.com/u/9112724?v=4 + url: https://github.com/cristeaadrian + - login: otivvormes + avatarUrl: https://avatars.githubusercontent.com/u/11317418?u=6de1edefb6afd0108c0ad2816bd6efc4464a9c44&v=4 + url: https://github.com/otivvormes + - login: iambobmae + avatarUrl: https://avatars.githubusercontent.com/u/12390270?u=c9a35c2ee5092a9b4135ebb1f91b7f521c467031&v=4 + url: https://github.com/iambobmae + - login: ronaldnwilliams + avatarUrl: https://avatars.githubusercontent.com/u/13632749?u=ac41a086d0728bf66a9d2bee9e5e377041ff44a4&v=4 + url: https://github.com/ronaldnwilliams + - login: pablonnaoji + avatarUrl: https://avatars.githubusercontent.com/u/15187159?u=afc15bd5a4ba9c5c7206bbb1bcaeef606a0932e0&v=4 + url: https://github.com/pablonnaoji + - login: natenka + avatarUrl: https://avatars.githubusercontent.com/u/15850513?u=00d1083c980d0b4ce32835dc07eee7f43f34fd2f&v=4 + url: https://github.com/natenka + - login: la-mar + avatarUrl: https://avatars.githubusercontent.com/u/16618300?u=7755c0521d2bb0d704f35a51464b15c1e2e6c4da&v=4 + url: https://github.com/la-mar + - login: robintully + avatarUrl: https://avatars.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4 + url: https://github.com/robintully + - login: ShaulAb + avatarUrl: https://avatars.githubusercontent.com/u/18129076?u=2c8d48e47f2dbee15c3f89c3d17d4c356504386c&v=4 + url: https://github.com/ShaulAb + - login: wedwardbeck + avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4 + url: https://github.com/wedwardbeck + - login: linusg + avatarUrl: https://avatars.githubusercontent.com/u/19366641?u=125e390abef8fff3b3b0d370c369cba5d7fd4c67&v=4 + url: https://github.com/linusg + - login: RedCarpetUp + avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4 + url: https://github.com/RedCarpetUp + - login: Filimoa + avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4 + url: https://github.com/Filimoa + - login: raminsj13 + avatarUrl: https://avatars.githubusercontent.com/u/24259406?u=d51f2a526312ebba150a06936ed187ca0727d329&v=4 + url: https://github.com/raminsj13 + - login: comoelcometa + avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=c6751efa038561b9bc5fa56d1033d5174e10cd65&v=4 + url: https://github.com/comoelcometa + - login: veprimk + avatarUrl: https://avatars.githubusercontent.com/u/29689749?u=f8cb5a15a286e522e5b189bc572d5a1a90217fb2&v=4 + url: https://github.com/veprimk + - login: orihomie + avatarUrl: https://avatars.githubusercontent.com/u/29889683?u=6bc2135a52fcb3a49e69e7d50190796618185fda&v=4 + url: https://github.com/orihomie + - login: SaltyCoco + avatarUrl: https://avatars.githubusercontent.com/u/31451104?u=6ee4e17c07d21b7054f54a12fa9cc377a1b24ff9&v=4 + url: https://github.com/SaltyCoco + - login: mauroalejandrojm + avatarUrl: https://avatars.githubusercontent.com/u/31569442?u=cdada990a1527926a36e95f62c30a8b48bbc49a1&v=4 + url: https://github.com/mauroalejandrojm + - login: bulkw4r3 + avatarUrl: https://avatars.githubusercontent.com/u/35562532?u=0b812a14a02de14bf73d05fb2b2760a67bacffc2&v=4 + url: https://github.com/bulkw4r3 + - login: ybressler + avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=6621dc9ab53b697912ab2a32211bb29ae90a9112&v=4 + url: https://github.com/ybressler + - login: dbanty + avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4 + url: https://github.com/dbanty + - login: dudikbender + avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4 + url: https://github.com/dudikbender + - login: primer-io + avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4 + url: https://github.com/primer-io + - login: tkrestiankova + avatarUrl: https://avatars.githubusercontent.com/u/67013045?v=4 + url: https://github.com/tkrestiankova + - login: daverin + avatarUrl: https://avatars.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4 + url: https://github.com/daverin + - login: anthonycepeda + avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 + url: https://github.com/anthonycepeda + - login: an-tho-ny + avatarUrl: https://avatars.githubusercontent.com/u/74874159?v=4 + url: https://github.com/an-tho-ny +- - login: linux-china + avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4 + url: https://github.com/linux-china + - login: jhb + avatarUrl: https://avatars.githubusercontent.com/u/142217?v=4 + url: https://github.com/jhb + - login: yourkin + avatarUrl: https://avatars.githubusercontent.com/u/178984?v=4 + url: https://github.com/yourkin + - login: jmagnusson + avatarUrl: https://avatars.githubusercontent.com/u/190835?v=4 + url: https://github.com/jmagnusson + - login: sakti + avatarUrl: https://avatars.githubusercontent.com/u/196178?u=0110be74c4270244546f1b610334042cd16bb8ad&v=4 + url: https://github.com/sakti + - login: slafs + avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4 + url: https://github.com/slafs + - login: adamghill + avatarUrl: https://avatars.githubusercontent.com/u/317045?u=f1349d5ffe84a19f324e204777859fbf69ddf633&v=4 + url: https://github.com/adamghill + - login: eteq + avatarUrl: https://avatars.githubusercontent.com/u/346587?v=4 + url: https://github.com/eteq + - login: dmig + avatarUrl: https://avatars.githubusercontent.com/u/388564?v=4 + url: https://github.com/dmig + - login: hongqn + avatarUrl: https://avatars.githubusercontent.com/u/405587?u=470b4c04832e45141fd5264d3354845cc9fc6466&v=4 + url: https://github.com/hongqn + - login: rinckd + avatarUrl: https://avatars.githubusercontent.com/u/546002?u=1fcc7e664dc86524a0af6837a0c222829c3fd4e5&v=4 + url: https://github.com/rinckd + - login: hardbyte + avatarUrl: https://avatars.githubusercontent.com/u/855189?u=aa29e92f34708814d6b67fcd47ca4cf2ce1c04ed&v=4 + url: https://github.com/hardbyte + - login: Pytlicek + avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=169dba3bfbc04ed214a914640ff435969f19ddb3&v=4 + url: https://github.com/Pytlicek + - login: okken + avatarUrl: https://avatars.githubusercontent.com/u/1568356?u=0a991a21bdc62e2bea9ad311652f2c45f453dc84&v=4 + url: https://github.com/okken + - login: cbonoz + avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4 + url: https://github.com/cbonoz + - login: Abbe98 + avatarUrl: https://avatars.githubusercontent.com/u/2631719?u=8a064aba9a710229ad28c616549d81a24191a5df&v=4 + url: https://github.com/Abbe98 + - login: rglsk + avatarUrl: https://avatars.githubusercontent.com/u/2768101?u=e349c88673f2155fe021331377c656a9d74bcc25&v=4 + url: https://github.com/rglsk + - login: Atem18 + avatarUrl: https://avatars.githubusercontent.com/u/2875254?v=4 + url: https://github.com/Atem18 + - login: paul121 + avatarUrl: https://avatars.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4 + url: https://github.com/paul121 + - login: igorcorrea + avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4 + url: https://github.com/igorcorrea + - login: anthcor + avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4 + url: https://github.com/anthcor + - login: zsinx6 + avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4 + url: https://github.com/zsinx6 + - login: pawamoy + avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4 + url: https://github.com/pawamoy + - login: spyker77 + avatarUrl: https://avatars.githubusercontent.com/u/4953435?u=03c724c6f8fbab5cd6575b810c0c91c652fa4f79&v=4 + url: https://github.com/spyker77 + - login: JonasKs + avatarUrl: https://avatars.githubusercontent.com/u/5310116?u=98a049f3e1491bffb91e1feb7e93def6881a9389&v=4 + url: https://github.com/JonasKs + - login: holec + avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4 + url: https://github.com/holec + - login: BartlomiejRasztabiga + avatarUrl: https://avatars.githubusercontent.com/u/8852711?u=ed213d60f7a423df31ceb1004aa3ec60e612cb98&v=4 + url: https://github.com/BartlomiejRasztabiga + - login: davanstrien + avatarUrl: https://avatars.githubusercontent.com/u/8995957?u=fb2aad2b52bb4e7b56db6d7c8ecc9ae1eac1b984&v=4 + url: https://github.com/davanstrien + - login: and-semakin + avatarUrl: https://avatars.githubusercontent.com/u/9129071?u=ea77ddf7de4bc375d546bf2825ed420eaddb7666&v=4 + url: https://github.com/and-semakin + - login: VivianSolide + avatarUrl: https://avatars.githubusercontent.com/u/9358572?u=ffb2e2ec522a15dcd3f0af1f9fd1df4afe418afa&v=4 + url: https://github.com/VivianSolide + - login: hard-coders + avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 + url: https://github.com/hard-coders + - login: satwikkansal + avatarUrl: https://avatars.githubusercontent.com/u/10217535?u=b12d6ef74ea297de9e46da6933b1a5b7ba9e6a61&v=4 + url: https://github.com/satwikkansal + - login: pheanex + avatarUrl: https://avatars.githubusercontent.com/u/10408624?u=5b6bab6ee174aa6e991333e06eb29f628741013d&v=4 + url: https://github.com/pheanex + - login: wotori + avatarUrl: https://avatars.githubusercontent.com/u/10486621?u=0044c295b91694b8c9bccc0a805681f794250f7b&v=4 + url: https://github.com/wotori + - login: JimFawkes + avatarUrl: https://avatars.githubusercontent.com/u/12075115?u=dc58ecfd064d72887c34bf500ddfd52592509acd&v=4 + url: https://github.com/JimFawkes + - login: logan-connolly + avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4 + url: https://github.com/logan-connolly + - login: iPr0ger + avatarUrl: https://avatars.githubusercontent.com/u/19322290?v=4 + url: https://github.com/iPr0ger + - login: ghandic + avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 + url: https://github.com/ghandic + - login: MoronVV + avatarUrl: https://avatars.githubusercontent.com/u/24293616?v=4 + url: https://github.com/MoronVV + - login: fstau + avatarUrl: https://avatars.githubusercontent.com/u/24669867?u=60e7c8c09f8dafabee8fc3edcd6f9e19abbff918&v=4 + url: https://github.com/fstau + - login: mertguvencli + avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4 + url: https://github.com/mertguvencli + - login: rgreen32 + avatarUrl: https://avatars.githubusercontent.com/u/35779241?u=c9d64ad1ab364b6a1ec8e3d859da9ca802d681d8&v=4 + url: https://github.com/rgreen32 + - login: askurihin + avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4 + url: https://github.com/askurihin + - login: JitPackJoyride + avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=9638bfeacfa5940358188f8205ce662bba022b53&v=4 + url: https://github.com/JitPackJoyride + - login: es3n1n + avatarUrl: https://avatars.githubusercontent.com/u/40367813?u=e881a3880f1e342d19a1ea7c8e1b6d76c52dc294&v=4 + url: https://github.com/es3n1n + - login: ilias-ant + avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4 + url: https://github.com/ilias-ant + - login: arrrrrmin + avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=05600727f1cfe75f440bb3fddd49bfea84b1e894&v=4 + url: https://github.com/arrrrrmin + - login: akanz1 + avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4 + url: https://github.com/akanz1 +- - login: leogregianin + avatarUrl: https://avatars.githubusercontent.com/u/1684053?u=94ddd387601bd1805034dbe83e6eba0491c15323&v=4 + url: https://github.com/leogregianin + - login: sadikkuzu + avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4 + url: https://github.com/sadikkuzu + - login: gabrielmbmb + avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=92084ed7242160dee4d20aece923a10c59758ee5&v=4 + url: https://github.com/gabrielmbmb + - login: starhype + avatarUrl: https://avatars.githubusercontent.com/u/36908028?u=6df41f7b62f0f673f1ecbc87e9cbadaa4fcb0767&v=4 + url: https://github.com/starhype + - login: pixel365 + avatarUrl: https://avatars.githubusercontent.com/u/53819609?u=9e0309c5420ec4624aececd3ca2d7105f7f68133&v=4 + url: https://github.com/pixel365 diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 3509ce152..1e4ee30ce 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,12 +1,12 @@ maintainers: - login: tiangolo answers: 1229 - prs: 247 + prs: 250 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=05f95ca7fdead36edd9c86be46b4ef6c3c71f876&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 273 + count: 278 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: dmontagu @@ -14,11 +14,11 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu - login: ycd - count: 216 + count: 217 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: Mause - count: 196 + count: 202 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause - login: euri10 @@ -37,26 +37,26 @@ experts: count: 57 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 url: https://github.com/falkben +- login: sm-Fifteen + count: 48 + avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 + url: https://github.com/sm-Fifteen - login: raphaelauv count: 47 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv -- login: sm-Fifteen - count: 46 - avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 - url: https://github.com/sm-Fifteen - login: includeamin count: 38 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 url: https://github.com/includeamin +- login: Dustyposa + count: 38 + avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 + url: https://github.com/Dustyposa - login: prostomarkeloff count: 33 avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4 url: https://github.com/prostomarkeloff -- login: Dustyposa - count: 32 - avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 - url: https://github.com/Dustyposa - login: krishnardt count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 @@ -91,7 +91,7 @@ experts: url: https://github.com/nsidnev - login: frankie567 count: 21 - avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=72adf1cb1d29787305c99700d669561952cea0af&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 url: https://github.com/frankie567 - login: chris-allnutt count: 21 @@ -117,14 +117,22 @@ experts: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 url: https://github.com/waynerv +- login: adriangb + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 + url: https://github.com/adriangb +- login: panla + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla - login: haizaar count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar -- login: panla - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 - url: https://github.com/panla +- login: STeveShary + count: 13 + avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 + url: https://github.com/STeveShary - login: acidjunk count: 11 avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 @@ -153,43 +161,47 @@ experts: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4 url: https://github.com/stefanondisponibile -- login: adriangb +- login: hellocoldworld count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 - url: https://github.com/adriangb + avatarUrl: https://avatars.githubusercontent.com/u/47581948?v=4 + url: https://github.com/hellocoldworld last_month_active: - login: Mause - count: 14 + count: 10 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause +- login: Kludex + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + url: https://github.com/Kludex - login: panla count: 7 avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 url: https://github.com/panla -- login: Kludex - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 - url: https://github.com/Kludex - login: adriangb - count: 3 + count: 6 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 url: https://github.com/adriangb -- login: rotten - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/717719?v=4 - url: https://github.com/rotten +- login: Dustyposa + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 + url: https://github.com/Dustyposa - login: STeveShary - count: 3 + count: 5 avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 url: https://github.com/STeveShary -- login: uricholiveira +- login: Cosmicoppai count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/48108280?u=347abd073ff99d18f8e3582db11fd7b7a297598c&v=4 - url: https://github.com/uricholiveira + avatarUrl: https://avatars.githubusercontent.com/u/63765823?u=b97c98ddd6eaf06cd5a0d312db36f97996ac5b23&v=4 + url: https://github.com/Cosmicoppai - login: AlexanderPodorov count: 3 avatarUrl: https://avatars.githubusercontent.com/u/54511144?v=4 url: https://github.com/AlexanderPodorov +- login: SamuelHeath + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/12291364?v=4 + url: https://github.com/SamuelHeath top_contributors: - login: waynerv count: 25 @@ -223,6 +235,10 @@ top_contributors: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 url: https://github.com/Serrones +- login: Kludex + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + url: https://github.com/Kludex - login: hard-coders count: 6 avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 @@ -231,10 +247,6 @@ top_contributors: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes -- login: Kludex - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 - url: https://github.com/Kludex - login: SwftAlpc count: 5 avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4 @@ -261,7 +273,7 @@ top_contributors: url: https://github.com/Smlep top_reviewers: - login: Kludex - count: 83 + count: 85 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: Laineyzhang55 @@ -328,6 +340,10 @@ top_reviewers: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4 url: https://github.com/sh0nk +- login: rjNemo + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 + url: https://github.com/rjNemo - login: hard-coders count: 12 avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 @@ -344,10 +360,6 @@ top_reviewers: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4 url: https://github.com/maoyibo -- login: rjNemo - count: 9 - avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 - url: https://github.com/rjNemo - login: Smlep count: 9 avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 @@ -444,356 +456,3 @@ top_reviewers: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/38372706?u=c9d28aff15958d6ebf1971148bfb3154ff943c4f&v=4 url: https://github.com/Bluenix2 -sponsors_50: -- login: johnadjei - avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4 - url: https://github.com/johnadjei -- login: wdwinslow - avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 - url: https://github.com/wdwinslow -sponsors: -- login: kamalgill - avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4 - url: https://github.com/kamalgill -- login: grillazz - avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=16d7d0ffa5dfb99f8834f8f76d90e138ba09b94a&v=4 - url: https://github.com/grillazz -- login: tizz98 - avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4 - url: https://github.com/tizz98 -- login: jmaralc - avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4 - url: https://github.com/jmaralc -- login: samuelcolvin - avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4 - url: https://github.com/samuelcolvin -- login: jokull - avatarUrl: https://avatars.githubusercontent.com/u/701?u=0532b62166893d5160ef795c4c8b7512d971af05&v=4 - url: https://github.com/jokull -- login: wshayes - avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 - url: https://github.com/wshayes -- login: koxudaxi - avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4 - url: https://github.com/koxudaxi -- login: falkben - avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 - url: https://github.com/falkben -- login: jqueguiner - avatarUrl: https://avatars.githubusercontent.com/u/690878?u=e4835b2a985a0f2d52018e4926cb5a58c26a62e8&v=4 - url: https://github.com/jqueguiner -- login: Mazyod - avatarUrl: https://avatars.githubusercontent.com/u/860511?v=4 - url: https://github.com/Mazyod -- login: ltieman - avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4 - url: https://github.com/ltieman -- login: mrmattwright - avatarUrl: https://avatars.githubusercontent.com/u/1277725?v=4 - url: https://github.com/mrmattwright -- login: westonsteimel - avatarUrl: https://avatars.githubusercontent.com/u/1593939?u=0f2c0e3647f916fe295d62fa70da7a4c177115e3&v=4 - url: https://github.com/westonsteimel -- login: timdrijvers - avatarUrl: https://avatars.githubusercontent.com/u/1694939?v=4 - url: https://github.com/timdrijvers -- login: mrgnw - avatarUrl: https://avatars.githubusercontent.com/u/2504532?u=7ec43837a6d0afa80f96f0788744ea6341b89f97&v=4 - url: https://github.com/mrgnw -- login: madisonmay - avatarUrl: https://avatars.githubusercontent.com/u/2645393?u=f22b93c6ea345a4d26a90a3834dfc7f0789fcb63&v=4 - url: https://github.com/madisonmay -- login: saivarunk - avatarUrl: https://avatars.githubusercontent.com/u/2976867?u=71f4385e781e9a9e871a52f2d4686f9a8d69ba2f&v=4 - url: https://github.com/saivarunk -- login: andre1sk - avatarUrl: https://avatars.githubusercontent.com/u/3148093?v=4 - url: https://github.com/andre1sk -- login: Shark009 - avatarUrl: https://avatars.githubusercontent.com/u/3163309?v=4 - url: https://github.com/Shark009 -- login: peterHoburg - avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4 - url: https://github.com/peterHoburg -- login: CINOAdam - avatarUrl: https://avatars.githubusercontent.com/u/4728508?u=34c3d58cb900fed475d0172b436c66a94ad739ed&v=4 - url: https://github.com/CINOAdam -- login: dudil - avatarUrl: https://avatars.githubusercontent.com/u/4785835?u=58b7ea39123e0507f3b2996448a27256b16fd697&v=4 - url: https://github.com/dudil -- login: ennui93 - avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4 - url: https://github.com/ennui93 -- login: MacroPower - avatarUrl: https://avatars.githubusercontent.com/u/5648814?u=e13991efd1e03c44c911f919872e750530ded633&v=4 - url: https://github.com/MacroPower -- login: ginomempin - avatarUrl: https://avatars.githubusercontent.com/u/6091865?v=4 - url: https://github.com/ginomempin -- login: iwpnd - avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=b2286006daafff5f991557344fee20b5da59639a&v=4 - url: https://github.com/iwpnd -- login: s3ich4n - avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=ba3025d698e1c986655e776ae383a3d60d9d578e&v=4 - url: https://github.com/s3ich4n -- login: Rehket - avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4 - url: https://github.com/Rehket -- login: christippett - avatarUrl: https://avatars.githubusercontent.com/u/7218120?u=434b9d29287d7de25772d94ddc74a9bd6d969284&v=4 - url: https://github.com/christippett -- login: Kludex - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 - url: https://github.com/Kludex -- login: Shackelford-Arden - avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4 - url: https://github.com/Shackelford-Arden -- login: macleodmac - avatarUrl: https://avatars.githubusercontent.com/u/8996312?u=e39c68c3e0b1d264dcba4850134a291680f46355&v=4 - url: https://github.com/macleodmac -- login: cristeaadrian - avatarUrl: https://avatars.githubusercontent.com/u/9112724?v=4 - url: https://github.com/cristeaadrian -- login: otivvormes - avatarUrl: https://avatars.githubusercontent.com/u/11317418?u=6de1edefb6afd0108c0ad2816bd6efc4464a9c44&v=4 - url: https://github.com/otivvormes -- login: iambobmae - avatarUrl: https://avatars.githubusercontent.com/u/12390270?u=c9a35c2ee5092a9b4135ebb1f91b7f521c467031&v=4 - url: https://github.com/iambobmae -- login: ronaldnwilliams - avatarUrl: https://avatars.githubusercontent.com/u/13632749?u=ac41a086d0728bf66a9d2bee9e5e377041ff44a4&v=4 - url: https://github.com/ronaldnwilliams -- login: pablonnaoji - avatarUrl: https://avatars.githubusercontent.com/u/15187159?u=afc15bd5a4ba9c5c7206bbb1bcaeef606a0932e0&v=4 - url: https://github.com/pablonnaoji -- login: natenka - avatarUrl: https://avatars.githubusercontent.com/u/15850513?u=00d1083c980d0b4ce32835dc07eee7f43f34fd2f&v=4 - url: https://github.com/natenka -- login: la-mar - avatarUrl: https://avatars.githubusercontent.com/u/16618300?u=7755c0521d2bb0d704f35a51464b15c1e2e6c4da&v=4 - url: https://github.com/la-mar -- login: robintully - avatarUrl: https://avatars.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4 - url: https://github.com/robintully -- login: ShaulAb - avatarUrl: https://avatars.githubusercontent.com/u/18129076?u=2c8d48e47f2dbee15c3f89c3d17d4c356504386c&v=4 - url: https://github.com/ShaulAb -- login: wedwardbeck - avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4 - url: https://github.com/wedwardbeck -- login: linusg - avatarUrl: https://avatars.githubusercontent.com/u/19366641?u=125e390abef8fff3b3b0d370c369cba5d7fd4c67&v=4 - url: https://github.com/linusg -- login: RedCarpetUp - avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4 - url: https://github.com/RedCarpetUp -- login: daddycocoaman - avatarUrl: https://avatars.githubusercontent.com/u/21189155?u=756f6a17c71c538b11470f70839baacab43807ef&v=4 - url: https://github.com/daddycocoaman -- login: Filimoa - avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4 - url: https://github.com/Filimoa -- login: raminsj13 - avatarUrl: https://avatars.githubusercontent.com/u/24259406?u=d51f2a526312ebba150a06936ed187ca0727d329&v=4 - url: https://github.com/raminsj13 -- login: comoelcometa - avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=c6751efa038561b9bc5fa56d1033d5174e10cd65&v=4 - url: https://github.com/comoelcometa -- login: veprimk - avatarUrl: https://avatars.githubusercontent.com/u/29689749?u=f8cb5a15a286e522e5b189bc572d5a1a90217fb2&v=4 - url: https://github.com/veprimk -- login: orihomie - avatarUrl: https://avatars.githubusercontent.com/u/29889683?u=6bc2135a52fcb3a49e69e7d50190796618185fda&v=4 - url: https://github.com/orihomie -- login: SaltyCoco - avatarUrl: https://avatars.githubusercontent.com/u/31451104?u=6ee4e17c07d21b7054f54a12fa9cc377a1b24ff9&v=4 - url: https://github.com/SaltyCoco -- login: mauroalejandrojm - avatarUrl: https://avatars.githubusercontent.com/u/31569442?u=cdada990a1527926a36e95f62c30a8b48bbc49a1&v=4 - url: https://github.com/mauroalejandrojm -- login: ybressler - avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=6621dc9ab53b697912ab2a32211bb29ae90a9112&v=4 - url: https://github.com/ybressler -- login: dbanty - avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4 - url: https://github.com/dbanty -- login: dudikbender - avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4 - url: https://github.com/dudikbender -- login: primer-io - avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4 - url: https://github.com/primer-io -- login: tkrestiankova - avatarUrl: https://avatars.githubusercontent.com/u/67013045?v=4 - url: https://github.com/tkrestiankova -- login: daverin - avatarUrl: https://avatars.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4 - url: https://github.com/daverin -- login: anthonycepeda - avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 - url: https://github.com/anthonycepeda -- login: an-tho-ny - avatarUrl: https://avatars.githubusercontent.com/u/74874159?v=4 - url: https://github.com/an-tho-ny -- login: linux-china - avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4 - url: https://github.com/linux-china -- login: jhb - avatarUrl: https://avatars.githubusercontent.com/u/142217?v=4 - url: https://github.com/jhb -- login: yourkin - avatarUrl: https://avatars.githubusercontent.com/u/178984?v=4 - url: https://github.com/yourkin -- login: jmagnusson - avatarUrl: https://avatars.githubusercontent.com/u/190835?v=4 - url: https://github.com/jmagnusson -- login: sakti - avatarUrl: https://avatars.githubusercontent.com/u/196178?u=0110be74c4270244546f1b610334042cd16bb8ad&v=4 - url: https://github.com/sakti -- login: slafs - avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4 - url: https://github.com/slafs -- login: adamghill - avatarUrl: https://avatars.githubusercontent.com/u/317045?u=f1349d5ffe84a19f324e204777859fbf69ddf633&v=4 - url: https://github.com/adamghill -- login: eteq - avatarUrl: https://avatars.githubusercontent.com/u/346587?v=4 - url: https://github.com/eteq -- login: dmig - avatarUrl: https://avatars.githubusercontent.com/u/388564?v=4 - url: https://github.com/dmig -- login: hongqn - avatarUrl: https://avatars.githubusercontent.com/u/405587?u=470b4c04832e45141fd5264d3354845cc9fc6466&v=4 - url: https://github.com/hongqn -- login: rinckd - avatarUrl: https://avatars.githubusercontent.com/u/546002?u=1fcc7e664dc86524a0af6837a0c222829c3fd4e5&v=4 - url: https://github.com/rinckd -- login: hardbyte - avatarUrl: https://avatars.githubusercontent.com/u/855189?u=aa29e92f34708814d6b67fcd47ca4cf2ce1c04ed&v=4 - url: https://github.com/hardbyte -- login: Pytlicek - avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=169dba3bfbc04ed214a914640ff435969f19ddb3&v=4 - url: https://github.com/Pytlicek -- login: okken - avatarUrl: https://avatars.githubusercontent.com/u/1568356?u=0a991a21bdc62e2bea9ad311652f2c45f453dc84&v=4 - url: https://github.com/okken -- login: cbonoz - avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4 - url: https://github.com/cbonoz -- login: Abbe98 - avatarUrl: https://avatars.githubusercontent.com/u/2631719?u=8a064aba9a710229ad28c616549d81a24191a5df&v=4 - url: https://github.com/Abbe98 -- login: rglsk - avatarUrl: https://avatars.githubusercontent.com/u/2768101?u=e349c88673f2155fe021331377c656a9d74bcc25&v=4 - url: https://github.com/rglsk -- login: Atem18 - avatarUrl: https://avatars.githubusercontent.com/u/2875254?v=4 - url: https://github.com/Atem18 -- login: paul121 - avatarUrl: https://avatars.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4 - url: https://github.com/paul121 -- login: igorcorrea - avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4 - url: https://github.com/igorcorrea -- login: anthcor - avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4 - url: https://github.com/anthcor -- login: zsinx6 - avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4 - url: https://github.com/zsinx6 -- login: pawamoy - avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4 - url: https://github.com/pawamoy -- login: spyker77 - avatarUrl: https://avatars.githubusercontent.com/u/4953435?u=568baae6469628e020fe0bab16e395b7ae10c7d3&v=4 - url: https://github.com/spyker77 -- login: serfer2 - avatarUrl: https://avatars.githubusercontent.com/u/5196592?u=e8798d87120952ed41876778f0cc8a1ddb47f901&v=4 - url: https://github.com/serfer2 -- login: JonasKs - avatarUrl: https://avatars.githubusercontent.com/u/5310116?u=98a049f3e1491bffb91e1feb7e93def6881a9389&v=4 - url: https://github.com/JonasKs -- login: holec - avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4 - url: https://github.com/holec -- login: BartlomiejRasztabiga - avatarUrl: https://avatars.githubusercontent.com/u/8852711?u=ed213d60f7a423df31ceb1004aa3ec60e612cb98&v=4 - url: https://github.com/BartlomiejRasztabiga -- login: davanstrien - avatarUrl: https://avatars.githubusercontent.com/u/8995957?u=fb2aad2b52bb4e7b56db6d7c8ecc9ae1eac1b984&v=4 - url: https://github.com/davanstrien -- login: and-semakin - avatarUrl: https://avatars.githubusercontent.com/u/9129071?u=ea77ddf7de4bc375d546bf2825ed420eaddb7666&v=4 - url: https://github.com/and-semakin -- login: VivianSolide - avatarUrl: https://avatars.githubusercontent.com/u/9358572?u=ffb2e2ec522a15dcd3f0af1f9fd1df4afe418afa&v=4 - url: https://github.com/VivianSolide -- login: hard-coders - avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 - url: https://github.com/hard-coders -- login: satwikkansal - avatarUrl: https://avatars.githubusercontent.com/u/10217535?u=b12d6ef74ea297de9e46da6933b1a5b7ba9e6a61&v=4 - url: https://github.com/satwikkansal -- login: pheanex - avatarUrl: https://avatars.githubusercontent.com/u/10408624?u=5b6bab6ee174aa6e991333e06eb29f628741013d&v=4 - url: https://github.com/pheanex -- login: wotori - avatarUrl: https://avatars.githubusercontent.com/u/10486621?u=0044c295b91694b8c9bccc0a805681f794250f7b&v=4 - url: https://github.com/wotori -- login: JimFawkes - avatarUrl: https://avatars.githubusercontent.com/u/12075115?u=dc58ecfd064d72887c34bf500ddfd52592509acd&v=4 - url: https://github.com/JimFawkes -- login: logan-connolly - avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4 - url: https://github.com/logan-connolly -- login: iPr0ger - avatarUrl: https://avatars.githubusercontent.com/u/19322290?v=4 - url: https://github.com/iPr0ger -- login: ghandic - avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 - url: https://github.com/ghandic -- login: MoronVV - avatarUrl: https://avatars.githubusercontent.com/u/24293616?v=4 - url: https://github.com/MoronVV -- login: fstau - avatarUrl: https://avatars.githubusercontent.com/u/24669867?u=60e7c8c09f8dafabee8fc3edcd6f9e19abbff918&v=4 - url: https://github.com/fstau -- login: mertguvencli - avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4 - url: https://github.com/mertguvencli -- login: rgreen32 - avatarUrl: https://avatars.githubusercontent.com/u/35779241?u=c9d64ad1ab364b6a1ec8e3d859da9ca802d681d8&v=4 - url: https://github.com/rgreen32 -- login: askurihin - avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4 - url: https://github.com/askurihin -- login: JitPackJoyride - avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=9638bfeacfa5940358188f8205ce662bba022b53&v=4 - url: https://github.com/JitPackJoyride -- login: es3n1n - avatarUrl: https://avatars.githubusercontent.com/u/40367813?u=e881a3880f1e342d19a1ea7c8e1b6d76c52dc294&v=4 - url: https://github.com/es3n1n -- login: ilias-ant - avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4 - url: https://github.com/ilias-ant -- login: arrrrrmin - avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=05600727f1cfe75f440bb3fddd49bfea84b1e894&v=4 - url: https://github.com/arrrrrmin -- login: akanz1 - avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4 - url: https://github.com/akanz1 -- login: athemeart - avatarUrl: https://avatars.githubusercontent.com/u/61623624?v=4 - url: https://github.com/athemeart -- login: sadikkuzu - avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4 - url: https://github.com/sadikkuzu -- login: gabrielmbmb - avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=92084ed7242160dee4d20aece923a10c59758ee5&v=4 - url: https://github.com/gabrielmbmb -- login: pixel365 - avatarUrl: https://avatars.githubusercontent.com/u/53819609?u=9e0309c5420ec4624aececd3ca2d7105f7f68133&v=4 - url: https://github.com/pixel365 -- login: amjed-ali-k - avatarUrl: https://avatars.githubusercontent.com/u/86785660?u=8713ba29ed451d3469f303a9eb8f164488d47500&v=4 - url: https://github.com/amjed-ali-k diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 49df39c99..b5bb9a773 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -1,11 +1,11 @@ gold: - - url: https://www.deta.sh/?ref=fastapi - title: The launchpad for all your (team's) ideas - img: https://fastapi.tiangolo.com/img/sponsors/deta.svg - url: https://bit.ly/2QSouzH title: "Jina: build neural search-as-a-service for any kind of data in just minutes." img: https://fastapi.tiangolo.com/img/sponsors/jina.svg silver: + - url: https://www.deta.sh/?ref=fastapi + title: The launchpad for all your (team's) ideas + img: https://fastapi.tiangolo.com/img/sponsors/deta.svg - url: https://www.investsuite.com/jobs title: Wealthtech jobs with FastAPI img: https://fastapi.tiangolo.com/img/sponsors/investsuite.svg @@ -15,7 +15,6 @@ silver: - url: https://talkpython.fm/fastapi-sponsor title: FastAPI video courses on demand from people you trust img: https://fastapi.tiangolo.com/img/sponsors/talkpython.png -bronze: - url: https://testdriven.io/courses/tdd-fastapi/ title: Learn to build high-quality web apps with best practices img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml new file mode 100644 index 000000000..066a82506 --- /dev/null +++ b/docs/en/data/sponsors_badge.yml @@ -0,0 +1,6 @@ +logins: + - jina-ai + - deta + - investsuite + - vimsoHQ + - mikeckennedy diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css index 2b6d55173..997bcd3af 100644 --- a/docs/en/docs/css/custom.css +++ b/docs/en/docs/css/custom.css @@ -20,6 +20,7 @@ a.internal-link::after { .user-list { display: flex; flex-wrap: wrap; + margin-bottom: 2rem; } .user-list-center { diff --git a/docs/en/docs/fastapi-people.md b/docs/en/docs/fastapi-people.md index ce8ea3887..f4f38cdbe 100644 --- a/docs/en/docs/fastapi-people.md +++ b/docs/en/docs/fastapi-people.md @@ -114,25 +114,28 @@ These are the **Sponsors**. 😎 They are supporting my work with **FastAPI** (and others), mainly through GitHub Sponsors. +{% if sponsors.gold %} + ### Gold Sponsors -{% if sponsors %} {% for sponsor in sponsors.gold -%} {% endfor %} {% endif %} +{% if sponsors.silver %} + ### Silver Sponsors -{% if sponsors %} {% for sponsor in sponsors.silver -%} {% endfor %} {% endif %} +{% if sponsors.bronze %} + ### Bronze Sponsors -{% if sponsors %} {% for sponsor in sponsors.bronze -%} {% endfor %} @@ -140,28 +143,22 @@ They are supporting my work with **FastAPI** (and others), mainly through -{% for user in people.sponsors_50 %} + +{% for user in group %} +{% if user.login not in sponsors_badge.logins %} + +{% endif %} {% endfor %}
-{% endif %} -{% endif %} - -{% if people %} -
-{% for user in people.sponsors %} - - {% endfor %} - -
{% endif %} ## About the data - technical details diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index eca89a553..aa381faa3 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -22,12 +22,12 @@
-
+
diff --git a/docs/fr/docs/fastapi-people.md b/docs/fr/docs/fastapi-people.md index ac6e19831..9ec2718c4 100644 --- a/docs/fr/docs/fastapi-people.md +++ b/docs/fr/docs/fastapi-people.md @@ -114,25 +114,28 @@ Ce sont les **Sponsors**. 😎 Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec GitHub Sponsors. +{% if sponsors.gold %} + ### Gold Sponsors -{% if sponsors %} {% for sponsor in sponsors.gold -%} {% endfor %} {% endif %} +{% if sponsors.silver %} + ### Silver Sponsors -{% if sponsors %} {% for sponsor in sponsors.silver -%} {% endfor %} {% endif %} +{% if sponsors.bronze %} + ### Bronze Sponsors -{% if sponsors %} {% for sponsor in sponsors.bronze -%} {% endfor %} @@ -140,28 +143,22 @@ Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec -{% for user in people.sponsors_50 %} + +{% for user in group %} +{% if user.login not in sponsors_badge.logins %} + +{% endif %} {% endfor %}
-{% endif %} -{% endif %} - -{% if people %} -
-{% for user in people.sponsors %} - - {% endfor %} - -
{% endif %} ## À propos des données - détails techniques diff --git a/docs/ja/docs/fastapi-people.md b/docs/ja/docs/fastapi-people.md index 1d263449a..229d8dde5 100644 --- a/docs/ja/docs/fastapi-people.md +++ b/docs/ja/docs/fastapi-people.md @@ -115,25 +115,28 @@ FastAPIには、様々なバックグラウンドの人々を歓迎する素晴 彼らは、GitHub Sponsors を介して私の **FastAPI** などに関する活動を支援してくれています。 +{% if sponsors.gold %} + ### Gold Sponsors -{% if sponsors %} {% for sponsor in sponsors.gold -%} {% endfor %} {% endif %} +{% if sponsors.silver %} + ### Silver Sponsors -{% if sponsors %} {% for sponsor in sponsors.silver -%} {% endfor %} {% endif %} +{% if sponsors.bronze %} + ### Bronze Sponsors -{% if sponsors %} {% for sponsor in sponsors.bronze -%} {% endfor %} @@ -141,28 +144,22 @@ FastAPIには、様々なバックグラウンドの人々を歓迎する素晴 ### Individual Sponsors -{% if people %} -{% if people.sponsors_50 %} +{% if github_sponsors %} +{% for group in github_sponsors.sponsors %}
-{% for user in people.sponsors_50 %} + +{% for user in group %} +{% if user.login not in sponsors_badge.logins %} + +{% endif %} {% endfor %}
-{% endif %} -{% endif %} - -{% if people %} -
-{% for user in people.sponsors %} - - {% endfor %} - -
{% endif %} ## データについて - 技術詳細 diff --git a/docs/zh/docs/fastapi-people.md b/docs/zh/docs/fastapi-people.md index ea239e6ca..75651592d 100644 --- a/docs/zh/docs/fastapi-people.md +++ b/docs/zh/docs/fastapi-people.md @@ -114,25 +114,28 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋 他们主要通过GitHub Sponsors支持我在 **FastAPI** (和其他项目)的工作。 +{% if sponsors.gold %} + ### 金牌赞助商 -{% if sponsors %} {% for sponsor in sponsors.gold -%} {% endfor %} {% endif %} +{% if sponsors.silver %} + ### 银牌赞助商 -{% if sponsors %} {% for sponsor in sponsors.silver -%} {% endfor %} {% endif %} +{% if sponsors.bronze %} + ### 铜牌赞助商 -{% if sponsors %} {% for sponsor in sponsors.bronze -%} {% endfor %} @@ -140,28 +143,22 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋 ### 个人赞助 -{% if people %} -{% if people.sponsors_50 %} +{% if github_sponsors %} +{% for group in github_sponsors.sponsors %}
-{% for user in people.sponsors_50 %} + +{% for user in group %} +{% if user.login not in sponsors_badge.logins %} + +{% endif %} {% endfor %}
-{% endif %} -{% endif %} - -{% if people %} -
-{% for user in people.sponsors %} - - {% endfor %} - -
{% endif %} ## 关于数据 - 技术细节 From 3409c9e32ffe994c879c7ceb6acc2bc0c6f3b866 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 18 Aug 2021 09:48:18 +0000 Subject: [PATCH 169/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d0d442e9a..2da13ead6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Update computation of FastAPI People and sponsors. PR [#3714](https://github.com/tiangolo/fastapi/pull/3714) by [@tiangolo](https://github.com/tiangolo). * ✨ Enable recent Material for MkDocs Insiders features. PR [#3710](https://github.com/tiangolo/fastapi/pull/3710) by [@tiangolo](https://github.com/tiangolo). * 🔥 Remove/clean extra imports from examples in docs for features. PR [#3709](https://github.com/tiangolo/fastapi/pull/3709) by [@tiangolo](https://github.com/tiangolo). * ➕ Update docs library to include sources in Markdown. PR [#3648](https://github.com/tiangolo/fastapi/pull/3648) by [@tiangolo](https://github.com/tiangolo). From d0ced2c7c900efcefdc324c51814f07132ba0b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 18 Aug 2021 15:07:08 +0200 Subject: [PATCH 170/814] =?UTF-8?q?=E2=9C=A8=20Add=20GitHub=20Action:=20No?= =?UTF-8?q?tify=20Translations=20(#3715)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../actions/notify-translations/Dockerfile | 7 ++ .../actions/notify-translations/action.yml | 10 +++ .../actions/notify-translations/app/main.py | 87 +++++++++++++++++++ .../notify-translations/app/translations.yml | 12 +++ .github/workflows/notify-translations.yml | 21 +++++ 5 files changed, 137 insertions(+) create mode 100644 .github/actions/notify-translations/Dockerfile create mode 100644 .github/actions/notify-translations/action.yml create mode 100644 .github/actions/notify-translations/app/main.py create mode 100644 .github/actions/notify-translations/app/translations.yml create mode 100644 .github/workflows/notify-translations.yml diff --git a/.github/actions/notify-translations/Dockerfile b/.github/actions/notify-translations/Dockerfile new file mode 100644 index 000000000..fa4197e6a --- /dev/null +++ b/.github/actions/notify-translations/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.7 + +RUN pip install httpx PyGithub "pydantic==1.5.1" "pyyaml>=5.3.1,<6.0.0" + +COPY ./app /app + +CMD ["python", "/app/main.py"] diff --git a/.github/actions/notify-translations/action.yml b/.github/actions/notify-translations/action.yml new file mode 100644 index 000000000..c3579977c --- /dev/null +++ b/.github/actions/notify-translations/action.yml @@ -0,0 +1,10 @@ +name: "Notify Translations" +description: "Notify in the issue for a translation when there's a new PR available" +author: "Sebastián Ramírez " +inputs: + token: + description: 'Token, to read the GitHub API. Can be passed in using {{ secrets.GITHUB_TOKEN }}' + required: true +runs: + using: 'docker' + image: 'Dockerfile' diff --git a/.github/actions/notify-translations/app/main.py b/.github/actions/notify-translations/app/main.py new file mode 100644 index 000000000..79850513a --- /dev/null +++ b/.github/actions/notify-translations/app/main.py @@ -0,0 +1,87 @@ +import logging +from pathlib import Path +from typing import Dict, Optional + +import yaml +from github import Github +from pydantic import BaseModel, BaseSettings, SecretStr + +awaiting_label = "awaiting review" +lang_all_label = "lang-all" +approved_label = "approved-2" +translations_path = Path(__file__).parent / "translations.yml" + + +class Settings(BaseSettings): + github_repository: str + input_token: SecretStr + github_event_path: Path + github_event_name: Optional[str] = None + input_debug: Optional[bool] = False + + +class PartialGitHubEventIssue(BaseModel): + number: int + + +class PartialGitHubEvent(BaseModel): + pull_request: PartialGitHubEventIssue + + +if __name__ == "__main__": + settings = Settings() + if settings.input_debug: + logging.basicConfig(level=logging.DEBUG) + else: + logging.basicConfig(level=logging.INFO) + logging.debug(f"Using config: {settings.json()}") + g = Github(settings.input_token.get_secret_value()) + repo = g.get_repo(settings.github_repository) + if not settings.github_event_path.is_file(): + raise RuntimeError( + f"No github event file available at: {settings.github_event_path}" + ) + contents = settings.github_event_path.read_text() + github_event = PartialGitHubEvent.parse_raw(contents) + translations_map: Dict[str, int] = yaml.safe_load(translations_path.read_text()) + logging.debug(f"Using translations map: {translations_map}") + pr = repo.get_pull(github_event.pull_request.number) + logging.debug(f"Processing PR: {pr.number}") + if pr.state == "open": + logging.debug(f"PR is open: {pr.number}") + label_strs = set([label.name for label in pr.get_labels()]) + if lang_all_label in label_strs and awaiting_label in label_strs: + logging.info( + f"This PR seems to be a language translation and awaiting reviews: {pr.number}" + ) + if approved_label in label_strs: + message = ( + f"It seems this PR already has the approved label: {pr.number}" + ) + logging.error(message) + raise RuntimeError(message) + langs = [] + for label in label_strs: + if label.startswith("lang-") and not label == lang_all_label: + langs.append(label[5:]) + for lang in langs: + if lang in translations_map: + num = translations_map[lang] + logging.info(f"Found a translation issue for language: {lang} in issue: {num}") + issue = repo.get_issue(num) + message = f"Good news everyone! 😉 There's a new translation PR to be reviewed: #{pr.number} 🎉" + already_notified = False + logging.info(f"Checking current comments in issue: {num} to see if already notified about this PR: {pr.number}") + for comment in issue.get_comments(): + if message in comment.body: + already_notified = True + if not already_notified: + logging.info(f"Writing comment in issue: {num} about PR: {pr.number}") + issue.create_comment(message) + else: + logging.info(f"Issue: {num} was already notified of PR: {pr.number}") + else: + logging.info( + f"Changing labels in a closed PR doesn't trigger comments, PR: {pr.number}" + ) + logging.info("Finished") diff --git a/.github/actions/notify-translations/app/translations.yml b/.github/actions/notify-translations/app/translations.yml new file mode 100644 index 000000000..2ac955673 --- /dev/null +++ b/.github/actions/notify-translations/app/translations.yml @@ -0,0 +1,12 @@ +pt: 1211 +es: 1218 +zh: 1228 +ru: 1362 +it: 1556 +ja: 1572 +uk: 1748 +tr: 1892 +fr: 1972 +ko: 2017 +sq: 2041 +pl: 3169 diff --git a/.github/workflows/notify-translations.yml b/.github/workflows/notify-translations.yml new file mode 100644 index 000000000..7e414ab95 --- /dev/null +++ b/.github/workflows/notify-translations.yml @@ -0,0 +1,21 @@ +name: Notify Translations + +on: + pull_request_target: + types: + - labeled + +jobs: + notify-translations: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + # Allow debugging with tmate + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} + with: + limit-access-to-actor: true + - uses: ./.github/actions/notify-translations + with: + token: ${{ secrets.GITHUB_TOKEN }} From a23eaaeda897cdb429f26a4d1760713342051f1e Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 18 Aug 2021 13:07:50 +0000 Subject: [PATCH 171/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2da13ead6..5b023a036 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add GitHub Action: Notify Translations. PR [#3715](https://github.com/tiangolo/fastapi/pull/3715) by [@tiangolo](https://github.com/tiangolo). * ✨ Update computation of FastAPI People and sponsors. PR [#3714](https://github.com/tiangolo/fastapi/pull/3714) by [@tiangolo](https://github.com/tiangolo). * ✨ Enable recent Material for MkDocs Insiders features. PR [#3710](https://github.com/tiangolo/fastapi/pull/3710) by [@tiangolo](https://github.com/tiangolo). * 🔥 Remove/clean extra imports from examples in docs for features. PR [#3709](https://github.com/tiangolo/fastapi/pull/3709) by [@tiangolo](https://github.com/tiangolo). From cb5b4e1b7e0c4d8277dbbd72e9b24fe6bee945af Mon Sep 17 00:00:00 2001 From: Sam Courtemanche Date: Wed, 18 Aug 2021 15:19:43 +0200 Subject: [PATCH 172/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20docs/async.md=20(#3416)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jacquet Corentin Co-authored-by: Sebastián Ramírez --- docs/fr/docs/async.md | 394 ++++++++++++++++++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 395 insertions(+) create mode 100644 docs/fr/docs/async.md diff --git a/docs/fr/docs/async.md b/docs/fr/docs/async.md new file mode 100644 index 000000000..20f4ee101 --- /dev/null +++ b/docs/fr/docs/async.md @@ -0,0 +1,394 @@ +# Concurrence et les mots-clés async et await + +Cette page vise à fournir des détails sur la syntaxe `async def` pour les *fonctions de chemins* et quelques rappels sur le code asynchrone, la concurrence et le parallélisme. + +## Vous êtes pressés ? + +TL;DR : + +Si vous utilisez des bibliothèques tierces qui nécessitent d'être appelées avec `await`, telles que : + +```Python +results = await some_library() +``` +Alors, déclarez vos *fonctions de chemins* avec `async def` comme ceci : + +```Python hl_lines="2" +@app.get('/') +async def read_results(): + results = await some_library() + return results +``` + +!!! note + Vous pouvez uniquement utiliser `await` dans les fonctions créées avec `async def`. + +--- + +Si vous utilisez une bibliothèque externe qui communique avec quelque chose (une BDD, une API, un système de fichiers, etc.) et qui ne supporte pas l'utilisation d'`await` (ce qui est actuellement le cas pour la majorité des bibliothèques de BDD), alors déclarez vos *fonctions de chemin* normalement, avec le classique `def`, comme ceci : + +```Python hl_lines="2" +@app.get('/') +def results(): + results = some_library() + return results +``` + +--- + +Si votre application n'a pas à communiquer avec une bibliothèque externe et pas à attendre de réponse, utilisez `async def`. + +--- + +Si vous ne savez pas, utilisez seulement `def` comme vous le feriez habituellement. + +--- + +**Note** : vous pouvez mélanger `def` et `async def` dans vos *fonctions de chemin* autant que nécessaire, **FastAPI** saura faire ce qu'il faut avec. + +Au final, peu importe le cas parmi ceux ci-dessus, **FastAPI** fonctionnera de manière asynchrone et sera extrêmement rapide. + +Mais si vous suivez bien les instructions ci-dessus, alors **FastAPI** pourra effectuer quelques optimisations et ainsi améliorer les performances. + +## Détails techniques + +Les versions modernes de Python supportent le **code asynchrone** grâce aux **"coroutines"** avec les syntaxes **`async` et `await`**. + +Analysons les différentes parties de cette phrase dans les sections suivantes : + +* **Code asynchrone** +* **`async` et `await`** +* **Coroutines** + +## Code asynchrone + +Faire du code asynchrone signifie que le langage 💬 est capable de dire à l'ordinateur / au programme 🤖 qu'à un moment du code, il 🤖 devra attendre que *quelque chose d'autre* se termine autre part. Disons que ce *quelque chose d'autre* est appelé "fichier-lent" 📝. + +Donc, pendant ce temps, l'ordinateur pourra effectuer d'autres tâches, pendant que "fichier-lent" 📝 se termine. + +Ensuite l'ordinateur / le programme 🤖 reviendra à chaque fois qu'il en a la chance que ce soit parce qu'il attend à nouveau, ou car il 🤖 a fini tout le travail qu'il avait à faire. Il 🤖 regardera donc si les tâches qu'il attend ont terminé d'être effectuées. + +Ensuite, il 🤖 prendra la première tâche à finir (disons, notre "fichier-lent" 📝) et continuera à faire avec cette dernière ce qu'il était censé. + +Ce "attendre quelque chose d'autre" fait généralement référence à des opérations I/O qui sont relativement "lentes" (comparées à la vitesse du processeur et de la mémoire RAM) telles qu'attendre que : + +* de la donnée soit envoyée par le client à travers le réseau +* de la donnée envoyée depuis votre programme soit reçue par le client à travers le réseau +* le contenu d'un fichier sur le disque soit lu par le système et passé à votre programme +* le contenu que votre programme a passé au système soit écrit sur le disque +* une opération effectuée à distance par une API se termine +* une opération en BDD se termine +* une requête à une BDD renvoie un résultat +* etc. + +Le temps d'exécution étant consommé majoritairement par l'attente d'opérations I/O on appelle ceci des opérations "I/O bound". + +Ce concept se nomme l'"asynchronisme" car l'ordinateur / le programme n'a pas besoin d'être "synchronisé" avec la tâche, attendant le moment exact où cette dernière se terminera en ne faisant rien, pour être capable de récupérer le résultat de la tâche et l'utiliser dans la suite des opérations. + +À la place, en étant "asynchrone", une fois terminée, une tâche peut légèrement attendre (quelques microsecondes) que l'ordinateur / le programme finisse ce qu'il était en train de faire, et revienne récupérer le résultat. + +Pour parler de tâches "synchrones" (en opposition à "asynchrones"), on utilise souvent le terme "séquentiel", car l'ordinateur / le programme va effectuer toutes les étapes d'une tâche séquentiellement avant de passer à une autre tâche, même si ces étapes impliquent de l'attente. + +### Concurrence et Burgers + +L'idée de code **asynchrone** décrite ci-dessus est parfois aussi appelée **"concurrence"**. Ce qui est différent du **"parallélisme"**. + +La **concurrence** et le **parallélisme** sont tous deux liés à l'idée de "différentes choses arrivant plus ou moins au même moment". + +Mais les détails entre la **concurrence** et le **parallélisme** diffèrent sur de nombreux points. + +Pour expliquer la différence, voici une histoire de burgers : + +#### Burgers concurrents + +Vous amenez votre crush 😍 dans votre fast food 🍔 favori, et faites la queue pendant que le serveur 💁 prend les commandes des personnes devant vous. + +Puis vient votre tour, vous commandez alors 2 magnifiques burgers 🍔 pour votre crush 😍 et vous. + +Vous payez 💸. + +Le serveur 💁 dit quelque chose à son collègue dans la cuisine 👨‍🍳 pour qu'il sache qu'il doit préparer vos burgers 🍔 (bien qu'il soit déjà en train de préparer ceux des clients précédents). + +Le serveur 💁 vous donne le numéro assigné à votre commande. + +Pendant que vous attendez, vous allez choisir une table avec votre crush 😍, vous discutez avec votre crush 😍 pendant un long moment (les burgers étant "magnifiques" ils sont très longs à préparer ✨🍔✨). + +Pendant que vous êtes assis à table, en attendant que les burgers 🍔 soient prêts, vous pouvez passer ce temps à admirer à quel point votre crush 😍 est géniale, mignonne et intelligente ✨😍✨. + +Pendant que vous discutez avec votre crush 😍, de temps en temps vous jetez un coup d'oeil au nombre affiché au-dessus du comptoir pour savoir si c'est à votre tour d'être servis. + +Jusqu'au moment où c'est (enfin) votre tour. Vous allez au comptoir, récupérez vos burgers 🍔 et revenez à votre table. + +Vous et votre crush 😍 mangez les burgers 🍔 et passez un bon moment ✨. + +--- + +Imaginez que vous êtes l'ordinateur / le programme 🤖 dans cette histoire. + +Pendant que vous faites la queue, vous être simplement inactif 😴, attendant votre tour, ne faisant rien de "productif". Mais la queue est rapide car le serveur 💁 prend seulement les commandes (et ne les prépare pas), donc tout va bien. + +Ensuite, quand c'est votre tour, vous faites des actions "productives" 🤓, vous étudiez le menu, décidez ce que vous voulez, demandez à votre crush 😍 son choix, payez 💸, vérifiez que vous utilisez la bonne carte de crédit, vérifiez que le montant débité sur la carte est correct, vérifiez que la commande contient les bons produits, etc. + +Mais ensuite, même si vous n'avez pas encore vos burgers 🍔, votre travail avec le serveur 💁 est "en pause" ⏸, car vous devez attendre 🕙 que vos burgers soient prêts. + +Après vous être écarté du comptoir et vous être assis à votre table avec le numéro de votre commande, vous pouvez tourner 🔀 votre attention vers votre crush 😍, et "travailler" ⏯ 🤓 là-dessus. Vous êtes donc à nouveau en train de faire quelque chose de "productif" 🤓, vous flirtez avec votre crush 😍. + +Puis le serveur 💁 dit "J'ai fini de préparer les burgers" 🍔 en mettant votre numéro sur l'affichage du comptoir, mais vous ne courrez pas immédiatement au moment où votre numéro s'affiche. Vous savez que personne ne volera vos burgers 🍔 car vous avez votre numéro et les autres clients ont le leur. + +Vous attendez donc que votre crush 😍 finisse son histoire, souriez gentiment et dites que vous allez chercher les burgers ⏸. + +Pour finir vous allez au comptoir 🔀, vers la tâche initiale qui est désormais terminée ⏯, récupérez les burgers 🍔, remerciez le serveur et ramenez les burgers 🍔 à votre table. Ceci termine l'étape / la tâche d'interaction avec le comptoir ⏹. Ce qui ensuite, crée une nouvelle tâche de "manger les burgers" 🔀 ⏯, mais la précédente, "récupérer les burgers" est terminée ⏹. + +#### Burgers parallèles + +Imaginons désormais que ce ne sont pas des "burgers concurrents" mais des "burgers parallèles". + +Vous allez avec votre crush 😍 dans un fast food 🍔 parallélisé. + +Vous attendez pendant que plusieurs (disons 8) serveurs qui sont aussi des cuisiniers 👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳 prennent les commandes des personnes devant vous. + +Chaque personne devant vous attend 🕙 que son burger 🍔 soit prêt avant de quitter le comptoir car chacun des 8 serveurs va lui-même préparer le burger directement avant de prendre la commande suivante. + +Puis c'est enfin votre tour, vous commandez 2 magnifiques burgers 🍔 pour vous et votre crush 😍. + +Vous payez 💸. + +Le serveur va dans la cuisine 👨‍🍳. + +Vous attendez devant le comptoir afin que personne ne prenne vos burgers 🍔 avant vous, vu qu'il n'y a pas de numéro de commande. + +Vous et votre crush 😍 étant occupés à vérifier que personne ne passe devant vous prendre vos burgers au moment où ils arriveront 🕙, vous ne pouvez pas vous préoccuper de votre crush 😞. + +C'est du travail "synchrone", vous être "synchronisés" avec le serveur/cuisinier 👨‍🍳. Vous devez attendre 🕙 et être présent au moment exact où le serveur/cuisinier 👨‍🍳 finira les burgers 🍔 et vous les donnera, sinon quelqu'un risque de vous les prendre. + +Puis le serveur/cuisinier 👨‍🍳 revient enfin avec vos burgers 🍔, après un long moment d'attente 🕙 devant le comptoir. + +Vous prenez vos burgers 🍔 et allez à une table avec votre crush 😍 + +Vous les mangez, et vous avez terminé 🍔 ⏹. + +Durant tout ce processus, il n'y a presque pas eu de discussions ou de flirts car la plupart de votre temps à été passé à attendre 🕙 devant le comptoir 😞. + +--- + +Dans ce scénario de burgers parallèles, vous êtes un ordinateur / programme 🤖 avec deux processeurs (vous et votre crush 😍) attendant 🕙 à deux et dédiant votre attention 🕙 à "attendre devant le comptoir" pour une longue durée. + +Le fast-food a 8 processeurs (serveurs/cuisiniers) 👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳. Alors que le fast-food de burgers concurrents en avait 2 (un serveur et un cuisinier). + +Et pourtant l'expérience finale n'est pas meilleure 😞. + +--- + +C'est donc l'histoire équivalente parallèle pour les burgers 🍔. + +Pour un exemple plus courant dans la "vie réelle", imaginez une banque. + +Jusqu'à récemment, la plupart des banques avaient plusieurs caisses (et banquiers) 👨‍💼👨‍💼👨‍💼👨‍💼 et une unique file d'attente 🕙🕙🕙🕙🕙🕙🕙🕙. + +Tous les banquiers faisaient l'intégralité du travail avec chaque client avant de passer au suivant 👨‍💼⏯. + +Et vous deviez attendre 🕙 dans la file pendant un long moment ou vous perdiez votre place. + +Vous n'auriez donc probablement pas envie d'amener votre crush 😍 avec vous à la banque 🏦. + +#### Conclusion + +Dans ce scénario des "burgers du fast-food avec votre crush", comme il y a beaucoup d'attente 🕙, il est très logique d'avoir un système concurrent ⏸🔀⏯. + +Et c'est le cas pour la plupart des applications web. + +Vous aurez de nombreux, nombreux utilisateurs, mais votre serveur attendra 🕙 que leur connexion peu performante envoie des requêtes. + +Puis vous attendrez 🕙 de nouveau que leurs réponses reviennent. + +Cette "attente" 🕙 se mesure en microsecondes, mais tout de même, en cumulé cela fait beaucoup d'attente. + +C'est pourquoi il est logique d'utiliser du code asynchrone ⏸🔀⏯ pour des APIs web. + +La plupart des frameworks Python existants (y compris Flask et Django) ont été créés avant que les nouvelles fonctionnalités asynchrones de Python n'existent. Donc, les façons dont ils peuvent être déployés supportent l'exécution parallèle et une ancienne forme d'exécution asynchrone qui n'est pas aussi puissante que les nouvelles fonctionnalités de Python. + +Et cela, bien que les spécifications principales du web asynchrone en Python (ou ASGI) ont été développées chez Django, pour ajouter le support des WebSockets. + +Ce type d'asynchronicité est ce qui a rendu NodeJS populaire (bien que NodeJS ne soit pas parallèle) et c'est la force du Go en tant que langage de programmation. + +Et c'est le même niveau de performance que celui obtenu avec **FastAPI**. + +Et comme on peut avoir du parallélisme et de l'asynchronicité en même temps, on obtient des performances plus hautes que la plupart des frameworks NodeJS et égales à celles du Go, qui est un langage compilé plus proche du C (tout ça grâce à Starlette). + +### Est-ce que la concurrence est mieux que le parallélisme ? + +Nope ! C'est ça la morale de l'histoire. + +La concurrence est différente du parallélisme. C'est mieux sur des scénarios **spécifiques** qui impliquent beaucoup d'attente. À cause de ça, c'est généralement bien meilleur que le parallélisme pour le développement d'applications web. Mais pas pour tout. + +Donc pour équilibrer tout ça, imaginez l'histoire suivante : + +> Vous devez nettoyer une grande et sale maison. + +*Oui, c'est toute l'histoire*. + +--- + +Il n'y a plus d'attente 🕙 nulle part, juste beaucoup de travail à effectuer, dans différentes pièces de la maison. + +Vous pourriez diviser en différentes sections comme avec les burgers, d'abord le salon, puis la cuisine, etc. Mais vous n'attendez 🕙 rien, vous ne faites que nettoyer et nettoyer, la séparation en sections ne changerait rien au final. + +Cela prendrait autant de temps pour finir avec ou sans sections (concurrence) et vous auriez effectué la même quantité de travail. + +Mais dans ce cas, si pouviez amener 8 ex-serveurs/cuisiniers/devenus-nettoyeurs 👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳, et que chacun d'eux (plus vous) pouvait prendre une zone de la maison pour la nettoyer, vous pourriez faire tout le travail en parallèle, et finir plus tôt. + +Dans ce scénario, chacun des nettoyeurs (vous y compris) serait un processeur, faisant sa partie du travail. + +Et comme la plupart du temps d'exécution est pris par du "vrai" travail (et non de l'attente), et que le travail dans un ordinateur est fait par un CPU, ce sont des problèmes dits "CPU bound". + +--- + +Des exemples communs d'opérations "CPU bounds" sont les procédés qui requièrent des traitements mathématiques complexes. + +Par exemple : + +* Traitements d'**audio** et d'**images**. +* La **vision par ordinateur** : une image est composée de millions de pixels, chaque pixel ayant 3 valeurs / couleurs, les traiter tous va nécessiter d'effectuer des traitements sur chaque pixel, et de préférence tous en même temps. +* L'apprentissage automatique (ou **Machine Learning**) : cela nécessite de nombreuses multiplications de matrices et vecteurs. Imaginez une énorme feuille de calcul remplie de nombres que vous multiplierez entre eux tous au même moment. +* L'apprentissage profond (ou **Deep Learning**) : est un sous-domaine du **Machine Learning**, donc les mêmes raisons s'appliquent. Avec la différence qu'il n'y a pas une unique feuille de calcul de nombres à multiplier, mais une énorme quantité d'entre elles, et dans de nombreux cas, on utilise un processeur spécial pour construire et / ou utiliser ces modèles. + +### Concurrence + Parallélisme : Web + Machine Learning + +Avec **FastAPI** vous pouvez bénéficier de la concurrence qui est très courante en developement web (c'est l'attrait principal de NodeJS). + +Mais vous pouvez aussi profiter du parallélisme et multiprocessing afin de gérer des charges **CPU bound** qui sont récurrentes dans les systèmes de *Machine Learning*. + +Ça, ajouté au fait que Python soit le langage le plus populaire pour la **Data Science**, le **Machine Learning** et surtout le **Deep Learning**, font de **FastAPI** un très bon choix pour les APIs et applications de **Data Science** / **Machine Learning**. + +Pour comprendre comment mettre en place ce parallélisme en production, allez lire la section [Déploiement](deployment/index.md){.internal-link target=_blank}. + +## `async` et `await` + +Les versions modernes de Python ont une manière très intuitive de définir le code asynchrone, tout en gardant une apparence de code "séquentiel" classique en laissant Python faire l'attente pour vous au bon moment. + +Pour une opération qui nécessite de l'attente avant de donner un résultat et qui supporte ces nouvelles fonctionnalités Python, vous pouvez l'utiliser comme tel : + +```Python +burgers = await get_burgers(2) +``` + +Le mot-clé important ici est `await`. Il informe Python qu'il faut attendre ⏸ que `get_burgers(2)` finisse d'effectuer ses opérations 🕙 avant de stocker les résultats dans la variable `burgers`. Grâce à cela, Python saura qu'il peut aller effectuer d'autres opérations 🔀 ⏯ pendant ce temps (comme par exemple recevoir une autre requête). + +Pour que `await` fonctionne, il doit être placé dans une fonction qui supporte l'asynchronicité. Pour que ça soit le cas, il faut déclarer cette dernière avec `async def` : + +```Python hl_lines="1" +async def get_burgers(number: int): + # Opérations asynchrones pour créer les burgers + return burgers +``` + +...et non `def` : + +```Python hl_lines="2" +# Ceci n'est pas asynchrone +def get_sequential_burgers(number: int): + # Opérations asynchrones pour créer les burgers + return burgers +``` + +Avec `async def`, Python sait que dans cette fonction il doit prendre en compte les expressions `await`, et qu'il peut mettre en pause ⏸ l'exécution de la fonction pour aller faire autre chose 🔀 avant de revenir. + +Pour appeler une fonction définie avec `async def`, vous devez utiliser `await`. Donc ceci ne marche pas : + +```Python +# Ceci ne fonctionne pas, car get_burgers a été défini avec async def +burgers = get_burgers(2) +``` + +--- + +Donc, si vous utilisez une bibliothèque qui nécessite que ses fonctions soient appelées avec `await`, vous devez définir la *fonction de chemin* en utilisant `async def` comme dans : + +```Python hl_lines="2-3" +@app.get('/burgers') +async def read_burgers(): + burgers = await get_burgers(2) + return burgers +``` + +### Plus de détails techniques + +Vous avez donc compris que `await` peut seulement être utilisé dans des fonctions définies avec `async def`. + +Mais en même temps, les fonctions définies avec `async def` doivent être appelées avec `await` et donc dans des fonctions définies elles aussi avec `async def`. + +Vous avez donc remarqué ce paradoxe d'oeuf et de la poule, comment appelle-t-on la première fonction `async` ? + +Si vous utilisez **FastAPI**, pas besoin de vous en inquiéter, car cette "première" fonction sera votre *fonction de chemin* ; et **FastAPI** saura comment arriver au résultat attendu. + +Mais si vous utilisez `async` / `await` sans **FastAPI**, allez jetez un coup d'oeil à la documentation officielle de Python. + +### Autres formes de code asynchrone + +L'utilisation d'`async` et `await` est relativement nouvelle dans ce langage. + +Mais cela rend la programmation asynchrone bien plus simple. + +Cette même syntaxe (ou presque) était aussi incluse dans les versions modernes de Javascript (dans les versions navigateur et NodeJS). + +Mais avant ça, gérer du code asynchrone était bien plus complexe et difficile. + +Dans les versions précédentes de Python, vous auriez utilisé des *threads* ou Gevent. Mais le code aurait été bien plus difficile à comprendre, débugger, et concevoir. + +Dans les versions précédentes de Javascript NodeJS / Navigateur, vous auriez utilisé des "callbacks". Menant potentiellement à ce que l'on appelle le "callback hell". + + +## Coroutines + +**Coroutine** est juste un terme élaboré pour désigner ce qui est retourné par une fonction définie avec `async def`. Python sait que c'est comme une fonction classique qui va démarrer à un moment et terminer à un autre, mais qu'elle peut aussi être mise en pause ⏸, du moment qu'il y a un `await` dans son contenu. + +Mais toutes ces fonctionnalités d'utilisation de code asynchrone avec `async` et `await` sont souvent résumées comme l'utilisation des *coroutines*. On peut comparer cela à la principale fonctionnalité clé de Go, les "Goroutines". + +## Conclusion + +Reprenons la phrase du début de la page : + +> Les versions modernes de Python supportent le **code asynchrone** grâce aux **"coroutines"** avec les syntaxes **`async` et `await`**. + +Ceci devrait être plus compréhensible désormais. ✨ + +Tout ceci est donc ce qui donne sa force à **FastAPI** (à travers Starlette) et lui permet d'avoir des performances aussi impressionnantes. + +## Détails très techniques + +!!! warning "Attention !" + Vous pouvez probablement ignorer cela. + + Ce sont des détails très poussés sur comment **FastAPI** fonctionne en arrière-plan. + + Si vous avez de bonnes connaissances techniques (coroutines, threads, code bloquant, etc.) et êtes curieux de comment **FastAPI** gère `async def` versus le `def` classique, cette partie est faite pour vous. + +### Fonctions de chemin + +Quand vous déclarez une *fonction de chemin* avec un `def` normal et non `async def`, elle est exécutée dans un groupe de threads (threadpool) externe qui est ensuite attendu, plutôt que d'être appelée directement (car cela bloquerait le serveur). + +Si vous venez d'un autre framework asynchrone qui ne fonctionne pas comme de la façon décrite ci-dessus et que vous êtes habitués à définir des *fonctions de chemin* basiques avec un simple `def` pour un faible gain de performance (environ 100 nanosecondes), veuillez noter que dans **FastAPI**, l'effet serait plutôt contraire. Dans ces cas-là, il vaut mieux utiliser `async def` à moins que votre *fonction de chemin* utilise du code qui effectue des opérations I/O bloquantes. + +Au final, dans les deux situations, il est fort probable que **FastAPI** soit tout de même [plus rapide](/#performance){.internal-link target=_blank} que (ou au moins de vitesse égale à) votre framework précédent. + +### Dépendances + +La même chose s'applique aux dépendances. Si une dépendance est définie avec `def` plutôt que `async def`, elle est exécutée dans la threadpool externe. + +### Sous-dépendances + +Vous pouvez avoir de multiples dépendances et sous-dépendances dépendant les unes des autres (en tant que paramètres de la définition de la *fonction de chemin*), certaines créées avec `async def` et d'autres avec `def`. Cela fonctionnerait aussi, et celles définies avec un simple `def` seraient exécutées sur un thread externe (venant de la threadpool) plutôt que d'être "attendues". + +### Autres fonctions utilitaires + +Toute autre fonction utilitaire que vous appelez directement peut être créée avec un classique `def` ou avec `async def` et **FastAPI** n'aura pas d'impact sur la façon dont vous l'appelez. + +Contrairement aux fonctions que **FastAPI** appelle pour vous : les *fonctions de chemin* et dépendances. + +Si votre fonction utilitaire est une fonction classique définie avec `def`, elle sera appelée directement (telle qu'écrite dans votre code), pas dans une threadpool, si la fonction est définie avec `async def` alors vous devrez attendre (avec `await`) que cette fonction se termine avant de passer à la suite du code. + +--- + +Encore une fois, ce sont des détails très techniques qui peuvent être utiles si vous venez ici les chercher. + +Sinon, les instructions de la section Vous êtes pressés ? ci-dessus sont largement suffisantes. diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index e9819b458..4891a29ca 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -59,6 +59,7 @@ nav: - python-types.md - Tutoriel - Guide utilisateur: - tutorial/background-tasks.md +- async.md - project-generation.md - alternatives.md - external-links.md From 326837443f87365c6432fb2a3f663d106bd4e0fa Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 18 Aug 2021 13:20:25 +0000 Subject: [PATCH 173/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5b023a036..038011778 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for `docs/async.md`. PR [#3416](https://github.com/tiangolo/fastapi/pull/3416) by [@Smlep](https://github.com/Smlep). * ✨ Add GitHub Action: Notify Translations. PR [#3715](https://github.com/tiangolo/fastapi/pull/3715) by [@tiangolo](https://github.com/tiangolo). * ✨ Update computation of FastAPI People and sponsors. PR [#3714](https://github.com/tiangolo/fastapi/pull/3714) by [@tiangolo](https://github.com/tiangolo). * ✨ Enable recent Material for MkDocs Insiders features. PR [#3710](https://github.com/tiangolo/fastapi/pull/3710) by [@tiangolo](https://github.com/tiangolo). From dda105c50d46682907745645022c67727e7b41a9 Mon Sep 17 00:00:00 2001 From: Fabio Serrao Date: Wed, 18 Aug 2021 10:24:21 -0300 Subject: [PATCH 174/814] =?UTF-8?q?=F0=9F=8C=90=20Portuguese=20translation?= =?UTF-8?q?=20of=20`docs/async.md`=20(#1330)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lucas <61513630+lsglucas@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/pt/docs/async.md | 394 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 394 insertions(+) create mode 100644 docs/pt/docs/async.md diff --git a/docs/pt/docs/async.md b/docs/pt/docs/async.md new file mode 100644 index 000000000..44f4b5148 --- /dev/null +++ b/docs/pt/docs/async.md @@ -0,0 +1,394 @@ +# Concorrência e async / await + +Detalhes sobre a sintaxe `async def` para *funções de operação de rota* e alguns conceitos de código assíncrono, concorrência e paralelismo. + +## Com pressa? + +TL;DR: + +Se você estiver utilizando bibliotecas de terceiros que dizem para você chamar as funções com `await`, como: + +```Python +results = await some_library() +``` + +Então, declare sua *função de operação de rota* com `async def` como: + +```Python hl_lines="2" +@app.get('/') +async def read_results(): + results = await some_library() + return results +``` + +!!! note + Você só pode usar `await` dentro de funções criadas com `async def`. + +--- + +Se você está usando biblioteca de terceiros que se comunica com alguma coisa (um banco de dados, uma API, sistema de arquivos etc) e não tem suporte para utilizar `await` (esse é atualmente o caso para a maioria das bibliotecas de banco de dados), então declare suas *funções de operação de rota* normalmente, com apenas `def`, como: + +```Python hl_lines="2" +@app.get('/') +def results(): + results = some_library() + return results +``` + +--- + +Se sua aplicação (de alguma forma) não tem que se comunicar com nada mais e tem que esperar que o respondam, use `async def`. + +--- + +Se você simplesmente não sabe, use apenas `def`. + +--- + +**Note**: Você pode misturar `def` e `async def` nas suas *funções de operação de rota* tanto quanto necessário e definir cada função usando a melhor opção para você. FastAPI irá fazer a coisa certa com elas. + +De qualquer forma, em ambos os casos acima, FastAPI irá trabalhar assincronamente e ser extremamente rápido. + +Seguindo os passos acima, ele será capaz de fazer algumas otimizações de performance. + +## Detalhes Técnicos + +Versões modernas de Python tem suporte para **"código assíncrono"** usando algo chamado **"corrotinas"**, com sintaxe **`async` e `await`**. + +Vamos ver aquela frase por partes na seção abaixo: + +* **Código assíncrono** +* **`async` e `await`** +* **Corrotinas** + +## Código assíncrono + +Código assíncrono apenas significa que a linguagem 💬 tem um jeito de dizer para o computador / programa 🤖 que em certo ponto, ele 🤖 terá que esperar por *algo* para finalizar em outro lugar. Vamos dizer que esse *algo* seja chamado "arquivo lento" 📝. + +Então, durante esse tempo, o computador pode ir e fazer outro trabalho, enquanto o "arquivo lento" 📝 termine. + +Então o computador / programa 🤖 irá voltar toda hora que tiver uma chance porquê ele ainda está esperando o "arquivo lento", ou ele 🤖 nunca irá terminar todo o trabalho que tem até esse ponto. E ele 🤖 irá ver se alguma das tarefas que estava esperando já terminaram, fazendo o que quer que tinham que fazer. + +Depois, ele 🤖 pega a primeira tarefa para finalizar (vamos dizer, nosso "arquivo lento" 📝) e continua o que ele tem que fazer com isso. + +Esse "esperar por algo" normalmente se refere a operações I/O que são relativamente "lentas" (comparadas a velocidade do processador e da memória RAM), como esperar por: + +* dados do cliente para serem enviados através da rede +* dados enviados pelo seu programa para serem recebidos pelo clente através da rede +* conteúdo de um arquivo no disco pra ser lido pelo sistema e entregar ao seu programa +* conteúdo que seu programa deu ao sistema para ser escrito no disco +* uma operação remota API +* uma operação no banco de dados para finalizar +* uma solicitação no banco de dados esperando o retorno do resultado +* etc. + +Enquanto o tempo de execução é consumido mais pela espera das operações I/O, essas operações são chamadas de operações "limitadas por I/O". + +Isso é chamado de "assíncrono" porquê o computador / programa não tem que ser "sincronizado" com a tarefa lenta, esperando pelo exato momento que a tarefa finalize, enquanto não faz nada, para ser capaz de pegar o resultado da tarefa e dar continuidade ao trabalho. + +Ao invés disso, sendo um sistema "assíncrono", uma vez finalizada, a tarefa pode esperar um pouco (alguns microssegundos) para que o computador / programa finalize o que quer que esteja fazendo,e então volte para pegar o resultado e continue trabalhando com ele. + +Para "síncrono" (contrário de "assíncrono") também é utilizado o termo "sequencial", porquê o computador / programa segue todos os passos, na sequência, antes de trocar para uma tarefa diferente, mesmo se alguns passos envolvam esperar. + +### Concorrência e hambúrgueres + +Essa idéia de código **assíncrono** descrito acima é algo às vezes chamado de **"concorrência"**. E é diferente de **"paralelismo"**. + +**Concorrência** e **paralelismo** ambos são relacionados a "diferentes coisas acontecendo mais ou menos ao mesmo tempo". + +Mas os detalhes entre *concorrência* e *paralelismo* são bem diferentes. + +Para ver essa diferença, imagine a seguinte história sobre hambúrgueres: + +### Hambúrgueres concorrentes + +Você vai com seu _crush_ :heart_eyes: na lanchonete, fica na fila enquanto o caixa pega os pedidos das pessoas na sua frente. + +Então chega a sua vez, você pede dois saborosos hambúrgueres para você e seu _crush_ :heart_eyes:. + +Você paga. + +O caixa diz alguma coisa para o cara na cozinha para que ele tenha que preparar seus hambúrgueres (mesmo embora ele esteja preparando os lanches dos outros clientes). + +O caixa te entrega seu número de chamada. + +Enquanto você espera, você vai com seu _crush_ :heart_eyes: e pega uma mesa, senta e conversa com seu _crush_ :heart_eyes: por um bom tempo (como seus hambúrgueres são muito saborosos, leva um tempo para serem preparados). + +Enquanto você está sentado na mesa com seu _crush_ :heart_eyes:, esperando os hambúrgueres, você pode gastar o tempo admirando como lindo, maravilhoso e esperto é seu _crush_ :heart_eyes:. + +Enquanto espera e conversa com seu _crush_ :heart_eyes:, de tempos em tempos, você verifica o número de chamada exibido no balcão para ver se já é sua vez. + +Então a certo ponto, é finalmente sua vez. Você vai no balcão, pega seus hambúrgueres e volta para a mesa. + +Você e seu _crush_ :heart_eyes: comem os hambúrgueres e aproveitam o tempo. + +--- + +Imagine que você seja o computador / programa nessa história. + +Enquanto você está na fila, tranquilo, esperando por sua vez, não está fazendo nada "produtivo". Mas a fila é rápida porquê o caixa só está pegando os pedidos, então está tudo bem. + +Então, quando é sua vez, você faz o trabalho "produtivo" de verdade, você processa o menu, decide o que quer, pega a escolha de seu _crush_ :heart_eyes:, paga, verifica se entregou o valor correto em dinheiro ou cartão de crédito, verifica se foi cobrado corretamente, verifica se seu pedido está correto etc. + +Mas então, embora você ainda não tenha os hambúrgueres, seu trabalho no caixa está "pausado", porquê você tem que esperar seus hambúrgueres estarem prontos. + +Mas enquanto você se afasta do balcão e senta na mesa com o número da sua chamada, você pode trocar sua atenção para seu _crush_ :heart_eyes:, e "trabalhar" nisso. Então você está novamente fazendo algo muito "produtivo", como flertar com seu _crush_ :heart_eyes:. + +Então o caixa diz que "seus hambúrgueres estão prontos" colocando seu número no balcão, mas você não corre que nem um maluco imediatamente quando o número exibido é o seu. Você sabe que ninguém irá roubar seus hambúrgueres porquê você tem o número de chamada, e os outros tem os números deles. + +Então você espera que seu _crush_ :heart_eyes: termine a história que estava contando (terminar o trabalho atual / tarefa sendo processada), sorri gentilmente e diz que você está indo buscar os hambúrgueres. + +Então você vai no balcão, para a tarefa inicial que agora está finalizada, pega os hambúrgueres, e leva para a mesa. Isso finaliza esse passo / tarefa da interação com o balcão. Agora é criada uma nova tarefa, "comer hambúrgueres", mas a tarefa anterior, "pegar os hambúrgueres" já está finalizada. + +### Hambúrgueres paralelos + +Você vai com seu _crush_ :heart_eyes: em uma lanchonete paralela. + +Você fica na fila enquanto alguns (vamos dizer 8) caixas pegam os pedidos das pessoas na sua frente. + +Todo mundo antes de você está esperando pelos hambúrgueres estarem prontos antes de deixar o caixa porquê cada um dos 8 caixas vai e prepara o hambúrguer antes de pegar o próximo pedido. + +Então é finalmente sua vez, e pede 2 hambúrgueres muito saborosos para você e seu _crush_ :heart_eyes:. + +Você paga. + +O caixa vai para a cozinha. + +Você espera, na frente do balcão, para que ninguém pegue seus hambúrgueres antes de você, já que não tem números de chamadas. + +Enquanto você e seu _crush_ :heart_eyes: estão ocupados não permitindo que ninguém passe a frente e pegue seus hambúrgueres assim que estiverem prontos, você não pode dar atenção ao seu _crush_ :heart_eyes:. + +Isso é trabalho "síncrono", você está "sincronizado" com o caixa / cozinheiro. Você tem que esperar e estar lá no exato momento que o caixa / cozinheiro terminar os hambúrgueres e dá-los a você, ou então, outro alguém pode pegá-los. + +Então seu caixa / cozinheiro finalmente volta com seus hambúrgueres, depois de um longo tempo esperando por eles em frente ao balcão. + +Você pega seus hambúrgueres e vai para a mesa com seu _crush_ :heart_eyes:. + +Vocês comem os hambúrgueres, e o trabalho está terminado. + +Não houve muita conversa ou flerte já que a maior parte do tempo foi gasto esperando os lanches na frente do balcão. + +--- + +Nesse cenário dos hambúrgueres paralelos, você é um computador / programa com dois processadores (você e seu _crush_ :heart_eyes:), ambos esperando e dedicando a atenção de estar "esperando no balcão" por um bom tempo. + +A lanchonete paralela tem 8 processadores (caixas / cozinheiros). Enquanto a lanchonete dos hambúrgueres concorrentes tinham apenas 2 (um caixa e um cozinheiro). + +Ainda assim, a última experiência não foi a melhor. + +--- + +Essa poderia ser a história paralela equivalente aos hambúrgueres. + +Para um exemplo "mais real", imagine um banco. + +Até recentemente, a maioria dos bancos tinha muitos caixas e uma grande fila. + +Todos os caixas fazendo todo o trabalho, um cliente após o outro. + +E você tinha que esperar na fila por um longo tempo ou poderia perder a vez. + +Você provavelmente não gostaria de levar seu _crush_ :heart_eyes: com você para um rolezinho no banco. + +### Conclusão dos hambúrgueres + +Nesse cenário dos "hambúrgueres com seu _crush_ :heart_eyes:", como tem muita espera, faz mais sentido ter um sistema concorrente. + +Esse é o caso da maioria das aplicações web. + +Geralmente são muitos usuários, e seu servidor está esperando pelas suas conexões não tão boas para enviar as requisições. + +E então esperando novamente pelas respostas voltarem. + +Essa "espera" é medida em microssegundos, e ainda assim, somando tudo, é um monte de espera no final. + +Por isso que faz muito mais sentido utilizar código assíncrono para APIs web. + +A maioria dos frameworks Python existentes mais populares (incluindo Flask e Django) foram criados antes que os novos recursos assíncronos existissem em Python. Então, os meios que eles podem ser colocados em produção para suportar execução paralela mais a forma antiga de execução assíncrona não são tão poderosos quanto as novas capacidades. + +Mesmo embora a especificação principal para web assíncrono em Python (ASGI) foi desenvolvida no Django, para adicionar suporte para WebSockets. + +Esse tipo de assincronicidade é o que fez NodeJS popular (embora NodeJS não seja paralelo) e que essa seja a força do Go como uma linguagem de programa. + +E esse é o mesmo nível de performance que você tem com o **FastAPI**. + +E como você pode ter paralelismo e sincronicidade ao mesmo tempo, você tem uma maior performance do que a maioria dos frameworks NodeJS testados e lado a lado com Go, que é uma linguagem compilada próxima ao C (tudo graças ao Starlette). + +### Concorrência é melhor que paralelismo? + +Não! Essa não é a moral da história. + +Concorrência é diferente de paralelismo. E é melhor em cenários **específicos** que envolvam um monte de espera. Por isso, geralmente é muito melhor do que paralelismo para desenvolvimento de aplicações web. Mas não para tudo. + +Então, para equilibrar tudo, imagine a seguinte historinha: + +> Você tem que limpar uma grande casa suja. + +*Sim, essa é toda a história*. + +--- + +Não há espera em lugar algum, apenas um monte de trabalho para ser feito, em múltiplos cômodos da casa. + +Você poderia ter chamadas como no exemplo dos hambúrgueres, primeiro a sala de estar, então a cozinha, mas você não está esperando por nada, apenas limpar e limpar, as chamadas não afetariam em nada. + +Levaria o mesmo tempo para finalizar com ou sem chamadas (concorrência) e você teria feito o mesmo tanto de trabalho. + +Mas nesse caso, se você trouxesse os 8 ex-caixas / cozinheiros / agora-faxineiros, e cada um deles (mais você) pudessem dividir a casa para limpá-la, vocês fariam toda a limpeza em **paralelo**, com a ajuda extra, e terminariam muito mais cedo. + +Nesse cenário, cada um dos faxineiros (incluindo você) poderia ser um processador, fazendo a sua parte do trabalho. + +E a maior parte do tempo de execução é tomada por trabalho (ao invés de ficar esperando), e o trabalho em um computador é feito pela CPU, que podem gerar problemas que são chamados de "limite de CPU". + +--- + +Exemplos comuns de limite de CPU são coisas que exigem processamento matemático complexo. + +Por exemplo: + +* **Processamento de áudio** ou **imagem** +* **Visão do Computador**: uma imagem é composta por milhões de pixels, cada pixel tem 3 valores (cores, processamento que normalmente exige alguma computação em todos esses pixels ao mesmo tempo) + +* **Machine Learning**: Normalmente exige muita multiplicação de matrizes e vetores. Pense numa grande folha de papel com números e multiplicando todos eles juntos e ao mesmo tempo. + +* **Deep Learning**: Esse é um subcampo do Machine Learning, então o mesmo se aplica. A diferença é que não há apenas uma grande folha de papel com números para multiplicar, mas um grande conjunto de folhas de papel, e em muitos casos, você utiliza um processador especial para construir e/ou usar modelos. + +### Concorrência + Paralelismo: Web + Machine learning + +Com **FastAPI** você pode levar a vantagem da concorrência que é muito comum para desenvolvimento web (o mesmo atrativo de NodeJS). + +Mas você também pode explorar os benefícios do paralelismo e multiprocessamento (tendo múltiplos processadores rodando em paralelo) para trabalhos pesados que geram **limite de CPU** como aqueles em sistemas de Machine Learning. + +Isso, mais o simples fato que Python é a principal linguagem para **Data Science**, Machine Learning e especialmente Deep Learning, faz do FastAPI uma ótima escolha para APIs web e aplicações com Data Science / Machine Learning (entre muitas outras). + +Para ver como alcançar esse paralelismo em produção veja a seção sobre [Deployment](deployment.md){.internal-link target=_blank}. + +## `async` e `await` + +Versões modernas do Python tem um modo muito intuitivo para definir código assíncrono. Isso faz parecer normal o código "sequencial" e fazer o "esperar" para você nos momentos certos. + +Quando tem uma operação que exigirá espera antes de dar os resultados e tem suporte para esses recursos Python, você pode escrever assim: + +```Python +burgers = await get_burgers(2) +``` + +A chave aqui é o `await`. Ele diz ao Python que ele tem que esperar por `get_burgers(2)` para finalizar suas coisas antes de armazenar os resultados em `burgers`. Com isso, o Python saberá que ele pode ir e fazer outras coisas nesse meio tempo (como receber outra requisição). + +Para o `await` funcionar, tem que estar dentro de uma função que suporte essa assincronicidade. Para fazer isso, apenas declare a função com `async def`: + +```Python hl_lines="1" +async def get_burgers(number: int): + # Fazer alguma coisa assíncrona para criar os hambúrgueres + return burgers +``` + +...ao invés de `def`: + +```Python hl_lines="2" +# Isso não é assíncrono +def get_sequential_burgers(number: int): + # Faz alguma coisa sequencial para criar os hambúrgueres + return burgers +``` + +Com `async def`, o Python sabe que, dentro dessa função, tem que estar ciente das expressões `await`, e que isso pode "pausar" a execução dessa função, e poderá fazer outra coisa antes de voltar. + +Quando você quiser chamar uma função `async def`, você tem que "esperar". Então, isso não funcionará: + +```Python +# Isso não irá funcionar, porquê get_burgers foi definido com: async def +burgers = get_burgers(2) +``` + +--- + +Então, se você está usando uma biblioteca que diz que você pode chamá-la com `await`, você precisa criar as *funções de operação de rota* com `async def`, como em: + +```Python hl_lines="2 3" +@app.get('/burgers') +async def read_burgers(): + burgers = await get_burgers(2) + return burgers +``` + +### Mais detalhes técnicos + +Você deve ter observado que `await` pode ser usado somente dentro de funções definidas com `async def`. + +Mas ao mesmo tempo, funções definidas com `async def` tem que ser aguardadas. Então, funções com `async def` pdem ser chamadas somente dentro de funções definidas com `async def` também. + +Então, sobre o ovo e a galinha, como você chama a primeira função async? + +Se você estivar trabalhando com **FastAPI** não terá que se preocupar com isso, porquê essa "primeira" função será a sua *função de operação de rota*, e o FastAPI saberá como fazer a coisa certa. + +Mas se você quiser usar `async` / `await` sem FastAPI, verifique a documentação oficial Python. + +### Outras formas de código assíncrono + +Esse estilo de usar `async` e `await` é relativamente novo na linguagem. + +Mas ele faz o trabalho com código assíncrono muito mais fácil. + +Essa mesma sintaxe (ou quase a mesma) foi também incluída recentemente em versões modernas do JavaScript (no navegador e NodeJS). + +Mas antes disso, controlar código assíncrono era bem mais complexo e difícil. + +Nas versões anteriores do Python, você poderia utilizar threads ou Gevent. Mas o código é um pouco mais complexo de entender, debugar, e pensar sobre. + +Nas versões anteriores do NodeJS / Navegador JavaScript, você poderia utilizar "callbacks". O que leva ao inferno do callback. + +## Corrotinas + +**Corrotina** é apenas um jeito bonitinho para a coisa que é retornada de uma função `async def`. O Python sabe que é uma função que pode começar e terminar em algum ponto, mas que pode ser pausada internamente também, sempre que tiver um `await` dentro dela. + +Mas toda essa funcionalidade de código assíncrono com `async` e `await` é muitas vezes resumida como "corrotina". É comparável ao principal recurso chave do Go, a "Gorotina". + +## Conclusão + +Vamos ver a mesma frase com o conteúdo cima: + +> Versões modernas do Python tem suporte para **"código assíncrono"** usando algo chamado **"corrotinas"**, com sintaxe **`async` e `await`**. + +Isso pode fazer mais sentido agora. + +Tudo isso é o que deixa o FastAPI poderoso (através do Starlette) e que o faz ter uma performance impressionante. + +## Detalhes muito técnicos + +!!! warning + Você pode provavelmente pular isso. + + Esses são detalhes muito técnicos de como **FastAPI** funciona por baixo do capô. + + Se você tem algum conhecimento técnico (corrotinas, threads, blocking etc) e está curioso sobre como o FastAPI controla o `async def` vs normal `def`, vá em frente. + +### Funções de operação de rota + +Quando você declara uma *função de operação de rota* com `def` normal ao invés de `async def`, ela é rodada em uma threadpool externa que então é aguardada, ao invés de ser chamada diretamente (ela poderia bloquear o servidor). + +Se você está chegando de outro framework assíncrono que não faz o trabalho descrito acima e você está acostumado a definir triviais *funções de operação de rota* com simples `def` para ter um mínimo ganho de performance (cerca de 100 nanosegundos), por favor observe que no **FastAPI** o efeito pode ser bem o oposto. Nesses casos, é melhor usar `async def` a menos que suas *funções de operação de rota* utilizem código que performem bloqueamento IO. + +Ainda, em ambas as situações, as chances são que o **FastAPI** será [ainda mais rápido](/#performance){.internal-link target=_blank} do que (ou ao menos comparável a) seus frameworks antecessores. + +### Dependências + +O mesmo se aplica para as dependências. Se uma dependência tem as funções com padrão `def` ao invés de `async def`, ela é rodada no threadpool externo. + +### Sub-dependências + +Você pode ter múltiplas dependências e sub-dependências exigindo uma a outra (como parâmetros de definições de funções), algumas delas podem ser criadas com `async def` e algumas com `def` normal. Isso ainda poderia funcionar, e aquelas criadas com `def` podem ser chamadas em uma thread externa ao invés de serem "aguardadas". + +### Outras funções de utilidade + +Qualquer outra função de utilidade que você chame diretamente pode ser criada com `def` normal ou `async def` e o FastAPI não irá afetar o modo como você a chama. + +Isso está em contraste às funções que o FastAPI chama para você: *funções de operação de rota* e dependências. + +Se sua função de utilidade é uma função normal com `def`, ela será chamada diretamente (como você a escreve no código), não em uma threadpool, se a função é criada com `async def` então você deve esperar por essa função quando você chamá-la no seu código. + +--- + +Novamente, esses são detalhes muito técnicos que provavelmente possam ser úteis caso você esteja procurando por eles. + +Caso contrário, você deve ficar bem com as dicas da seção acima: Com pressa?. From 7c2ed25d6f28f287b611beb359ffbbc1c6280a8d Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 18 Aug 2021 13:24:58 +0000 Subject: [PATCH 175/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 038011778..0bbb68894 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Portuguese translation of `docs/async.md`. PR [#1330](https://github.com/tiangolo/fastapi/pull/1330) by [@Serrones](https://github.com/Serrones). * 🌐 Add French translation for `docs/async.md`. PR [#3416](https://github.com/tiangolo/fastapi/pull/3416) by [@Smlep](https://github.com/Smlep). * ✨ Add GitHub Action: Notify Translations. PR [#3715](https://github.com/tiangolo/fastapi/pull/3715) by [@tiangolo](https://github.com/tiangolo). * ✨ Update computation of FastAPI People and sponsors. PR [#3714](https://github.com/tiangolo/fastapi/pull/3714) by [@tiangolo](https://github.com/tiangolo). From 38c52fa12d07d1367f2f3f31cf073596e7fc1ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Victor=20Ribeiro=20Silva?= Date: Wed, 18 Aug 2021 10:27:05 -0300 Subject: [PATCH 176/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/advanced/index.md`=20(#3460)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lucas <61513630+lsglucas@users.noreply.github.com> --- docs/pt/docs/advanced/index.md | 24 ++++++++++++++++++++++++ docs/pt/mkdocs.yml | 3 +++ 2 files changed, 27 insertions(+) create mode 100644 docs/pt/docs/advanced/index.md diff --git a/docs/pt/docs/advanced/index.md b/docs/pt/docs/advanced/index.md new file mode 100644 index 000000000..d1a57c6d1 --- /dev/null +++ b/docs/pt/docs/advanced/index.md @@ -0,0 +1,24 @@ +# Guia de Usuário Avançado - Introdução + +## Recursos Adicionais + +O [Tutorial - Guia de Usuário](../tutorial/){.internal-link target=_blank} deve ser o suficiente para dar a você um tour por todos os principais recursos do **FastAPI**. + +Na próxima seção você verá outras opções, configurações, e recursos adicionais. + +!!! tip "Dica" + As próximas seções **não são necessáriamente "avançadas"** + + E é possível que para seu caso de uso, a solução esteja em uma delas. + +## Leia o Tutorial primeiro + +Você ainda pode usar a maior parte dos recursos no **FastAPI** com o conhecimento do [Tutorial - Guia de Usuário](../tutorial/){.internal-link target=_blank}. + +E as próximas seções assumem que você já leu ele, e que você conhece suas ideias principais. + +## Curso TestDriven.io + +Se você gostaria de fazer um curso avançado-iniciante para complementar essa seção da documentação, você pode querer conferir: Test-Driven Development com FastAPI e Docker por **TestDriven.io**. + +Eles estão atualmente doando 10% de todos os lucros para o desenvolvimento do **FastAPI**. 🎉 😄 diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index bd5ad59c1..7e4c8b7bf 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -61,6 +61,8 @@ nav: - tutorial/body-fields.md - Segurança: - tutorial/security/index.md + - Guia de Usuário Avançado: + - advanced/index.md - Implantação: - deployment/index.md - deployment/versions.md @@ -137,3 +139,4 @@ extra_css: extra_javascript: - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js + From 98a0fe8628f715ece3f5c7a6c80cf72bba622e5d Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 18 Aug 2021 13:27:46 +0000 Subject: [PATCH 177/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0bbb68894..fc017c2e1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/advanced/index.md`. PR [#3460](https://github.com/tiangolo/fastapi/pull/3460) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Portuguese translation of `docs/async.md`. PR [#1330](https://github.com/tiangolo/fastapi/pull/1330) by [@Serrones](https://github.com/Serrones). * 🌐 Add French translation for `docs/async.md`. PR [#3416](https://github.com/tiangolo/fastapi/pull/3416) by [@Smlep](https://github.com/Smlep). * ✨ Add GitHub Action: Notify Translations. PR [#3715](https://github.com/tiangolo/fastapi/pull/3715) by [@tiangolo](https://github.com/tiangolo). From 8c5d1f30dc50c7a67aea6b5b54e295d984741538 Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Wed, 18 Aug 2021 21:31:59 +0800 Subject: [PATCH 178/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20`docs/tutorial/dependencies/sub-dependencies.md`=20?= =?UTF-8?q?(#3491)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Waynerv Co-authored-by: Sebastián Ramírez --- .../tutorial/dependencies/sub-dependencies.md | 88 +++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 89 insertions(+) create mode 100644 docs/zh/docs/tutorial/dependencies/sub-dependencies.md diff --git a/docs/zh/docs/tutorial/dependencies/sub-dependencies.md b/docs/zh/docs/tutorial/dependencies/sub-dependencies.md new file mode 100644 index 000000000..76d3e9f44 --- /dev/null +++ b/docs/zh/docs/tutorial/dependencies/sub-dependencies.md @@ -0,0 +1,88 @@ +# 子依赖项 + +FastAPI 支持创建含**子依赖项**的依赖项。 + +并且,可以按需声明任意**深度**的子依赖项嵌套层级。 + +**FastAPI** 负责处理解析不同深度的子依赖项。 + +### 第一层依赖项 + +下列代码创建了第一层依赖项: + +```Python hl_lines="8-9" +{!../../../docs_src/dependencies/tutorial005.py!} +``` + +这段代码声明了类型为 `str` 的可选查询参数 `q`,然后返回这个查询参数。 + +这个函数很简单(不过也没什么用),但却有助于让我们专注于了解子依赖项的工作方式。 + +### 第二层依赖项 + +接下来,创建另一个依赖项函数,并同时用该依赖项自身再声明一个依赖项(所以这也是一个「依赖项」): + +```Python hl_lines="13" +{!../../../docs_src/dependencies/tutorial005.py!} +``` + +这里重点说明一下声明的参数: + +* 尽管该函数自身是依赖项,但还声明了另一个依赖项(它「依赖」于其他对象) + * 该函数依赖 `query_extractor`, 并把 `query_extractor` 的返回值赋给参数 `q` +* 同时,该函数还声明了类型是 `str` 的可选 cookie(`last_query`) + * 用户未提供查询参数 `q` 时,则使用上次使用后保存在 cookie 中的查询 + +### 使用依赖项 + +接下来,就可以使用依赖项: + +```Python hl_lines="21" +{!../../../docs_src/dependencies/tutorial005.py!} +``` + +!!! info "信息" + + 注意,这里在*路径操作函数*中只声明了一个依赖项,即 `query_or_cookie_extractor` 。 + + 但 **FastAPI** 必须先处理 `query_extractor`,以便在调用 `query_or_cookie_extractor` 时使用 `query_extractor` 返回的结果。 + +```mermaid +graph TB + +query_extractor(["query_extractor"]) +query_or_cookie_extractor(["query_or_cookie_extractor"]) + +read_query["/items/"] + +query_extractor --> query_or_cookie_extractor --> read_query +``` + +## 多次使用同一个依赖项 + +如果在同一个*路径操作* 多次声明了同一个依赖项,例如,多个依赖项共用一个子依赖项,**FastAPI** 在处理同一请求时,只调用一次该子依赖项。 + +FastAPI 不会为同一个请求多次调用同一个依赖项,而是把依赖项的返回值进行「缓存」,并把它传递给同一请求中所有需要使用该返回值的「依赖项」。 + +在高级使用场景中,如果不想使用「缓存」值,而是为需要在同一请求的每一步操作(多次)中都实际调用依赖项,可以把 `Depends` 的参数 `use_cache` 的值设置为 `False` : + +```Python hl_lines="1" +async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)): + return {"fresh_value": fresh_value} +``` + +## 小结 + +千万别被本章里这些花里胡哨的词藻吓倒了,其实**依赖注入**系统非常简单。 + +依赖注入无非是与*路径操作函数*一样的函数罢了。 + +但它依然非常强大,能够声明任意嵌套深度的「图」或树状的依赖结构。 + +!!! tip "提示" + + 这些简单的例子现在看上去虽然没有什么实用价值, + + 但在**安全**一章中,您会了解到这些例子的用途, + + 以及这些例子所能节省的代码量。 \ No newline at end of file diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 5f8fc30f8..03e9c7e96 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -83,6 +83,7 @@ nav: - tutorial/body-updates.md - 依赖项: - tutorial/dependencies/index.md + - tutorial/dependencies/sub-dependencies.md - tutorial/dependencies/global-dependencies.md - 安全性: - tutorial/security/index.md From 2280a48c67a8eb3ca3718566c72f8e96bb4b4a6c Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 18 Aug 2021 13:32:37 +0000 Subject: [PATCH 179/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fc017c2e1..38b4ef42d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for `docs/tutorial/dependencies/sub-dependencies.md`. PR [#3491](https://github.com/tiangolo/fastapi/pull/3491) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Portuguese translation for `docs/advanced/index.md`. PR [#3460](https://github.com/tiangolo/fastapi/pull/3460) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Portuguese translation of `docs/async.md`. PR [#1330](https://github.com/tiangolo/fastapi/pull/1330) by [@Serrones](https://github.com/Serrones). * 🌐 Add French translation for `docs/async.md`. PR [#3416](https://github.com/tiangolo/fastapi/pull/3416) by [@Smlep](https://github.com/Smlep). From b5dcd98605c88ee0b54dcb053695b391bb9b2f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 18 Aug 2021 15:44:11 +0200 Subject: [PATCH 180/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20new=20Translation?= =?UTF-8?q?=20tracking=20issues=20for=20German=20and=20Indonesian=20(#3718?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/notify-translations/app/translations.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/notify-translations/app/translations.yml b/.github/actions/notify-translations/app/translations.yml index 2ac955673..3f53adb65 100644 --- a/.github/actions/notify-translations/app/translations.yml +++ b/.github/actions/notify-translations/app/translations.yml @@ -10,3 +10,5 @@ fr: 1972 ko: 2017 sq: 2041 pl: 3169 +de: 3716 +id: 3717 From ab5afd0b42fb26f5515ff659620b9ffc07cdf27a Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 18 Aug 2021 13:44:46 +0000 Subject: [PATCH 181/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 38b4ef42d..845f62c55 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add new Translation tracking issues for German and Indonesian. PR [#3718](https://github.com/tiangolo/fastapi/pull/3718) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/sub-dependencies.md`. PR [#3491](https://github.com/tiangolo/fastapi/pull/3491) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Portuguese translation for `docs/advanced/index.md`. PR [#3460](https://github.com/tiangolo/fastapi/pull/3460) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Portuguese translation of `docs/async.md`. PR [#1330](https://github.com/tiangolo/fastapi/pull/1330) by [@Serrones](https://github.com/Serrones). From 13bf477579c4e296af6d641c788d73edfeaf74a0 Mon Sep 17 00:00:00 2001 From: jaystone776 <1732865113@qq.com> Date: Wed, 18 Aug 2021 21:49:44 +0800 Subject: [PATCH 182/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20`docs/tutorial/dependencies/dependencies-in-path-op?= =?UTF-8?q?eration-decorators.md`=20(#3492)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Waynerv Co-authored-by: Sebastián Ramírez --- ...pendencies-in-path-operation-decorators.md | 73 +++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 74 insertions(+) create mode 100644 docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md diff --git a/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md new file mode 100644 index 000000000..e36e33c4f --- /dev/null +++ b/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md @@ -0,0 +1,73 @@ +# 路径操作装饰器依赖项 + +有时,我们并不需要在*路径操作函数*中使用依赖项的返回值。 + +或者说,有些依赖项不返回值。 + +但仍要执行或解析该依赖项。 + +对于这种情况,不必在声明*路径操作函数*的参数时使用 `Depends`,而是可以在*路径操作装饰器*中添加一个由 `dependencies` 组成的 `list`。 + +## 在*路径操作装饰器*中添加 `dependencies` 参数 + +*路径操作装饰器*支持可选参数 ~ `dependencies`。 + +该参数的值是由 `Depends()` 组成的 `list`: + +```Python hl_lines="17" +{!../../../docs_src/dependencies/tutorial006.py!} +``` + +路径操作装饰器依赖项(以下简称为**“路径装饰器依赖项”**)的执行或解析方式和普通依赖项一样,但就算这些依赖项会返回值,它们的值也不会传递给*路径操作函数*。 + +!!! tip "提示" + + 有些编辑器会检查代码中没使用过的函数参数,并显示错误提示。 + + 在*路径操作装饰器*中使用 `dependencies` 参数,可以确保在执行依赖项的同时,避免编辑器显示错误提示。 + + 使用路径装饰器依赖项还可以避免开发新人误会代码中包含无用的未使用参数。 + +!!! info "说明" + + 本例中,使用的是自定义响应头 `X-Key` 和 `X-Token`。 + + 但实际开发中,尤其是在实现安全措施时,最好使用 FastAPI 内置的[安全工具](../security/index.md){.internal-link target=_blank}(详见下一章)。 + +## 依赖项错误和返回值 + +路径装饰器依赖项也可以使用普通的依赖项*函数*。 + +### 依赖项的需求项 + +路径装饰器依赖项可以声明请求的需求项(比如响应头)或其他子依赖项: + +```Python hl_lines="6 11" +{!../../../docs_src/dependencies/tutorial006.py!} +``` + +### 触发异常 + +路径装饰器依赖项与正常的依赖项一样,可以 `raise` 异常: + +```Python hl_lines="8 13" +{!../../../docs_src/dependencies/tutorial006.py!} +``` + +### 返回值 + +无论路径装饰器依赖项是否返回值,路径操作都不会使用这些值。 + +因此,可以复用在其他位置使用过的、(能返回值的)普通依赖项,即使没有使用这个值,也会执行该依赖项: + +```Python hl_lines="9 14" +{!../../../docs_src/dependencies/tutorial006.py!} +``` + +## 为一组路径操作定义依赖项 + +稍后,[大型应用 - 多文件](../../tutorial/bigger-applications.md){.internal-link target=\_blank}一章中会介绍如何使用多个文件创建大型应用程序,在这一章中,您将了解到如何为一组*路径操作*声明单个 `dependencies` 参数。 + +## 全局依赖项 + +接下来,我们将学习如何为 `FastAPI` 应用程序添加全局依赖项,创建应用于每个*路径操作*的依赖项。 diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 03e9c7e96..d73afaa93 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -84,6 +84,7 @@ nav: - 依赖项: - tutorial/dependencies/index.md - tutorial/dependencies/sub-dependencies.md + - tutorial/dependencies/dependencies-in-path-operation-decorators.md - tutorial/dependencies/global-dependencies.md - 安全性: - tutorial/security/index.md From 70f1b8ebd05e0f50617e7a9129fa6d22bea789f7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 18 Aug 2021 13:50:17 +0000 Subject: [PATCH 183/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 845f62c55..cc88a2398 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for `docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#3492](https://github.com/tiangolo/fastapi/pull/3492) by [@jaystone776](https://github.com/jaystone776). * 🔧 Add new Translation tracking issues for German and Indonesian. PR [#3718](https://github.com/tiangolo/fastapi/pull/3718) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/sub-dependencies.md`. PR [#3491](https://github.com/tiangolo/fastapi/pull/3491) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Portuguese translation for `docs/advanced/index.md`. PR [#3460](https://github.com/tiangolo/fastapi/pull/3460) by [@ComicShrimp](https://github.com/ComicShrimp). From c03b9b2d4c0f1eaa1bf5e3cc81e3fe173108bfd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Victor=20Ribeiro=20Silva?= Date: Thu, 19 Aug 2021 05:21:21 -0300 Subject: [PATCH 184/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20of=20`docs/fastapi-people.md`=20(#3461)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/fastapi-people.md | 4 + docs/pt/docs/fastapi-people.md | 178 +++++++++++++++++++++++++++++++++ docs/pt/docs/index.md | 4 +- docs/pt/mkdocs.yml | 1 + 4 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 docs/pt/docs/fastapi-people.md diff --git a/docs/en/docs/fastapi-people.md b/docs/en/docs/fastapi-people.md index f4f38cdbe..0cbcb69c9 100644 --- a/docs/en/docs/fastapi-people.md +++ b/docs/en/docs/fastapi-people.md @@ -114,6 +114,8 @@ These are the **Sponsors**. 😎 They are supporting my work with **FastAPI** (and others), mainly through GitHub Sponsors. +{% if sponsors %} + {% if sponsors.gold %} ### Gold Sponsors @@ -141,6 +143,8 @@ They are supporting my work with **FastAPI** (and others), mainly through +{% for user in people.maintainers %} + +
@{{ user.login }}
Respostas: {{ user.answers }}
Pull Requests: {{ user.prs }}
+{% endfor %} + +
+{% endif %} + +Eu sou o criador e mantenedor do **FastAPI**. Você pode ler mais sobre isso em [Help FastAPI - Get Help - Connect with the author](help-fastapi.md#connect-with-the-author){.internal-link target=_blank}. + +...Mas aqui eu quero mostrar a você a comunidade. + +--- + +**FastAPI** recebe muito suporte da comunidade. E quero destacar suas contribuições. + +Estas são as pessoas que: + +* [Help others with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}. +* [Create Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}. +* Revisar Pull Requests, [especially important for translations](contributing.md#translations){.internal-link target=_blank}. + +Uma salva de palmas para eles. 👏 🙇 + +## Usuários mais ativos do ultimo mês + +Estes são os usuários que estão [helping others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} durante o ultimo mês. ☕ + +{% if people %} +
+{% for user in people.last_month_active %} + +
@{{ user.login }}
Issues respondidas: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +## Especialistas + +Aqui está os **Especialistas do FastAPI**. 🤓 + + +Estes são os usuários que [helped others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} em *todo o tempo*. + +Eles provaram ser especialistas ajudando muitos outros. ✨ + +{% if people %} +
+{% for user in people.experts %} + +
@{{ user.login }}
Issues respondidas: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +## Top Contribuidores + +Aqui está os **Top Contribuidores**. 👷 + +Esses usuários têm [created the most Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank} que tem sido *mergeado*. + +Eles contribuíram com o código-fonte, documentação, traduções, etc. 📦 + +{% if people %} +
+{% for user in people.top_contributors %} + +
@{{ user.login }}
Pull Requests: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +Existem muitos outros contribuidores (mais de uma centena), você pode ver todos eles em Página de Contribuidores do FastAPI no GitHub. 👷 + +## Top Revisores + +Esses usuários são os **Top Revisores**. 🕵️ + +### Revisões para Traduções + +Eu só falo algumas línguas (e não muito bem 😅). Então, os revisores são aqueles que têm o [**poder de aprovar traduções**](contributing.md#translations){.internal-link target=_blank} da documentação. Sem eles, não haveria documentação em vários outros idiomas. + +--- + +Os **Top Revisores** 🕵️ revisaram a maior parte de Pull Requests de outros, garantindo a qualidade do código, documentação, e especialmente, as **traduções**. + +{% if people %} +
+{% for user in people.top_reviewers %} + +
@{{ user.login }}
Revisões: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +## Patrocinadores + +Esses são os **Patrocinadores**. 😎 + +Eles estão apoiando meu trabalho **FastAPI** (e outros), principalmente através de GitHub Sponsors. + +{% if sponsors %} +{% if sponsors.gold %} + +### Patrocinadores Ouro + +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + +{% if sponsors.silver %} + +### Patrocinadores Prata + +{% for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + +{% if sponsors.bronze %} + +### Patrocinadores Bronze + +{% for sponsor in sponsors.bronze -%} + +{% endfor %} +{% endif %} + +### Patrocinadores Individuais + +{% if github_sponsors %} +{% for group in github_sponsors.sponsors %} + +
+ +{% for user in group %} +{% if user.login not in sponsors_badge.logins %} + + + +{% endif %} +{% endfor %} + +
+ +{% endfor %} +{% endif %} + +{% endif %} + +## Sobre os dados - detalhes técnicos + +A principal intenção desta página é destacar o esforço da comunidade para ajudar os outros. + +Especialmente incluindo esforços que normalmente são menos visíveis, e em muitos casos mais árduo, como ajudar os outros com issues e revisando Pull Requests com traduções. + +Os dados são calculados todo mês, você pode ler o código fonte aqui. + +Aqui também estou destacando contribuições de patrocinadores. + +Eu também me reservo o direito de atualizar o algoritmo, seções, limites, etc (só para prevenir 🤷). diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md index 63f1f88fe..848fff08a 100644 --- a/docs/pt/docs/index.md +++ b/docs/pt/docs/index.md @@ -39,7 +39,7 @@ Os recursos chave são: * estimativas baseadas em testes realizados com equipe interna de desenvolvimento, construindo aplicações em produção. -## Sponsors +## Patrocinadores Ouro @@ -54,7 +54,7 @@ Os recursos chave são: -Other sponsors +Outros patrocinadores ## Opiniões diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 7e4c8b7bf..ec0684d54 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -55,6 +55,7 @@ nav: - uk: /uk/ - zh: /zh/ - features.md +- fastapi-people.md - Tutorial - Guia de Usuário: - tutorial/index.md - tutorial/first-steps.md From f7d7c6c8659bffc23626928ffc0d924673cc1b01 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 19 Aug 2021 08:21:59 +0000 Subject: [PATCH 185/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index cc88a2398..15a35f598 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation of `docs/fastapi-people.md`. PR [#3461](https://github.com/tiangolo/fastapi/pull/3461) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#3492](https://github.com/tiangolo/fastapi/pull/3492) by [@jaystone776](https://github.com/jaystone776). * 🔧 Add new Translation tracking issues for German and Indonesian. PR [#3718](https://github.com/tiangolo/fastapi/pull/3718) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/sub-dependencies.md`. PR [#3491](https://github.com/tiangolo/fastapi/pull/3491) by [@jaystone776](https://github.com/jaystone776). From 20d48345465e5b09756cc9ef62fb940c63255a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 24 Aug 2021 12:21:05 +0200 Subject: [PATCH 186/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20`read?= =?UTF-8?q?=5Fwith=5Form=5Fmode`,=20to=20support=20SQLModel=20relationship?= =?UTF-8?q?=20attributes=20(#3757)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/routing.py | 7 +++++ tests/test_read_with_orm_mode.py | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/test_read_with_orm_mode.py diff --git a/fastapi/routing.py b/fastapi/routing.py index 0ad082341..63ad72964 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -65,6 +65,13 @@ def _prepare_response_content( exclude_none: bool = False, ) -> Any: if isinstance(res, BaseModel): + read_with_orm_mode = getattr(res.__config__, "read_with_orm_mode", None) + if read_with_orm_mode: + # Let from_orm extract the data from this model instead of converting + # it now to a dict. + # Otherwise there's no way to extract lazy data that requires attribute + # access instead of dict iteration, e.g. lazy relationships. + return res return res.dict( by_alias=True, exclude_unset=exclude_unset, diff --git a/tests/test_read_with_orm_mode.py b/tests/test_read_with_orm_mode.py new file mode 100644 index 000000000..360ad2503 --- /dev/null +++ b/tests/test_read_with_orm_mode.py @@ -0,0 +1,53 @@ +from typing import Any + +from fastapi import FastAPI +from fastapi.testclient import TestClient +from pydantic import BaseModel + + +class PersonBase(BaseModel): + name: str + lastname: str + + +class Person(PersonBase): + @property + def full_name(self) -> str: + return f"{self.name} {self.lastname}" + + class Config: + orm_mode = True + read_with_orm_mode = True + + +class PersonCreate(PersonBase): + pass + + +class PersonRead(PersonBase): + full_name: str + + class Config: + orm_mode = True + + +app = FastAPI() + + +@app.post("/people/", response_model=PersonRead) +def create_person(person: PersonCreate) -> Any: + db_person = Person.from_orm(person) + return db_person + + +client = TestClient(app) + + +def test_read_with_orm_mode() -> None: + person_data = {"name": "Dive", "lastname": "Wilson"} + response = client.post("/people/", json=person_data) + data = response.json() + assert response.status_code == 200, response.text + assert data["name"] == person_data["name"] + assert data["lastname"] == person_data["lastname"] + assert data["full_name"] == person_data["name"] + " " + person_data["lastname"] From dc9c570733441a83232d111ca0df3f93876a8097 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 24 Aug 2021 10:21:45 +0000 Subject: [PATCH 187/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 15a35f598..0421f754e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for `read_with_orm_mode`, to support SQLModel relationship attributes. PR [#3757](https://github.com/tiangolo/fastapi/pull/3757) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Portuguese translation of `docs/fastapi-people.md`. PR [#3461](https://github.com/tiangolo/fastapi/pull/3461) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#3492](https://github.com/tiangolo/fastapi/pull/3492) by [@jaystone776](https://github.com/jaystone776). * 🔧 Add new Translation tracking issues for German and Indonesian. PR [#3718](https://github.com/tiangolo/fastapi/pull/3718) by [@tiangolo](https://github.com/tiangolo). From 6ac35b1c2aed4392f5227ee5458e23eca2fc52c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 24 Aug 2021 14:13:47 +0200 Subject: [PATCH 188/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0421f754e..f2c89aaaa 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,10 @@ ## Latest Changes -* ✨ Add support for `read_with_orm_mode`, to support SQLModel relationship attributes. PR [#3757](https://github.com/tiangolo/fastapi/pull/3757) by [@tiangolo](https://github.com/tiangolo). +* ✨ Add support for `read_with_orm_mode`, to support [SQLModel](https://sqlmodel.tiangolo.com/) relationship attributes. PR [#3757](https://github.com/tiangolo/fastapi/pull/3757) by [@tiangolo](https://github.com/tiangolo). + +### Translations + * 🌐 Add Portuguese translation of `docs/fastapi-people.md`. PR [#3461](https://github.com/tiangolo/fastapi/pull/3461) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Add Chinese translation for `docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#3492](https://github.com/tiangolo/fastapi/pull/3492) by [@jaystone776](https://github.com/jaystone776). * 🔧 Add new Translation tracking issues for German and Indonesian. PR [#3718](https://github.com/tiangolo/fastapi/pull/3718) by [@tiangolo](https://github.com/tiangolo). @@ -10,12 +13,15 @@ * 🌐 Add Portuguese translation for `docs/advanced/index.md`. PR [#3460](https://github.com/tiangolo/fastapi/pull/3460) by [@ComicShrimp](https://github.com/ComicShrimp). * 🌐 Portuguese translation of `docs/async.md`. PR [#1330](https://github.com/tiangolo/fastapi/pull/1330) by [@Serrones](https://github.com/Serrones). * 🌐 Add French translation for `docs/async.md`. PR [#3416](https://github.com/tiangolo/fastapi/pull/3416) by [@Smlep](https://github.com/Smlep). + +### Internal + * ✨ Add GitHub Action: Notify Translations. PR [#3715](https://github.com/tiangolo/fastapi/pull/3715) by [@tiangolo](https://github.com/tiangolo). * ✨ Update computation of FastAPI People and sponsors. PR [#3714](https://github.com/tiangolo/fastapi/pull/3714) by [@tiangolo](https://github.com/tiangolo). * ✨ Enable recent Material for MkDocs Insiders features. PR [#3710](https://github.com/tiangolo/fastapi/pull/3710) by [@tiangolo](https://github.com/tiangolo). * 🔥 Remove/clean extra imports from examples in docs for features. PR [#3709](https://github.com/tiangolo/fastapi/pull/3709) by [@tiangolo](https://github.com/tiangolo). * ➕ Update docs library to include sources in Markdown. PR [#3648](https://github.com/tiangolo/fastapi/pull/3648) by [@tiangolo](https://github.com/tiangolo). -* ⬆ Add support for Python 3.9. PR [#2298](https://github.com/tiangolo/fastapi/pull/2298) by [@Kludex](https://github.com/Kludex). +* ⬆ Enable tests for Python 3.9. PR [#2298](https://github.com/tiangolo/fastapi/pull/2298) by [@Kludex](https://github.com/Kludex). * 👥 Update FastAPI People. PR [#3642](https://github.com/tiangolo/fastapi/pull/3642) by [@github-actions[bot]](https://github.com/apps/github-actions). ## 0.68.0 From 7b6e198d314e320256c2ed8b62430b2a42c31cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 24 Aug 2021 14:16:09 +0200 Subject: [PATCH 189/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.68?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f2c89aaaa..921c2b992 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.68.1 + * ✨ Add support for `read_with_orm_mode`, to support [SQLModel](https://sqlmodel.tiangolo.com/) relationship attributes. PR [#3757](https://github.com/tiangolo/fastapi/pull/3757) by [@tiangolo](https://github.com/tiangolo). ### Translations diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 60f90b80d..316362669 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.68.0" +__version__ = "0.68.1" from starlette import status as status From f49ba24b71c5c2539ba9cc8b8d1408072da5f631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 27 Aug 2021 10:49:08 +0200 Subject: [PATCH 190/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20new=20Sponsor=20Ca?= =?UTF-8?q?lmcode.io=20(#3777)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/data/sponsors.yml | 4 ++++ docs/en/data/sponsors_badge.yml | 1 + docs/en/docs/img/sponsors/calmcode.jpg | Bin 0 -> 16949 bytes 3 files changed, 5 insertions(+) create mode 100644 docs/en/docs/img/sponsors/calmcode.jpg diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index b5bb9a773..e0a4ee783 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -18,3 +18,7 @@ silver: - url: https://testdriven.io/courses/tdd-fastapi/ title: Learn to build high-quality web apps with best practices img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg +bronze: + - url: https://calmcode.io + title: Code. Simply. Clearly. Calmly. + img: https://fastapi.tiangolo.com/img/sponsors/calmcode.jpg diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index 066a82506..9e95a6255 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -4,3 +4,4 @@ logins: - investsuite - vimsoHQ - mikeckennedy + - koaning diff --git a/docs/en/docs/img/sponsors/calmcode.jpg b/docs/en/docs/img/sponsors/calmcode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..59e68dd07357878a76bd228b61fb62f201bd0236 GIT binary patch literal 16949 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 Date: Fri, 27 Aug 2021 08:49:40 +0000 Subject: [PATCH 191/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 921c2b992..1502e4de6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add new Sponsor Calmcode.io. PR [#3777](https://github.com/tiangolo/fastapi/pull/3777) by [@tiangolo](https://github.com/tiangolo). ## 0.68.1 From c8b4e4d455cf0ca370d2814ac019ffe74e47eb12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 10 Sep 2021 17:28:22 +0300 Subject: [PATCH 192/814] =?UTF-8?q?=F0=9F=8E=A8=20Tweak=20CSS=20styles=20f?= =?UTF-8?q?or=20shell=20animations=20(#3888)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/css/custom.css | 14 ++++++++++++++ docs/en/docs/css/termynal.css | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css index 997bcd3af..7d3503e49 100644 --- a/docs/en/docs/css/custom.css +++ b/docs/en/docs/css/custom.css @@ -1,3 +1,13 @@ +.termynal-comment { + color: #4a968f; + font-style: italic; + display: block; +} + +.termy [data-termynal] { + white-space: pre-wrap; +} + a.external-link::after { /* \00A0 is a non-breaking space to make the mark be on the same line as the link @@ -12,6 +22,10 @@ a.internal-link::after { content: "\00A0↪"; } +.shadow { + box-shadow: 5px 5px 10px #999; +} + /* Give space to lower icons so Gitter chat doesn't get on top of them */ .md-footer-meta { padding-bottom: 2em; diff --git a/docs/en/docs/css/termynal.css b/docs/en/docs/css/termynal.css index 0484e65d4..406c00897 100644 --- a/docs/en/docs/css/termynal.css +++ b/docs/en/docs/css/termynal.css @@ -17,7 +17,8 @@ max-width: 100%; background: var(--color-bg); color: var(--color-text); - font-size: 18px; + /* font-size: 18px; */ + font-size: 15px; /* font-family: 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace; */ font-family: 'Roboto Mono', 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace; border-radius: 4px; From eaeafc32c49100d6b3f92acdf225761ea48bb9a7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 10 Sep 2021 14:29:04 +0000 Subject: [PATCH 193/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1502e4de6..ea50f4ab3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🎨 Tweak CSS styles for shell animations. PR [#3888](https://github.com/tiangolo/fastapi/pull/3888) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new Sponsor Calmcode.io. PR [#3777](https://github.com/tiangolo/fastapi/pull/3777) by [@tiangolo](https://github.com/tiangolo). ## 0.68.1 From 3a786a7a3aef87fc1a313acf60a0782324ca3222 Mon Sep 17 00:00:00 2001 From: Maximilian Wassink Date: Mon, 13 Sep 2021 19:29:03 +0200 Subject: [PATCH 194/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20German=20translati?= =?UTF-8?q?on=20for=20`docs/features.md`=20(#3699)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/de/docs/features.md | 204 +++++++++++++++++++++++++++++++++++++++ docs/de/mkdocs.yml | 1 + 2 files changed, 205 insertions(+) create mode 100644 docs/de/docs/features.md diff --git a/docs/de/docs/features.md b/docs/de/docs/features.md new file mode 100644 index 000000000..e5b38616f --- /dev/null +++ b/docs/de/docs/features.md @@ -0,0 +1,204 @@ +# Merkmale + +## FastAPI Merkmale + +**FastAPI** ermöglicht Ihnen folgendes: + +### Basiert auf offenen Standards + +* OpenAPI für API-Erstellung, zusammen mit Deklarationen von Pfad Operationen, Parameter, Nachrichtenrumpf-Anfragen (englisch: body request), Sicherheit, etc. +* Automatische Dokumentation der Datenentitäten mit dem JSON Schema (OpenAPI basiert selber auf dem JSON Schema). +* Entworfen auf Grundlage dieser Standards nach einer sorgfältigen Studie, statt einer nachträglichen Schicht über diesen Standards. +* Dies ermöglicht automatische **Quellcode-Generierung auf Benutzerebene** in vielen Sprachen. + +### Automatische Dokumentation + +Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzerschnittstellen. Da FastAPI auf OpenAPI basiert, gibt es hierzu mehrere Optionen, wobei zwei standartmäßig vorhanden sind. + +* Swagger UI, bietet interaktive Exploration: testen und rufen Sie ihre API direkt vom Webbrowser auf. + +![Swagger UI Interaktion](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Alternative API-Dokumentation mit ReDoc. + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Nur modernes Python + +Alles basiert auf **Python 3.6 Typ**-Deklarationen (dank Pydantic). Es muss keine neue Syntax gelernt werden, nur standardisiertes modernes Python. + + + +Wenn Sie eine kurze, zweiminütige, Auffrischung in der Benutzung von Python Typ-Deklarationen benötigen (auch wenn Sie FastAPI nicht nutzen), schauen Sie sich diese kurze Einführung an (Englisch): Python Types{.internal-link target=_blank}. + +Sie schreiben Standard-Python mit Typ-Deklarationen: + +```Python +from typing import List, Dict +from datetime import date + +from pydantic import BaseModel + +# Deklariere eine Variable als str +# und bekomme Editor-Unterstütung innerhalb der Funktion +def main(user_id: str): + return user_id + + +# Ein Pydantic model +class User(BaseModel): + id: int + name: str + joined: date +``` + +Dies kann nun wiefolgt benutzt werden: + +```Python +my_user: User = User(id=3, name="John Doe", joined="2018-07-19") + +second_user_data = { + "id": 4, + "name": "Mary", + "joined": "2018-11-30", +} + +my_second_user: User = User(**second_user_data) +``` + +!!! info + `**second_user_data` bedeutet: + + Übergebe die Schlüssel und die zugehörigen Werte des `second_user_data` Datenwörterbuches direkt als Schlüssel-Wert Argumente, äquivalent zu: `User(id=4, name="Mary", joined="2018-11-30")` + +### Editor Unterstützung + +FastAPI wurde so entworfen, dass es einfach und intuitiv zu benutzen ist; alle Entscheidungen wurden auf mehreren Editoren getestet (sogar vor der eigentlichen Implementierung), um so eine best mögliche Entwicklererfahrung zu gewährleisten. + +In der letzen Python Entwickler Umfrage stellte sich heraus, dass die meist genutzte Funktion die "Autovervollständigung" ist. + +Die gesamte Struktur von **FastAPI** soll dem gerecht werden. Autovervollständigung funktioniert überall. + +Sie müssen selten in die Dokumentation schauen. + +So kann ihr Editor Sie unterstützen: + +* in Visual Studio Code: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +* in PyCharm: + +![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png) + +Sie bekommen Autovervollständigung an Stellen, an denen Sie dies vorher nicht für möglich gehalten hätten. Zum Beispiel der `price` Schlüssel aus einem JSON Datensatz (dieser könnte auch verschachtelt sein) aus einer Anfrage. + +Hierdurch werden Sie nie wieder einen falschen Schlüsselnamen benutzen und sparen sich lästiges Suchen in der Dokumentation, um beispielsweise herauszufinden ob Sie `username` oder `user_name` als Schlüssel verwenden. + +### Kompakt + +FastAPI nutzt für alles sensible **Standard-Einstellungen**, welche optional überall konfiguriert werden können. Alle Parameter können ganz genau an Ihre Bedürfnisse angepasst werden, sodass sie genau die API definieren können, die sie brachen. + +Aber standartmäßig, **"funktioniert einfach"** alles. + +### Validierung + +* Validierung für die meisten (oder alle?) Python **Datentypen**, hierzu gehören: + * JSON Objekte (`dict`). + * JSON Listen (`list`), die den Typ ihrer Elemente definieren. + * Zeichenketten (`str`), mit definierter minimaler und maximaler Länge. + * Zahlen (`int`, `float`) mit minimaler und maximaler Größe, usw. + +* Validierung für ungewögnliche Typen, wie: + * URL. + * Email. + * UUID. + * ... und andere. + +Die gesamte Validierung übernimmt das etablierte und robuste **Pydantic**. + +### Sicherheit und Authentifizierung + +Sicherheit und Authentifizierung integriert. Ohne einen Kompromiss aufgrund einer Datenbank oder den Datenentitäten. + +Unterstützt alle von OpenAPI definierten Sicherheitsschemata, hierzu gehören: + +* HTTP Basis Authentifizierung. +* **OAuth2** (auch mit **JWT Zugriffstokens**). Schauen Sie sich hierzu dieses Tutorial an: [OAuth2 mit JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. +* API Schlüssel in: + * Kopfzeile (HTTP Header). + * Anfrageparametern. + * Cookies, etc. + +Zusätzlich gibt es alle Sicherheitsfunktionen von Starlette (auch **session cookies**). + +Alles wurde als wiederverwendbare Werkzeuge und Komponenten geschaffen, die einfach in ihre Systeme, Datenablagen, relationale und nicht-relationale Datenbanken, ..., integriert werden können. + +### Einbringen von Abhängigkeiten (meist: Dependency Injection) + +FastAPI enthält ein extrem einfaches, aber extrem mächtiges Dependency Injection System. + +* Selbst Abhängigkeiten können Abhängigkeiten haben, woraus eine Hierachie oder ein **"Graph" von Abhängigkeiten** entsteht. +* **Automatische Umsetzung** durch FastAPI. +* Alle abhängigen Komponenten könnten Daten von Anfragen, **Erweiterungen der Pfadoperations-**Einschränkungen und der automatisierten Dokumentation benötigen. +* **Automatische Validierung** selbst für *Pfadoperationen*-Parameter, die in den Abhängigkeiten definiert wurden. +* Unterstütz komplexe Benutzerauthentifizierungssysteme, mit **Datenbankverbindungen**, usw. +* **Keine Kompromisse** bei Datenbanken, Eingabemasken, usw. Sondern einfache Integration von allen. + +### Unbegrenzte Erweiterungen + +Oder mit anderen Worten, sie werden nicht benötigt. Importieren und nutzen Sie Quellcode nach Bedarf. + +Jede Integration wurde so entworfen, dass sie einfach zu nutzen ist (mit Abhängigkeiten), sodass Sie eine Erweiterung für Ihre Anwendung mit nur zwei Zeilen an Quellcode implementieren können. Hierbei nutzen Sie die selbe Struktur und Syntax, wie bei Pfadoperationen. + +### Getestet + +* 100% Testabdeckung. +* 100% Typen annotiert. +* Verwendet in Produktionsanwendungen. + +## Starlette's Merkmale + +**FastAPI** ist vollkommen kompatibel (und basiert auf) Starlette. Das bedeutet, auch ihr eigner Starlett Quellcode funktioniert. + +`FastAPI` ist eigentlich eine Unterklasse von `Starlette`. Wenn sie also bereits Starlette kennen oder benutzen, können Sie das meiste Ihres Wissen direkt anwenden. + +Mit **FastAPI** bekommen Sie viele von **Starlette**'s Funktionen (da FastAPI nur Starlette auf Steroiden ist): + +* Stark beeindruckende Performanz. Es ist eines der schnellsten Python frameworks, auf Augenhöhe mit **NodeJS** und **Go**. +* **WebSocket**-Unterstützung. +* **GraphQL**-Unterstützung. +* Hintergrundaufgaben im selben Prozess. +* Ereignisse für das Starten und Herunterfahren. +* Testclient basierend auf `requests`. +* **CORS**, GZip, statische Dateien, Antwortfluss. +* **Sitzungs und Cookie** Unterstützung. +* 100% Testabdeckung. +* 100% Typen annotiert. + +## Pydantic's Merkmale + +**FastAPI** ist vollkommen kompatibel (und basiert auf) Pydantic. Das bedeutet, auch jeder zusätzliche Pydantic Quellcode funktioniert. + +Verfügbar sind ebenso externe auf Pydantic basierende Bibliotheken, wie ORMs, ODMs für Datenbanken. + +Daher können Sie in vielen Fällen das Objekt einer Anfrage **direkt zur Datenbank** schicken, weil alles automatisch validiert wird. + +Das selbe gilt auch für die andere Richtung: Sie können jedes Objekt aus der Datenbank **direkt zum Klienten** schicken. + +Mit **FastAPI** bekommen Sie alle Funktionen von **Pydantic** (da FastAPI für die gesamte Datenverarbeitung Pydantic nutzt): + +* **Kein Kopfzerbrechen**: + * Sie müssen keine neue Schemadefinitionssprache lernen. + * Wenn Sie mit Python's Typisierung arbeiten können, können Sie auch mit Pydantic arbeiten. +* Gutes Zusammenspiel mit Ihrer/Ihrem **IDE/linter/Gehirn**: + * Weil Datenstrukturen von Pydantic einfach nur Instanzen ihrer definierten Klassen sind, sollten Autovervollständigung, Linting, mypy und ihre Intuition einwandfrei funktionieren. +* **Schnell**: + * In Vergleichen ist Pydantic schneller als jede andere getestete Bibliothek. +* Validierung von **komplexen Strukturen**: + * Benutzung von hierachischen Pydantic Schemata, Python `typing`’s `List` und `Dict`, etc. + * Validierungen erlauben klare und einfache Datenschemadefinition, überprüft und dokumentiert als JSON Schema. + * Sie können stark **verschachtelte JSON** Objekte haben und diese sind trotzdem validiert und annotiert. +* **Erweiterbar**: + * Pydantic erlaubt die Definition von eigenen Datentypen oder sie können die Validierung mit einer `validator` dekorierten Methode erweitern.. +* 100% Testabdeckung. diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 49fad8ec4..77882db03 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -54,6 +54,7 @@ nav: - tr: /tr/ - uk: /uk/ - zh: /zh/ +- features.md markdown_extensions: - toc: permalink: true From bee35f5ae1fc58e7ab125427ad4287210e99d8b3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 13 Sep 2021 17:29:47 +0000 Subject: [PATCH 195/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ea50f4ab3..a581cf394 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add German translation for `docs/features.md`. PR [#3699](https://github.com/tiangolo/fastapi/pull/3699) by [@mawassk](https://github.com/mawassk). * 🎨 Tweak CSS styles for shell animations. PR [#3888](https://github.com/tiangolo/fastapi/pull/3888) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new Sponsor Calmcode.io. PR [#3777](https://github.com/tiangolo/fastapi/pull/3777) by [@tiangolo](https://github.com/tiangolo). From 64e7deaebc1bebb327cc146f1d65e088b282e731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 27 Sep 2021 16:40:38 +0200 Subject: [PATCH 196/814] =?UTF-8?q?=F0=9F=93=9D=20Upgrade=20HTTPS=20guide?= =?UTF-8?q?=20with=20more=20explanations=20and=20diagrams=20(#3950)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/deployment/https.md | 192 ++++++++++-- .../en/docs/img/deployment/https/https.drawio | 277 ++++++++++++++++++ docs/en/docs/img/deployment/https/https.svg | 62 ++++ .../docs/img/deployment/https/https01.drawio | 78 +++++ docs/en/docs/img/deployment/https/https01.svg | 57 ++++ .../docs/img/deployment/https/https02.drawio | 110 +++++++ docs/en/docs/img/deployment/https/https02.svg | 57 ++++ .../docs/img/deployment/https/https03.drawio | 131 +++++++++ docs/en/docs/img/deployment/https/https03.svg | 62 ++++ .../docs/img/deployment/https/https04.drawio | 152 ++++++++++ docs/en/docs/img/deployment/https/https04.svg | 62 ++++ .../docs/img/deployment/https/https05.drawio | 166 +++++++++++ docs/en/docs/img/deployment/https/https05.svg | 62 ++++ .../docs/img/deployment/https/https06.drawio | 183 ++++++++++++ docs/en/docs/img/deployment/https/https06.svg | 62 ++++ .../docs/img/deployment/https/https07.drawio | 203 +++++++++++++ docs/en/docs/img/deployment/https/https07.svg | 62 ++++ .../docs/img/deployment/https/https08.drawio | 217 ++++++++++++++ docs/en/docs/img/deployment/https/https08.svg | 62 ++++ 19 files changed, 2232 insertions(+), 25 deletions(-) create mode 100644 docs/en/docs/img/deployment/https/https.drawio create mode 100644 docs/en/docs/img/deployment/https/https.svg create mode 100644 docs/en/docs/img/deployment/https/https01.drawio create mode 100644 docs/en/docs/img/deployment/https/https01.svg create mode 100644 docs/en/docs/img/deployment/https/https02.drawio create mode 100644 docs/en/docs/img/deployment/https/https02.svg create mode 100644 docs/en/docs/img/deployment/https/https03.drawio create mode 100644 docs/en/docs/img/deployment/https/https03.svg create mode 100644 docs/en/docs/img/deployment/https/https04.drawio create mode 100644 docs/en/docs/img/deployment/https/https04.svg create mode 100644 docs/en/docs/img/deployment/https/https05.drawio create mode 100644 docs/en/docs/img/deployment/https/https05.svg create mode 100644 docs/en/docs/img/deployment/https/https06.drawio create mode 100644 docs/en/docs/img/deployment/https/https06.svg create mode 100644 docs/en/docs/img/deployment/https/https07.drawio create mode 100644 docs/en/docs/img/deployment/https/https07.svg create mode 100644 docs/en/docs/img/deployment/https/https08.drawio create mode 100644 docs/en/docs/img/deployment/https/https08.svg diff --git a/docs/en/docs/deployment/https.md b/docs/en/docs/deployment/https.md index c735f1f4a..1a3b1a0aa 100644 --- a/docs/en/docs/deployment/https.md +++ b/docs/en/docs/deployment/https.md @@ -7,42 +7,184 @@ But it is way more complex than that. !!! tip If you are in a hurry or don't care, continue with the next sections for step by step instructions to set everything up with different techniques. -To learn the basics of HTTPS, from a consumer perspective, check https://howhttps.works/. +To **learn the basics of HTTPS**, from a consumer perspective, check https://howhttps.works/. -Now, from a developer's perspective, here are several things to have in mind while thinking about HTTPS: +Now, from a **developer's perspective**, here are several things to have in mind while thinking about HTTPS: -* For HTTPS, the server needs to have "certificates" generated by a third party. - * Those certificates are actually acquired from the third-party, not "generated". -* Certificates have a lifetime. - * They expire. - * And then they need to be renewed, acquired again from the third party. -* The encryption of the connection happens at the TCP level. - * That's one layer below HTTP. - * So, the certificate and encryption handling is done before HTTP. -* TCP doesn't know about "domains". Only about IP addresses. - * The information about the specific domain requested goes in the HTTP data. -* The HTTPS certificates "certify" a certain domain, but the protocol and encryption happen at the TCP level, before knowing which domain is being dealt with. -* By default, that would mean that you can only have one HTTPS certificate per IP address. +* For HTTPS, **the server** needs to **have "certificates"** generated by a **third party**. + * Those certificates are actually **acquired** from the third party, not "generated". +* Certificates have a **lifetime**. + * They **expire**. + * And then they need to be **renewed**, **acquired again** from the third party. +* The encryption of the connection happens at the **TCP level**. + * That's one layer **below HTTP**. + * So, the **certificate and encryption** handling is done **before HTTP**. +* **TCP doesn't know about "domains"**. Only about IP addresses. + * The information about the **specific domain** requested goes in the **HTTP data**. +* The **HTTPS certificates** "certify" a **certain domain**, but the protocol and encryption happen at the TCP level, **before knowing** which domain is being dealt with. +* **By default**, that would mean that you can only have **one HTTPS certificate per IP address**. * No matter how big your server is or how small each application you have on it might be. - * There is a solution to this, however. -* There's an extension to the TLS protocol (the one handling the encryption at the TCP level, before HTTP) called SNI. - * This SNI extension allows one single server (with a single IP address) to have several HTTPS certificates and serve multiple HTTPS domains/applications. - * For this to work, a single component (program) running on the server, listening on the public IP address, must have all the HTTPS certificates in the server. -* After obtaining a secure connection, the communication protocol is still HTTP. - * The contents are encrypted, even though they are being sent with the HTTP protocol. + * There is a **solution** to this, however. +* There's an **extension** to the **TLS** protocol (the one handling the encryption at the TCP level, before HTTP) called **SNI**. + * This SNI extension allows one single server (with a **single IP address**) to have **several HTTPS certificates** and serve **multiple HTTPS domains/applications**. + * For this to work, a **single** component (program) running on the server, listening on the **public IP address**, must have **all the HTTPS certificates** in the server. +* **After** obtaining a secure connection, the communication protocol is **still HTTP**. + * The contents are **encrypted**, even though they are being sent with the **HTTP protocol**. -It is a common practice to have one program/HTTP server running on the server (the machine, host, etc.) and managing all the HTTPS parts : sending the decrypted HTTP requests to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the HTTP response from the application, encrypt it using the appropriate certificate and sending it back to the client using HTTPS. This server is often called a TLS Termination Proxy. +It is a common practice to have **one program/HTTP server** running on the server (the machine, host, etc.) and **managing all the HTTPS parts**: receiving the **encrypted HTTPS requests**, sending the **decrypted HTTP requests** to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the **HTTP response** from the application, **encrypt it** using the appropriate **HTTPS certificate** and sending it back to the client using **HTTPS**. This server is often called a **TLS Termination Proxy**. + +Some of the options you could use as a TLS Termination Proxy are: + +* Traefik (that can also handle certificate renewals) +* Caddy (that can also handle certificate renewals) +* Nginx +* HAProxy ## Let's Encrypt -Before Let's Encrypt, these HTTPS certificates were sold by trusted third-parties. +Before Let's Encrypt, these **HTTPS certificates** were sold by trusted third parties. The process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive. -But then Let's Encrypt was created. +But then **Let's Encrypt** was created. -It is a project from the Linux Foundation. It provides HTTPS certificates for free. In an automated way. These certificates use all the standard cryptographic security, and are short lived (about 3 months), so the security is actually better because of their reduced lifespan. +It is a project from the Linux Foundation. It provides **HTTPS certificates for free**, in an automated way. These certificates use all the standard cryptographic security, and are short-lived (about 3 months), so the **security is actually better** because of their reduced lifespan. The domains are securely verified and the certificates are generated automatically. This also allows automating the renewal of these certificates. -The idea is to automate the acquisition and renewal of these certificates, so that you can have secure HTTPS, for free, forever. +The idea is to automate the acquisition and renewal of these certificates so that you can have **secure HTTPS, for free, forever**. + +## HTTPS for Developers + +Here's an example of how an HTTPS API could look like, step by step, paying attention mainly to the ideas important for developers. + +### Domain Name + +It would probably all start by you **acquiring** some **domain name**. Then, you would configure it in a DNS server (possibly your same cloud provider). + +You would probably get a cloud server (a virtual machine) or something similar, and it would have a fixed **public IP address**. + +In the DNS server(s) you would configure a record (an "`A record`") to point **your domain** to the public **IP address of your server**. + +You would probably do this just once, the first time, when setting everything up. + +!!! tip + This Domain Name part is way before HTTPS, but as everything depends on the domain and the IP address, it's worth mentioning it here. + +### DNS + +Now let's focus on all the actual HTTPS parts. + +First, the browser would check with the **DNS servers** what is the **IP for the domain**, in this case, `someapp.example.com`. + +The DNS servers would tell the browser to use some specific **IP address**. That would be the public IP address used by your server, that you configured in the DNS servers. + + + +### TLS Handshake Start + +The browser would then communicate with that IP address on **port 443** (the HTTPS port). + +The first part of the communication is just to establish the connection between the client and the server and to decide the cryptographic keys they will use, etc. + + + +This interaction between the client and the server to establish the TLS connection is called the **TLS handshake**. + +### TLS with SNI Extension + +**Only one process** in the server can be listening on a specific **port** in a specific **IP address**. There could be other processes listening on other ports in the same IP address, but only one for each combination of IP address and port. + +TLS (HTTPS) uses the specific port `443` by default. So that's the port we would need. + +As only one process can be listening on this port, the process that would do it would be the **TLS Termination Proxy**. + +The TLS Termination Proxy would have access to one or more **TLS certificates** (HTTPS certificates). + +Using the **SNI extension** discussed above, the TLS Termination Proxy would check which of the TLS (HTTPS) certificates available it should use for this connection, using the one that matches the domain expected by the client. + +In this case, it would use the certificate for `someapp.example.com`. + + + +The client already **trusts** the entity that generated that TLS certificate (in this case Let's Encrypt, but we'll see about that later), so it can **verify** that the certificate is valid. + +Then, using the certificate, the client and the TLS Termination Proxy **decide how to encrypt** the rest of the **TCP communication**. This completes the **TLS Handshake** part. + +After this, the client and the server have an **encrypted TCP connection**, this is what TLS provides. And then they can use that connection to start the actual **HTTP communication**. + +And that's what **HTTPS** is, it's just plain **HTTP** inside a **secure TLS connection** instead of a pure (unencrypted) TCP connection. + +!!! tip + Notice that the encryption of the communication happens at the **TCP level**, not at the HTTP level. + +### HTTPS Request + +Now that the client and server (specifically the browser and the TLS Termination Proxy) have an **encrypted TCP connection**, they can start the **HTTP communication**. + +So, the client sends an **HTTPS request**. This is just an HTTP request through an encrypted TLS connection. + + + +### Decrypt the Request + +The TLS Termination Proxy would use the encryption agreed to **decrypt the request**, and would transmit the **plain (decrypted) HTTP request** to the process running the application (for example a process with Uvicorn running the FastAPI application). + + + +### HTTP Response + +The application would process the request and send a **plain (unencrypted) HTTP response** to the TLS Termination Proxy. + + + +### HTTPS Response + +The TLS Termination Proxy would then **encrypt the response** using the cryptography agreed before (that started with the certificate for `someapp.example.com`), and send it back to the browser. + +Next, the browser would verify that the response is valid and encrypted with the right cryptographic key, etc. It would then **decrypt the response** and process it. + + + +The client (browser) will know that the response comes from the correct server because it is using the cryptography they agreed using the **HTTPS certificate** before. + +### Multiple Applications + +In the same server (or servers), there could be **multiple applications**, for example, other API programs or a database. + +Only one process can be handling the specific IP and port (the TLS Termination Proxy in our example) but the other applications/processes can be running on the server(s) too, as long as they don't try to use the same **combination of public IP and port**. + + + +That way, the TLS Termination Proxy could handle HTTPS and certificates for **multiple domains**, for multiple applications, and then transmit the requests to the right application in each case. + +### Certificate Renewal + +At some point in the future, each certificate would **expire** (about 3 months after acquiring it). + +And then, there would be another program (in some cases it's another program, in some cases it could be the same TLS Termination Proxy) that would talk to Let's Encrypt, and renew the certificate(s). + + + +The **TLS certificates** are **associated with a domain name**, not with an IP address. + +So, to renew the certificates, the renewal program needs to **prove** to the authority (Let's Encrypt) that it indeed **"owns" and controls that domain**. + +To do that, and to accommodate different application needs, there are several ways it can do it. Some popular ways are: + +* **Modify some DNS records**. + * For this, the renewal program needs to support the APIs of the DNS provider, so, depending on the DNS provider you are using, this might or might not be an option. +* **Run as a server** (at least during the certificate acquisition process) on the public IP address associated with the domain. + * As we said above, only one process can be listening on a specific IP and port. + * This is one of the reasons why it's very useful when the same TLS Termination Proxy also takes care of the certificate renewal process. + * Otherwise, you might have to stop the TLS Termination Proxy momentarily, start the renewal program to acquire the certificates, then configure them with the TLS Termination Proxy, and then restart the TLS Termination Proxy. This is not ideal, as your app(s) will not be available during the time that the TLS Termination Proxy is off. + +All this renewal process, while still serving the app, is one of the main reasons why you would want to have a **separate system to handle HTTPS** with a TLS Termination Proxy instead of just using the TLS certificates with the application server directly (e.g. Uvicorn). + +## Recap + +Having **HTTPS** is very important, and quite **critical** in most cases. Most of the effort you as a developer have to put around HTTPS is just about **understanding these concepts** and how they work. + +But once you know the basic information of **HTTPS for developers** you can easily combine and configure different tools to help you manage everything in a simple way. + +In some of the next chapters I'll show you several concrete examples of how to set up **HTTPS** for **FastAPI** applications. 🔒 diff --git a/docs/en/docs/img/deployment/https/https.drawio b/docs/en/docs/img/deployment/https/https.drawio new file mode 100644 index 000000000..31cfab96b --- /dev/null +++ b/docs/en/docs/img/deployment/https/https.drawio @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https.svg b/docs/en/docs/img/deployment/https/https.svg new file mode 100644 index 000000000..e63345eba --- /dev/null +++ b/docs/en/docs/img/deployment/https/https.svg @@ -0,0 +1,62 @@ +
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
TLS Termination Proxy
TLS Termination Proxy +
Cert Renovation Program
Cert Renovation Program
Let's Encrypt
Let's Encrypt
FastAPI app for: someapp.example.com
FastAPI app for: someapp.example.com
Another app: another.example.com
Another app: another.example.com
One more app: onemore.example.com
One more app: onemore.example.com
A Database
A Database
Plain response from: someapp.example.com
Plain response from: someapp.example.com
Port 443 (HTTPS)
Port 443 (HTTPS)
Encrypted request for: someapp.example.com
Encrypted request for: someapp.example.com
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
Renew HTTPS cert for: someapp.example.com
Renew HTTPS cert for: someapp.example.com
New HTTPS cert for: someapp.example.com
New HTTPS cert for: someapp.example.com
TLS Handshake
TLS Handshake
Encrypted response from: someapp.example.com
Encrypted response from: someapp.example.com
HTTPS certificates
HTTPS certificates +
someapp.example.com
someapp.example.com +
another.example.net
another.example.net +
onemore.example.org
onemore.example.org +
IP:
123.124.125.126
IP:...
Decrypted request for: someapp.example.com
Decrypted request for: someapp.example.com
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https01.drawio b/docs/en/docs/img/deployment/https/https01.drawio new file mode 100644 index 000000000..9bc5340ce --- /dev/null +++ b/docs/en/docs/img/deployment/https/https01.drawio @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https01.svg b/docs/en/docs/img/deployment/https/https01.svg new file mode 100644 index 000000000..4fee0adfc --- /dev/null +++ b/docs/en/docs/img/deployment/https/https01.svg @@ -0,0 +1,57 @@ +
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https02.drawio b/docs/en/docs/img/deployment/https/https02.drawio new file mode 100644 index 000000000..0f7578d3e --- /dev/null +++ b/docs/en/docs/img/deployment/https/https02.drawio @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https02.svg b/docs/en/docs/img/deployment/https/https02.svg new file mode 100644 index 000000000..1f37a7098 --- /dev/null +++ b/docs/en/docs/img/deployment/https/https02.svg @@ -0,0 +1,57 @@ +
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
Port 443 (HTTPS)
Port 443 (HTTPS)
IP:
123.124.125.126
IP:...
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
TLS Handshake
TLS Handshake
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https03.drawio b/docs/en/docs/img/deployment/https/https03.drawio new file mode 100644 index 000000000..c5766086c --- /dev/null +++ b/docs/en/docs/img/deployment/https/https03.drawio @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https03.svg b/docs/en/docs/img/deployment/https/https03.svg new file mode 100644 index 000000000..e68e1c459 --- /dev/null +++ b/docs/en/docs/img/deployment/https/https03.svg @@ -0,0 +1,62 @@ +
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
TLS Termination Proxy
TLS Termination Proxy +
Port 443 (HTTPS)
Port 443 (HTTPS)
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
TLS Handshake
TLS Handshake
HTTPS certificates
HTTPS certificates +
someapp.example.com
someapp.example.com +
another.example.net
another.example.net +
onemore.example.org
onemore.example.org +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https04.drawio b/docs/en/docs/img/deployment/https/https04.drawio new file mode 100644 index 000000000..ea357a6c1 --- /dev/null +++ b/docs/en/docs/img/deployment/https/https04.drawio @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https04.svg b/docs/en/docs/img/deployment/https/https04.svg new file mode 100644 index 000000000..4c9b7999b --- /dev/null +++ b/docs/en/docs/img/deployment/https/https04.svg @@ -0,0 +1,62 @@ +
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
TLS Termination Proxy
TLS Termination Proxy +
Port 443 (HTTPS)
Port 443 (HTTPS)
Encrypted request for: someapp.example.com
Encrypted request for: someapp.example.com
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
TLS Handshake
TLS Handshake
HTTPS certificates
HTTPS certificates +
someapp.example.com
someapp.example.com +
another.example.net
another.example.net +
onemore.example.org
onemore.example.org +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https05.drawio b/docs/en/docs/img/deployment/https/https05.drawio new file mode 100644 index 000000000..9b8b7c6f7 --- /dev/null +++ b/docs/en/docs/img/deployment/https/https05.drawio @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https05.svg b/docs/en/docs/img/deployment/https/https05.svg new file mode 100644 index 000000000..d11647b9b --- /dev/null +++ b/docs/en/docs/img/deployment/https/https05.svg @@ -0,0 +1,62 @@ +
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
TLS Termination Proxy
TLS Termination Proxy +
FastAPI app for: someapp.example.com
FastAPI app for: someapp.example.com
Decrypted request for: someapp.example.com
Decrypted request for: someapp.example.com
Port 443 (HTTPS)
Port 443 (HTTPS)
Encrypted request for: someapp.example.com
Encrypted request for: someapp.example.com
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
TLS Handshake
TLS Handshake
HTTPS certificates
HTTPS certificates +
someapp.example.com
someapp.example.com +
another.example.net
another.example.net +
onemore.example.org
onemore.example.org +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https06.drawio b/docs/en/docs/img/deployment/https/https06.drawio new file mode 100644 index 000000000..5bb85813f --- /dev/null +++ b/docs/en/docs/img/deployment/https/https06.drawio @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https06.svg b/docs/en/docs/img/deployment/https/https06.svg new file mode 100644 index 000000000..10e03b7c5 --- /dev/null +++ b/docs/en/docs/img/deployment/https/https06.svg @@ -0,0 +1,62 @@ +
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
TLS Termination Proxy
TLS Termination Proxy +
FastAPI app for: someapp.example.com
FastAPI app for: someapp.example.com
Plain response from: someapp.example.com
Plain response from: someapp.example.com
Decrypted request for: someapp.example.com
Decrypted request for: someapp.example.com
Port 443 (HTTPS)
Port 443 (HTTPS)
Encrypted request for: someapp.example.com
Encrypted request for: someapp.example.com
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
TLS Handshake
TLS Handshake
HTTPS certificates
HTTPS certificates +
someapp.example.com
someapp.example.com +
another.example.net
another.example.net +
onemore.example.org
onemore.example.org +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https07.drawio b/docs/en/docs/img/deployment/https/https07.drawio new file mode 100644 index 000000000..1ca994b22 --- /dev/null +++ b/docs/en/docs/img/deployment/https/https07.drawio @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https07.svg b/docs/en/docs/img/deployment/https/https07.svg new file mode 100644 index 000000000..e409d8871 --- /dev/null +++ b/docs/en/docs/img/deployment/https/https07.svg @@ -0,0 +1,62 @@ +
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
TLS Termination Proxy
TLS Termination Proxy +
FastAPI app for: someapp.example.com
FastAPI app for: someapp.example.com
Plain response from: someapp.example.com
Plain response from: someapp.example.com
Decrypted request for: someapp.example.com
Decrypted request for: someapp.example.com
Port 443 (HTTPS)
Port 443 (HTTPS)
Encrypted request for: someapp.example.com
Encrypted request for: someapp.example.com
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
TLS Handshake
TLS Handshake
Encrypted response from: someapp.example.com
Encrypted response from: someapp.example.com
HTTPS certificates
HTTPS certificates +
someapp.example.com
someapp.example.com +
another.example.net
another.example.net +
onemore.example.org
onemore.example.org +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https08.drawio b/docs/en/docs/img/deployment/https/https08.drawio new file mode 100644 index 000000000..8a4f41056 --- /dev/null +++ b/docs/en/docs/img/deployment/https/https08.drawio @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/https/https08.svg b/docs/en/docs/img/deployment/https/https08.svg new file mode 100644 index 000000000..3047dd821 --- /dev/null +++ b/docs/en/docs/img/deployment/https/https08.svg @@ -0,0 +1,62 @@ +
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
TLS Termination Proxy
TLS Termination Proxy +
FastAPI app for: someapp.example.com
FastAPI app for: someapp.example.com
Another app: another.example.com
Another app: another.example.com
One more app: onemore.example.com
One more app: onemore.example.com
A Database
A Database
Plain response from: someapp.example.com
Plain response from: someapp.example.com
Decrypted request for: someapp.example.com
Decrypted request for: someapp.example.com
Port 443 (HTTPS)
Port 443 (HTTPS)
Encrypted request for: someapp.example.com
Encrypted request for: someapp.example.com
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
TLS Handshake
TLS Handshake
Encrypted response from: someapp.example.com
Encrypted response from: someapp.example.com
HTTPS certificates
HTTPS certificates +
someapp.example.com
someapp.example.com +
another.example.net
another.example.net +
onemore.example.org
onemore.example.org +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1
\ No newline at end of file From fe086a490396eff622a067468531c8776343217f Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 27 Sep 2021 14:41:20 +0000 Subject: [PATCH 197/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a581cf394..f67b11f0f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Upgrade HTTPS guide with more explanations and diagrams. PR [#3950](https://github.com/tiangolo/fastapi/pull/3950) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add German translation for `docs/features.md`. PR [#3699](https://github.com/tiangolo/fastapi/pull/3699) by [@mawassk](https://github.com/mawassk). * 🎨 Tweak CSS styles for shell animations. PR [#3888](https://github.com/tiangolo/fastapi/pull/3888) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new Sponsor Calmcode.io. PR [#3777](https://github.com/tiangolo/fastapi/pull/3777) by [@tiangolo](https://github.com/tiangolo). From cb7e79ab8a27b8f453ded2674adb92f8738d7cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 1 Oct 2021 22:44:19 +0200 Subject: [PATCH 198/814] =?UTF-8?q?=F0=9F=93=9D=20Re-write=20and=20extend?= =?UTF-8?q?=20Deployment=20guide:=20Concepts,=20Uvicorn,=20Gunicorn,=20Doc?= =?UTF-8?q?ker,=20Containers,=20Kubernetes=20(#3974)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/deployment/concepts.md | 311 +++++++++ docs/en/docs/deployment/deta.md | 18 + docs/en/docs/deployment/docker.md | 655 ++++++++++++++++-- docs/en/docs/deployment/index.md | 16 +- docs/en/docs/deployment/manually.md | 50 +- docs/en/docs/deployment/server-workers.md | 178 +++++ .../docs/img/deployment/concepts/image01.png | Bin 0 -> 124827 bytes .../deployment/concepts/process-ram.drawio | 106 +++ .../img/deployment/concepts/process-ram.svg | 59 ++ docs/en/mkdocs.yml | 6 +- 10 files changed, 1320 insertions(+), 79 deletions(-) create mode 100644 docs/en/docs/deployment/concepts.md create mode 100644 docs/en/docs/deployment/server-workers.md create mode 100644 docs/en/docs/img/deployment/concepts/image01.png create mode 100644 docs/en/docs/img/deployment/concepts/process-ram.drawio create mode 100644 docs/en/docs/img/deployment/concepts/process-ram.svg diff --git a/docs/en/docs/deployment/concepts.md b/docs/en/docs/deployment/concepts.md new file mode 100644 index 000000000..d22b53fe0 --- /dev/null +++ b/docs/en/docs/deployment/concepts.md @@ -0,0 +1,311 @@ +# Deployments Concepts + +When deploying a **FastAPI** application, or actually, any type of web API, there are several concepts that you probably care about, and using them you can find the **most appropriate** way to **deploy your application**. + +Some of the important concepts are: + +* Security - HTTPS +* Running on startup +* Restarts +* Replication (the number of processes running) +* Memory +* Previous steps before starting + +We'll see how they would affect **deployments**. + +In the end, the ultimate objective is to be able to **serve your API clients** in a way that is **secure**, to **avoid disruptions**, and to use the **compute resources** (for example remote servers/virtual machines) as efficiently as possible. 🚀 + +I'll tell you a bit more about these **concepts** here, and that would hopefully give you the **intuition** you would need to decide how to deploy your API in very different environments, possibly even in **future** ones that don't exist yet. + +By considering these concepts, you will be able to **evaluate and design** the best way to deploy **your own APIs**. + +In the next chapters, I'll give you more **concrete recipes** to deploy FastAPI applications. + +But for now, let's check these important **conceptual ideas**. These concepts also apply for any other type of web API. 💡 + +## Security - HTTPS + +In the [previous chapter about HTTPS](./https.md){.internal-link target=_blank} we learned about how HTTPS provides encryption for your API. + +We also saw that HTTPS is normally provided by a component **external** to your application server, a **TLS Termination Proxy**. + +And there has to be something in charge of **renewing the HTTPS certificates**, it could be the same component or it could be something different. + +### Example Tools for HTTPS + +Some of the tools you could use as a TLS Termination Proxy are: + +* Traefik + * Automatically handles certificates renewals ✨ +* Caddy + * Automatically handles certificates renewals ✨ +* Nginx + * With an external component like Certbot for certificate renewals +* HAProxy + * With an external component like Certbot for certificate renewals +* Kubernetes with an Ingress Controller like Nginx + * With an external component like cert-manager for certificate renewals +* Handled internally by a cloud provider as part of their services (read below 👇) + +Another option is that you could use a **cloud service** that does more of the work including setting up HTTPS. It could have some restrictions or charge you more, etc. But in that case you wouldn't have to set up a TLS Termination Proxy yourself. + +I'll show you some concrete examples in the next chapters. + +--- + +Then the next concepts to consider are all about the program running your actual API (e.g. Uvicorn). + +## Program and Process + +We will talk a lot about the running "**process**", so it's useful to have clarity about what it means, and what's the difference with the word "**program**". + +### What is a Program + +The word **program** is commonly used to describe many things: + +* The **code** that you write, the **Python files**. +* The **file** that can be **executed** by the operating system, for example `python`, `python.exe` or `uvicorn`. +* A particular program while it is **running** on the operating system, using the CPU, and storing things on memory. This is also called a **process**. + +### What is a Process + +The word **process** is normally used in a more specific way, only referring to the thing that is running in the operating system (like in the last point above): + +* A particular program while it is **running** on the operating system. + * This doesn't refer to the file, nor to the code, it refers **specifically** to the thing that is being **executed** and managed by the operating system. +* Any program, any code, **can only do things** when it is being **executed**. So, when there's a **process running**. +* The process can be **terminated** (or "killed") by you, or by the operating system. At that point, it stops running/being executed, and it can **no longer do things**. +* Each application that you have running in your computer has some process behind it, each running program, each window, etc. And there are normally many processes running **at the same time** while a computer is on. +* There can be **multiple processes** of the **same program** running at the same time. + +If you check out the "task manager" or "system monitor" (or similar tools) in your operating system, you will be able to see many of those processes running. + +And, for example, you will probably see that there are multiple processes running the same browser program (Firefox, Chrome, Edge, etc). They normally run one process per tab, plus some other extra processes. + + + +--- + +Now that we know the difference between the terms **process** and **program**, let's continue talking about deployments. + +## Running on Startup + +In most cases, when you create a web API, you want it to be **always running**, uninterrupted, so that your clients can always access it. This is of course, unless you have a specific reason why you want it to run only on certain situations, but most of the time you want it constantly running and **available**. + +### In a Remote Server + +When you set up a remote server (a cloud server, a virtual machine, etc.) the simplest thing you can do is to run Uvicorn (or similar) manually, the same way you do when developing locally. + +And it will work, and will be useful **during development**. + +But if your connection to the server is lost, the **running process** will probably die. + +And if the server is restarted (for example after updates, or migrations from the cloud provider) you probably **won't notice it**. And because of that, you won't even know that you have to restart the process manually. So, your API will just stay dead. 😱 + +### Run Automatically on Startup + +In general, you will probably want the server program (e.g. Uvicorn) to be started automatically on server startup, and without needing any **human intervention**, to have a process always running with your API (e.g. Uvicorn running your FastAPI app). + +### Separate Program + +To achieve this, you will normally have a **separate program** that would make sure your application is run on startup. And in many cases it would also make sure other components or applications are also run, for example a database. + +### Example Tools to Run at Startup + +Some examples of the tools that can do this job are: + +* Docker +* Kubernetes +* Docker Compose +* Docker in Swarm Mode +* Systemd +* Supervisor +* Handled internally by a cloud provider as part of their services +* Others... + +I'll give you more concrete examples in the next chapters. + +## Restarts + +Similar to making sure your application is run on startup, you probably also want to make sure it is **restarted** after failures. + +### We Make Mistakes + +We, as humans, make **mistakes**, all the time. Software almost *always* has **bugs** hidden in different places. 🐛 + +And we as developers keep improving the code as we find those bugs and as we implement new features (possibly adding new bugs too 😅). + +### Small Errors Automatically Handled + +When building web APIs with FastAPI, if there's an error in our code, FastAPI will normally contain it to the single request that triggered the error. 🛡 + +The client will get a **500 Internal Server Error** for that request, but the application will continue working for the next requests instead of just crashing completely. + +### Bigger Errors - Crashes + +Nevertheless, there might be cases where we write some code that **crashes the entire application** making Uvicorn and Python crash. 💥 + +And still, you would probably not want the application to stay dead because there was an error in one place, you probably want it to **continue running** at least for the *path operations* that are not broken. + +### Restart After Crash + +But in those cases with really bad errors that crash the running **process**, you would want an external component that is in charge of **restarting** the process, at least a couple of times... + +!!! tip + ...Although if the whole application is just **crashing immediately** it probably doesn't make sense to keep restarting it forever. But in those cases, you will probably notice it during development, or at least right after deployment. + + So let's focus on the main cases, where it could crash entirely in some particular cases **in the future**, and it still makes sense to restart it. + +You would probably want to have the thing in charge of restarting your application as an **external component**, because by that point, the same application with Uvicorn and Python already crashed, so there's nothing in the same code of the same app that could do anything about it. + +### Example Tools to Restart Automatically + +In most cases, the same tool that is used to **run the program on startup** is also used to handle automatic **restarts**. + +For example, this could be handled by: + +* Docker +* Kubernetes +* Docker Compose +* Docker in Swarm Mode +* Systemd +* Supervisor +* Handled internally by a cloud provider as part of their services +* Others... + +## Replication - Processes and Memory + +With a FastAPI application, using a server program like Uvicorn, running it once in **one process** can serve multiple clients concurrently. + +But in many cases you will want to run several worker processes at the same time. + +### Multiple Processes - Workers + +If you have more clients than what a single process can handle (for example if the virtual machine is not too big) and you have **multiple cores** in the server's CPU, then you could have **multiple processes** running with the same application at the same time, and distribute all the requests among them. + +When you run **multiple processes** of the same API program, they are commonly called **workers**. + +### Worker Processes and Ports + +Remember from the docs [About HTTPS](./https.md){.internal-link target=_blank} that only one process can be listening on one combination of port and IP address in a server? + +This is still true. + +So, to be able to have **multiple processes** at the same time, there has to be a **single process listening on a port** that then transmits the communication to each worker process in some way. + +### Memory per Process + +Now, when the program loads things in memory, for example, a machine learning model in a variable, or the contents of a large file in a variable, all that **consumes a bit of the memory (RAM)** of the server. + +And multiple processes normally **don't share any memory**. This means that each running process has its own things, its own variables, its own memory. And if you are consuming a large amount of memory in your code, **each process** will consume an equivalent amount of memory. + +### Server Memory + +For example, if your code loads a Machine Learning model with **1 GB in size**, when you run one process with your API, it will consume at least 1 GB or RAM. And if you start **4 processes** (4 workers), each will consume 1 GB of RAM. So, in total your API will consume **4 GB of RAM**. + +And if your remote server or virtual machine only has 3 GB of RAM, trying to load more than 4 GB of RAM will cause problems. 🚨 + +### Multiple Processes - An Example + +In this example, there's a **Manager Process** that starts and controls two **Worker Processes**. + +This Manager Process would probably be the one listening on the **port** in the IP. And it would transmit all the communication to the worker processes. + +Those worker processes would be the ones running your application, they would perform the main computations to receive a **request** and return a **response**, and they would load anything you put in variables in RAM. + + + +And of course, the same machine would probably have **other processes** running as well, apart from your application. + +An interesting detail is that the percentage of the **CPU used** by each process can **vary** a lot over time, but the **memory (RAM)** normally stays more or less **stable**. + +If you have an API that does a comparable amount of computations every time and you have a lot of clients, then the **CPU utilization** will probably *also be stable* (instead of constantly going up and down quickly). + +### Examples of Replication Tools and Strategies + +There can be several approaches to achieve this, and I'll tell you more about specific strategies in the next chapters, for example when talking about Docker and containers. + +The main constraint to consider is that there has to be a **single** component handling the **port** in the **public IP**. And then it has to have a way to **transmit** the communication to the replicated **processes/workers**. + +Here are some possible combinations and strategies: + +* **Gunicorn** managing **Uvicorn workers** + * Gunicorn would be the **process manager** listening on the **IP** and **port**, the replication would be by having **multiple Uvicorn worker processes** +* **Uvicorn** managing **Uvicorn workers** + * One Uvicorn **process manager** would listen on the **IP** and **port**, and it would start **multiple Uvicorn worker processes** +* **Kubernetes** and other distributed **container systems** + * Something in the **Kubernetes** layer would listen on the **IP** and **port**. The replication would be by having **multiple containers**, each with **one Uvicorn process** running +* **Cloud services** that handle this for your + * The cloud service will probably **handle replication for you**. It would possibly let you define **a process to run**, or a **container image** to use, in any case, it would most probably be **a single Uvicorn process**, and the cloud service would be in charge of replicating it. + +!!! tip + Don't worry if some of these items about **containers**, Docker, or Kubernetes don't make a lot of sense yet. + + I'll tell you more about container images, Docker, Kubernetes, etc. in a future chapter: [FastAPI in Containers - Docker](./docker.md){.internal-link target=_blank}. + +## Previous Steps Before Starting + +There are many cases where you want to perform some steps **before starting** your application. + +For example, you might want to run **database migrations**. + +But in most cases, you will want to perform these steps only **once**. + +So, you will want to have a **single process** to perform those **previous steps**, before starting the application. + +And you will have to make sure that it's a single process running those previous steps *even* if afterwards you start **multiple processes** (multiple workers) for the application itself. If those steps were run by **multiple processes**, they would **duplicate** the work by running it on **parallel**, and if the steps were something delicate like a database migration, they could cause conflicts with each other. + +Of course, there are some cases where there's no problem in running the previous steps multiple times, in that case it's a lot easier to handle. + +!!! tip + Also have in mind that depending on your setup, in some cases you **might not even need any previous steps** before starting your application. + + In that case, you wouldn't have to worry about any of this. 🤷 + +### Examples of Previous Steps Strategies + +This will **depend heavily** on the way you **deploy your system**, and it would probably be connected to the way you start programs, handling restarts, etc. + +Here are some possible ideas: + +* An "Init Container" in Kubernetes that runs before your app container +* A bash script that runs the previous steps and then starts your application + * You would still need a way to start/restart *that* bash script, detect errors, etc. + +!!! tip + I'll give you more concrete examples for doing this with containers in a future chapter: [FastAPI in Containers - Docker](./docker.md){.internal-link target=_blank}. + +## Resource Utilization + +Your server(s) is (are) a **resource**, you can consume or **utilize**, with your programs, the computation time on the CPUs, and the RAM memory available. + +How much resources do you want to be consuming/utilizing? It might be easy to think "not much", but in reality, you will probably want to consume **as much as possible without crashing**. + +If you are paying for 3 servers but you are using only a little bit of their RAM and CPU, you are probably **wasting money** 💸, and probably **wasting server electric power** 🌎, etc. + +In that case, it could be better to have only 2 servers and use a higher percentage of their resources (CPU, memory, disk, network bandwidth, etc). + +On the other hand, if you have 2 servers and you are using **100% of their CPU and RAM**, at some point one process will ask for more memory, and the server will have to use the disk as "memory" (which can be thousands of times slower), or even **crash**. Or one process might need to do some computation and would have to wait until the CPU is free again. + +In this case, it would be better to get **one extra server** and run some processes on it so that they all have **enough RAM and CPU time**. + +There's also the chance that for some reason you have a **spike** of usage of your API. Maybe it went viral, or maybe some other services or bots start using it. And you might want to have extra resources to be safe in those cases. + +You could put an **arbitrary number** to target, for example something **between 50% to 90%** of resource utilization. The point is that those are probably the main things you will want to measure and use to tweak your deployments. + +You can use simple tools like `htop` to see the CPU and RAM used in your server, or the amount used by each process. Or you can use more complex monitoring tools, maybe distributed across servers, etc. + +## Recap + +You have been reading here some of the main concepts that you would probably need to have in mind when deciding how to deploy your application: + +* Security - HTTPS +* Running on startup +* Restarts +* Replication (the number of processes running) +* Memory +* Previous steps before starting + +Understanding these ideas and how to apply them should give you the intuition necessary to take any decisions when configuring and tweaking your deployments. 🤓 + +In the next sections I'll give you more concrete examples of possible strategies you can follow. 🚀 diff --git a/docs/en/docs/deployment/deta.md b/docs/en/docs/deployment/deta.md index fd4b30a3c..b0d1cb928 100644 --- a/docs/en/docs/deployment/deta.md +++ b/docs/en/docs/deployment/deta.md @@ -238,3 +238,21 @@ You can also edit them and re-play them. At some point you will probably want to store some data for your app in a way that persists through time. For that you can use Deta Base, it also has a generous **free tier**. You can also read more in the Deta Docs. + +## Deployment Concepts + +Coming back to the concepts we discussed in [Deployments Concepts](./concepts.md){.internal-link target=_blank}, here's how each of them would be handled with Deta: + +* **HTTPS**: Handled by Deta, they will give you a subdomain and handle HTTPS automatically. +* **Running on startup**: Handled by Deta, as part of their service. +* **Restarts**: Handled by Deta, as part of their service. +* **Replication**: Handled by Deta, as part of their service. +* **Memory**: Limit predefined by Deta, you could contact them to increase it. +* **Previous steps before starting**: Not directly supported, you could make it work with their Cron system or additional scripts. + +!!! note + Deta is designed to make it easy (and free) to deploy simple applications quickly. + + It can simplify a lot several use cases, but at the same time it doesn't support others, like using external databases (apart from Deta's own NoSQL database system), custom virtual machines, etc. + + You can read more details in the Deta docs to see if it's the right choice for you. diff --git a/docs/en/docs/deployment/docker.md b/docs/en/docs/deployment/docker.md index e32a2969d..e25401f20 100644 --- a/docs/en/docs/deployment/docker.md +++ b/docs/en/docs/deployment/docker.md @@ -1,67 +1,144 @@ -# Deploy with Docker +# FastAPI in Containers - Docker -In this section you'll see instructions and links to guides to know how to: +When deploying FastAPI applications a common approach is to build a **Linux container image**. It's normally done using **Docker**. And then you can deploy that container image in one of different possible ways. -* Make your **FastAPI** application a Docker image/container with maximum performance. In about **5 min**. -* (Optionally) understand what you, as a developer, need to know about HTTPS. -* Set up a Docker Swarm mode cluster with automatic HTTPS, even on a simple $5 USD/month server. In about **20 min**. -* Generate and deploy a full **FastAPI** application, using your Docker Swarm cluster, with HTTPS, etc. In about **10 min**. - -You can use **Docker** for deployment. It has several advantages like security, replicability, development simplicity, etc. - -If you are using Docker, you can use the official Docker image: - -## tiangolo/uvicorn-gunicorn-fastapi - -This image has an "auto-tuning" mechanism included, so that you can just add your code and get very high performance automatically. And without making sacrifices. - -But you can still change and update all the configurations with environment variables or configuration files. +Using Linux containers has several advantages including **security**, **replicability**, **simplicity**, and others. !!! tip - To see all the configurations and options, go to the Docker image page: tiangolo/uvicorn-gunicorn-fastapi. + In a hurry and already know this stuff? Jump to the [`Dockerfile` below 👇](#build-a-docker-image-for-fastapi). -## Create a `Dockerfile` - -* Go to your project directory. -* Create a `Dockerfile` with: +
+Dockerfile Preview 👀 ```Dockerfile -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 +FROM python:3.9 -COPY ./app /app -``` +WORKDIR /code -### Bigger Applications +COPY ./requirements.txt /code/requirements.txt -If you followed the section about creating [Bigger Applications with Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}, your `Dockerfile` might instead look like: +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt -```Dockerfile -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 - -COPY ./app /app/app -``` - -### Raspberry Pi and other architectures - -If you are running Docker in a Raspberry Pi (that has an ARM processor) or any other architecture, you can create a `Dockerfile` from scratch, based on a Python base image (that is multi-architecture) and use Uvicorn alone. - -In this case, your `Dockerfile` could look like: - -```Dockerfile -FROM python:3.7 - -RUN pip install fastapi uvicorn - -EXPOSE 80 - -COPY ./app /app +COPY ./app /code/app CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] + +# If running behind a proxy like Nginx or Traefik add --proxy-headers +# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"] ``` -## Create the **FastAPI** Code +
+ +## What is a Container + +Containers (mainly Linux containers) are a very **lightweight** way to package applications including all their dependencies and necessary files while keeping them isolated from other containers (other applications or components) in the same system. + +Linux containers run using the same Linux kernel of the host (machine, virtual machine, cloud server, etc). This just means that they are very lightweight (compared to full virtual machines emulating an entire operating system). + +This way, containers consume **little resources**, an amount comparable to running the processes directly (a virtual machine would consume much more). + +Containers also have their own **isolated** running processes (commonly just one process), file system, and network, simplifying deployment, security, development, etc. + +## What is a Container Image + +A **container** is run from a **container image**. + +A container image is a **static** version of all the files, environment variables, and the default command/program that should be present in a container. **Static** here means that the container **image** is not running, it's not being executed, it's only the packaged files and metadata. + +In contrast to a "**container image**" that is the stored static contents, a "**container**" normally refers to the running instance, the thing that is being **executed**. + +When the **container** is started and running (started from a **container image**) it could create or change files, environment variables, etc. Those changes will exist only in that container, but would not persist in the underlying container image (would not be saved to disk). + +A container image is comparable to the **program** file and contents, e.g. `python` and some file `main.py`. + +And the **container** itself (in contrast to the **container image**) is the actual running instance of the image, comparable to a **process**. In fact, a container is running only when it has a **process running** (and normally it's only a single process). The container stops when there's no process running in it. + +## Container Images + +Docker has been one of the main tools to create and manage **container images** and **containers**. + +And there's a public Docker Hub with pre-made **official container images** for many tools, environments, databases, and applications. + +For example, there's an official Python Image. + +And there are many other images for different things like databases, for example for: + +* PostgreSQL +* MySQL +* MongoDB +* Redis, etc. + +By using a pre-made container image it's very easy to **combine** and use different tools. For example, to try out a new database. In most cases you can use the **official images**, and just configure them with environment variables. + +That way, in many cases you can learn about containers and Docker and re-use that knowledge with many different tools and components. + +So, you would run **multiple containers** with different things, like a database, a Python application, a web server with a React frontend application, and connect them together via their internal network. + +All the container management systems (like Docker or Kubernetes) have these networking features integrated in them. + +## Containers and Processes + +A **container image** normally includes in its metadata the default program or command that should be run when the **container** is started and the parameters to be passed to that program. Very similar to what would be if it was in the command line. + +When a **container** is started, it will run that command/program (although you can override it and make it run a different command/program). + +A container is running as long as the **main process** (command or program) is running. + +A container normally has a **single process**, but it's also possible to start subprocesses from the main process, and that way have **multiple processes** in the same container. + +But it's not possible to have a running container without **at least one running process**. If the main process stops, the container stops. + +## Build a Docker Image for FastAPI + +Okay, let's build something now! 🚀 + +I'll show you how to build a **Docker image** for FastAPI **from scratch**, based on the **official Python** image. + +This is what you would want to do in **most cases**, for example: + +* Using **Kubernetes** or similar tools +* When running on a **Raspberry Pi** +* Using a cloud service that would run a container image for you, etc. + +### Package Requirements + +You would normally have the **package requirements** for your application in some file. + +It would depend mainly on the tool you use to **install** those requirements. + +The most common way to do it is to have a file `requirements.txt` with the package names and their versions, one per line. + +You would of course use the same ideas you read in [About FastAPI versions](./versions.md){.internal-link target=_blank} to set the ranges of versions. + +For example, your `requirements.txt` could look like: + +``` +fastapi>=0.68.0,<0.69.0 +pydantic>=1.8.0,<2.0.0 +uvicorn>=0.15.0,<0.16.0 +``` + +And you would normally install those package dependencies with `pip`, for example: + +
+ +```console +$ pip install -r requirements.txt +---> 100% +Successfully installed fastapi pydantic uvicorn +``` + +
+ +!!! info + There are other formats and tools to define and install package dependencies. + + I'll show you an example using Poetry later in a section below. 👇 + +### Create the **FastAPI** Code * Create an `app` directory and enter in it. +* Create an empty file `__init__.py`. * Create a `main.py` file with: ```Python @@ -82,16 +159,126 @@ def read_item(item_id: int, q: Optional[str] = None): return {"item_id": item_id, "q": q} ``` -* You should now have a directory structure like: +### Dockerfile + +Now in the same project directory create a file `Dockerfile` with: + +```{ .dockerfile .annotate } +# (1) +FROM python:3.9 + +# (2) +WORKDIR /code + +# (3) +COPY ./requirements.txt /code/requirements.txt + +# (4) +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +# (5) +COPY ./app /code/app + +# (6) +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] +``` + +1. Start from the official Python base image. + +2. Set the current working directory to `/code`. + + This is where we'll put the `requirements.txt` file and the `app` directory. + +3. Copy the file with the requirements to the `/code` directory. + + Copy **only** the file with the requirements first, not the rest of the code. + + As this file **doesn't change often**, Docker will detect it and use the **cache** for this step, enabling the cache for the next step too. + +4. Install the package dependencies in the requirements file. + + The `--no-cache-dir` option tells `pip` to not save the downloaded packages locally, as that is only if `pip` was going to be run again to install the same packages, but that's not the case when working with containers. + + !!! note + The `--no-cache-dir` is only related to `pip`, it has nothing to do with Docker or containers. + + The `--upgrade` option tells `pip` to upgrade the packages if they are already installed. + + Because the previous step copying the file could be detected by the **Docker cache**, this step will also **use the Docker cache** when available. + + Using the cache in this step will **save** you a lot of **time** when building the image again and again during development, instead of **downloading and installing** all the dependencies **every time**. + +5. Copy the `./app` directory inside the `/code` directory. + + As this has all the code which is what **changes most frequently** the Docker **cache** won't be used for this or any **following steps** easily. + + So, it's important to put this **near the end** of the `Dockerfile`, to optimize the container image build times. + +6. Set the **command** to run the `uvicorn` server. + + `CMD` takes a list of strings, each of this strings is what you would type in the command line separated by spaces. + + This command will be run from the **current working directory**, the same `/code` directory you set above with `WORKDIR /code`. + + Because the program will be started at `/code` and inside of it is the directory `./app` with your code, **Uvicorn** will be able to see and **import** `app` from `app.main`. + +!!! tip + Review what each line does by clicking each number bubble in the code. 👆 + +You should now have a directory structure like: ``` . ├── app +│   ├── __init__.py │ └── main.py -└── Dockerfile +├── Dockerfile +└── requirements.txt ``` -## Build the Docker image +#### Behind a TLS Termination Proxy + +If you are running your container behind a TLS Termination Proxy (load balancer) like Nginx or Traefik, add the option `--proxy-headers`, this will tell Uvicorn to trust the headers sent by that proxy telling it that the application is running behind HTTPS, etc. + +```Dockerfile +CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"] +``` + +#### Docker Cache + +There's an important trick in this `Dockerfile`, we first copy the **file with the dependencies alone**, not the rest of the code. Let me tell you why is that. + +```Dockerfile +COPY ./requirements.txt /code/requirements.txt +``` + +Docker and other tools **build** these container images **incrementally**, adding **one layer on top of the other**, starting from the top of the `Dockerfile` and adding any files created by each of the instructions of the `Dockerfile`. + +Docker and similar tools also use an **internal cache** when building the image, if a file hasn't changed since the last time building the container image, then it will **re-use the same layer** created the last time, instead of copying the file again and creating a new layer from scratch. + +Just avoiding the copy of files doesn't necessarily improve things too much, but because it used the cache for that step, it can **use the cache for the next step**. For example, it could use the cache for the instruction that installs dependencies with: + +```Dockerfile +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt +``` + +The file with the package requirements **won't change frequently**. So, by copying only that file, Docker will be able to **use the cache** for that step. + +And then, Docker will be able to **use the cache for the next step** that downloads and install those dependencies. And here's where we **save a lot of time**. ✨ ...and avoid boredom waiting. 😪😆 + +Downloading and installing the package dependencies **could take minutes**, but using the **cache** would **take seconds** at most. + +And as you would be building the container image again and again during development to check that your code changes are working, there's a lot of accumulated time this would save. + +Then, near the end of the `Dockerfile`, we copy all the code. As this is what **changes most frequently**, we put it near the end, because almost always, anything after this step will not be able to use the cache. + +```Dockerfile +COPY ./app /code/app +``` + +### Build the Docker Image + +Now that all the files are in place, let's build the container image. * Go to the project directory (in where your `Dockerfile` is, containing your `app` directory). * Build your FastAPI image: @@ -106,7 +293,12 @@ $ docker build -t myimage .
-## Start the Docker container +!!! tip + Notice the `.` at the end, it's equivalent to `./`, it tells Docker the directory to use to build the container image. + + In this case, it's the same current directory (`.`). + +### Start the Docker Container * Run a container based on your image: @@ -118,8 +310,6 @@ $ docker run -d --name mycontainer -p 80:80 myimage
-Now you have an optimized FastAPI server in a Docker container. Auto-tuned for your current server (and number of CPU cores). - ## Check it You should be able to check it in your Docker container's URL, for example: http://192.168.99.100/items/5?q=somequery or http://127.0.0.1/items/5?q=somequery (or equivalent, using your Docker host). @@ -146,34 +336,363 @@ You will see the alternative automatic documentation (provided by Traefik is a high performance reverse proxy / load balancer. It can do the "TLS Termination Proxy" job (apart from other features). +If your FastAPI is a single file, for example `main.py` without an `./app` directory, your file structure could look like: -It has integration with Let's Encrypt. So, it can handle all the HTTPS parts, including certificate acquisition and renewal. +``` +. +├── Dockerfile +├── main.py +└── requirements.txt +``` -It also has integrations with Docker. So, you can declare your domains in each application configurations and have it read those configurations, generate the HTTPS certificates and serve HTTPS to your application automatically, without requiring any change in its configuration. +Then you would just have to change the corresponding paths to copy the file inside the `Dockerfile`: + +```{ .dockerfile .annotate hl_lines="10 13" } +FROM python:3.9 + +WORKDIR /code + +COPY ./requirements.txt /code/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +# (1) +COPY ./main.py /code/ + +# (2) +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] +``` + +1. Copy the `main.py` file to the `/code` directory directly (without any `./app` directory). + +2. Run Uvicorn and tell it to import the `app` object from `main` (instead of importing from `app.main`). + +Then adjust the Uvicorn command to use the new module `main` instead of `app.main` to import the FastAPI object `app`. + +## Deployment Concepts + +Let's talk again about some of the same [Deployment Concepts](./concepts.md){.internal-link target=_blank} in terms of containers. + +Containers are mainly a tool to simplify the process of **building and deploying** an application, but they don't enforce a particular approach to handle these **deployment concepts**, and there are several possible strategies. + +The **good news** is that with each different strategy there's a way to cover all of the deployment concepts. 🎉 + +Let's review these **deployment concepts** in terms of containers: + +* HTTPS +* Running on startup +* Restarts +* Replication (the number of processes running) +* Memory +* Previous steps before starting + +## HTTPS + +If we focus just on the **container image** for a FastAPI application (and later the running **container**), HTTPS normally would be handled **externally** by another tool. + +It could be another container, for example with Traefik, handling **HTTPS** and **automatic** acquisition of **certificates**. + +!!! tip + Traefik has integrations with Docker, Kubernetes, and others, so it's very easy to set up and configure HTTPS for your containers with it. + +Alternatively, HTTPS could be handled by a cloud provider as one of their services (while still running the application in a container). + +## Running on Startup and Restarts + +There is normally another tool in charge of **starting and running** your container. + +It could be **Docker** directly, **Docker Compose**, **Kubernetes**, a **cloud service**, etc. + +In most (or all) cases, there's a simple option to enable running the container on startup and enabling restarts on failures. For example, in Docker, it's the command line option `--restart`. + +Without using containers, making applications run on startup and with restarts can be cumbersome and difficult. But when **working with containers** in most cases that functionality is included by default. ✨ + +## Replication - Number of Processes + +If you have a cluster of machines with **Kubernetes**, Docker Swarm Mode, Nomad, or other similar complex system to manage distributed containers on multiple machines, then you will probably want to **handle replication** at the **cluster level** instead of using a **process manager** (like Gunicorn with workers) in each container. + +One of those distributed container management systems like Kubernetes normally has some integrated way of handling **replication of containers** while still supporting **load balancing** for the incoming requests. All at the **cluster level**. + +In those cases, you would probably want to build a **Docker image from scratch** as [explained above](#dockerfile), installing your dependencies, and running **a single Uvicorn process** instead of running something like Gunicorn with Uvicorn workers. + +### Load Balancer + +When using containers, you would normally have some component **listening on the main port**. It could possibly be another container that is also a **TLS Termination Proxy** to handle **HTTPS** or some similar tool. + +As this component would take the **load** of requests and distribute that among the workers in a (hopefully) **balanced** way, it is also commonly called a **Load Balancer**. + +!!! tip + The same **TLS Termination Proxy** component used for HTTPS would probably also be a **Load Balancer**. + +And when working with containers, the same system you use to start and manage them would already have internal tools to transmit the **network communication** (e.g. HTTP requests) from that **load balancer** (that could also be a **TLS Termination Proxy**) to the container(s) with your app. + +### One Load Balancer - Multiple Worker Containers + +When working with **Kubernetes** or similar distributed container management systems, using their internal networking mechanisms would allow the single **load balancer** that is listening on the main **port** to transmit communication (requests) to possibly **multiple containers** running your app. + +Each of these containers running your app would normally have **just one process** (e.g. a Uvicorn process running your FastAPI application). They would all be **identical containers**, running the same thing, but each with its own process, memory, etc. That way you would take advantage of **parallelization** in **different cores** of the CPU, or even in **different machines**. + +And the distributed container system with the **load balancer** would **distribute the requests** to each one of the containers with your app **in turns**. So, each request could be handled by one of the multiple **replicated containers** running your app. + +And normally this **load balancer** would be able to handle requests that go to *other* apps in your cluster (e.g. to a different domain, or under a different URL path prefix), and would transmit that communication to the right containers for *that other* application running in your cluster. + +### One Process per Container + +In this type of scenario, you probably would want to have **a single (Uvicorn) process per container**, as you would already be handling replication at the cluster level. + +So, in this case, you **would not** want to have a process manager like Gunicorn with Uvicorn workers, or Uvicorn using its own Uvicorn workers. You would want to have just a **single Uvicorn process** per container (but probably multiple containers). + +Having another process manager inside the container (as would be with Gunicorn or Uvicorn managing Uvicorn workers) would only add **unnecessary complexity** that you are most probably already taking care of with your cluster system. + +### Containers with Multiple Processes and Special Cases + +Of course, there are **special cases** where you could want to have **a container** with a **Gunicorn process manager** starting several **Uvicorn worker processes** inside. + +In those cases, you can use the **official Docker image** that includes **Gunicorn** as a process manager running multiple **Uvicorn worker processes**, and some default settings to adjust the number of workers based on the current CPU cores automatically. I'll tell you more about it below in [Official Docker Image with Gunicorn - Uvicorn](#official-docker-image-with-gunicorn-uvicorn). + +Here are some examples of when that could make sense: + +#### A Simple App + +You could want a process manager in the container if your application is **simple enough** that you don't need (at least not yet) to fine-tune the number of processes too much, and you can just use an automated default (with the official Docker image), and you are running it on a **single server**, not a cluster. + +#### Docker Compose + +You could be deploying to a **single server** (not a cluster) with **Docker Compose**, so you wouldn't have an easy way to manage replication of containers (with Docker Compose) while preserving the shared network and **load balancing**. + +Then you could want to have **a single container** with a **process manager** starting **several worker processes** inside. + +#### Prometheus and Other Reasons + +You could also have **other reasons** that would make it easier to have a **single container** with **multiple processes** instead of having **multiple containers** with **a single process** in each of them. + +For example (depending on your setup) you could have some tool like a Prometheus exporter in the same container that should have access to **each of the requests** that come. + +In this case, if you had **multiple containers**, by default, when Prometheus came to **read the metrics**, it would get the ones for **a single container each time** (for the container that handled that particular request), instead of getting the **accumulated metrics** for all the replicated containers. + +Then, in that case, it could be simpler to have **one container** with **multiple processes**, and a local tool (e.g. a Prometheus exporter) on the same container collecting Prometheus metrics for all the internal processes and exposing those metrics on that single container. --- -With this information and tools, continue with the next section to combine everything. +The main point is, **none** of these are **rules written in stone** that you have to blindly follow. You can use these ideas to **evaluate your own use case** and decide what is the best approach for your system, checking out how to manage the concepts of: -## Docker Swarm mode cluster with Traefik and HTTPS +* Security - HTTPS +* Running on startup +* Restarts +* Replication (the number of processes running) +* Memory +* Previous steps before starting -You can have a Docker Swarm mode cluster set up in minutes (about 20 min) with a main Traefik handling HTTPS (including certificate acquisition and renewal). +## Memory -By using Docker Swarm mode, you can start with a "cluster" of a single machine (it can even be a $5 USD / month server) and then you can grow as much as you need adding more servers. +If you run **a single process per container** you will have a more or less well defined, stable, and limited amount of memory consumed by each of of those containers (more than one if they are replicated). -To set up a Docker Swarm Mode cluster with Traefik and HTTPS handling, follow this guide: +And then you can set those same memory limits and requirements in your configurations for your container management system (for example in **Kubernetes**). That way it will be able to **replicate the containers** in the **available machines** taking into account the amount of memory needed by them, and the amount available in the machines in the cluster. -### Docker Swarm Mode and Traefik for an HTTPS cluster +If your application is **simple**, this will probably **not be a problem**, and you might not need to specify hard memory limits. But if you are **using a lot of memory** (for example with **machine learning** models), you should check how much memory you are consuming and adjust the **number of containers** that runs in **each machine** (and maybe add more machines to your cluster). -### Deploy a FastAPI application +If you run **multiple processes per container** (for example with the official Docker image) you will have to make sure that the number of processes started doesn't **consume more memory** than what is available. -The easiest way to set everything up, would be using the [**FastAPI** Project Generators](../project-generation.md){.internal-link target=_blank}. +## Previous Steps Before Starting and Containers -It is designed to be integrated with this Docker Swarm cluster with Traefik and HTTPS described above. +If you are using containers (e.g. Docker, Kubernetes), then there are two main approaches you can use. -You can generate a project in about 2 min. +### Multiple Containers -The generated project has instructions to deploy it, doing it takes another 2 min. +If you have **multiple containers**, probably each one running a **single process** (for example, in a **Kubernetes** cluster), then you would probably want to have a **separate container** doing the work of the **previous steps** in a single container, running a single process, **before** running the replicated worker containers. + +!!! info + If you are using Kubernetes, this would probably be an Init Container. + +If in your use case there's no problem in running those previous steps **multiple times in parallel** (for example if you are not running database migrations, but just checking if the database is ready yet), then you could also just put them in each container right before starting the main process. + +### Single Container + +If you have a simple setup, with a **single container** that then starts multiple **worker processes** (or also just one process), then you could run those previous steps in the same container, right before starting the process with the app. The official Docker image supports this internally. + +## Official Docker Image with Gunicorn - Uvicorn + +There is an official Docker image that includes Gunicorn running with Uvicorn workers, as detailed in a previous chapter: [Server Workers - Gunicorn with Uvicorn](./server-workers.md){.internal-link target=_blank}. + +This image would be useful mainly in the situations described above in: [Containers with Multiple Processes and Special Cases](#containers-with-multiple-processes-and-special-cases). + +* tiangolo/uvicorn-gunicorn-fastapi. + +!!! warning + There's a high chance that you **don't** need this base image or any other similar one, and would be better off by building the image from scratch as [described above in: Build a Docker Image for FastAPI](#build-a-docker-image-for-fastapi). + +This image has an **auto-tuning** mechanism included to set the **number of worker processes** based on the CPU cores available. + +It has **sensible defaults**, but you can still change and update all the configurations with **environment variables** or configuration files. + +It also supports running **previous steps before starting** with a script. + +!!! tip + To see all the configurations and options, go to the Docker image page: tiangolo/uvicorn-gunicorn-fastapi. + +### Number of Processes on the Official Docker Image + +The **number of processes** on this image is **computed automatically** from the CPU **cores** available. + +This means that it will try to **squeeze** as much **performance** from the CPU as possible. + +You can also adjust it with the configurations using **environment variables**, etc. + +But it also means that as the number of processes depends on the CPU the container is running, the **amount of memory consumed** will also depend on that. + +So, if your application consumes a lot of memory (for example with machine learning models), and your server has a lot of CPU cores **but little memory**, then your container could end up trying to use more memory than what is available, and degrading performance a lot (or even crashing). 🚨 + +### Create a `Dockerfile` + +Here's how you would create a `Dockerfile` based on this image: + +```Dockerfile +FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9 + +COPY ./requirements.txt /app/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt + +COPY ./app /app +``` + +### Bigger Applications + +If you followed the section about creating [Bigger Applications with Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}, your `Dockerfile` might instead look like: + +```Dockerfile hl_lines="7" +FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9 + +COPY ./requirements.txt /app/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt + +COPY ./app /app/app +``` + +### When to Use + +You should probably **not** use this official base image (or any other similar one) if you are using **Kubernetes** (or others) and you are already setting **replication** at the cluster level, with multiple **containers**. In those cases, you are better off **building an image from scratch** as described above: [Build a Docker Image for FastAPI](#build-a-docker-image-for-fastapi). + +This image would be useful mainly in the special cases described above in [Containers with Multiple Processes and Special Cases](#containers-with-multiple-processes-and-special-cases). For example, if your application is **simple enough** that setting a default number of processes based on the CPU works well, you don't want to bother with manually configuring the replication at the cluster level, and you are not running more than one container with your app. Or if you are deploying with **Docker Compose**, running on a single server, etc. + +## Deploy the Container Image + +After having a Container (Docker) Image there are several ways to deploy it. + +For example: + +* With **Docker Compose** in a single server +* With a **Kubernetes** cluster +* With a Docker Swarm Mode cluster +* With another tool like Nomad +* With a cloud service that takes your container image and deploys it + +## Docker Image with Poetry + +If you use Poetry to manage your project's dependencies, you could use Docker multi-stage building: + +```{ .dockerfile .annotate } +# (1) +FROM python:3.9 as requirements-stage + +# (2) +WORKDIR /tmp + +# (3) +RUN pip install poetry + +# (4) +COPY ./pyproject.toml ./poetry.lock* /tmp/ + +# (5) +RUN poetry export -f requirements.txt --output requirements.txt --without-hashes + +# (6) +FROM python:3.9 + +# (7) +WORKDIR /code + +# (8) +COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt + +# (9) +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +# (10) +COPY ./app /code/app + +# (11) +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] +``` + +1. This is the first stage, it is named `requirements-stage`. + +2. Set `/tmp` as the current working directory. + + Here's where we will generate the file `requirements.txt` + +3. Install Poetry in this Docker stage. + +4. Copy the `pyproject.toml` and `poetry.lock` files to the `/tmp` directory. + + Because it uses `./poetry.lock*` (ending with a `*`), it won't crash if that file is not available yet. + +5. Generate the `requirements.txt` file. + +6. This is the final stage, anything here will be preserved in the final container image. + +7. Set the current working directory to `/code`. + +8. Copy the `requirements.txt` file to the `/code` directory. + + This file only lives in the previous Docker stage, that's why we use `--from-requirements-stage` to copy it. + +9. Install the package dependencies in the generated `requirements.txt` file. + +10. Copy the `app` directory to the `/code` directory. + +11. Run the `uvicorn` command, telling it to use the `app` object imported from `app.main`. + +!!! tip + Click the bubble numbers to see what each line does. + +A **Docker stage** is a part of a `Dockerfile` that works as a **temporary container image** that is only used to generate some files to be used later. + +The first stage will only be used to **install Poetry** and to **generate the `requirements.txt`** with your project dependencies from Poetry's `pyproject.toml` file. + +This `requirements.txt` file will be used with `pip` later in the **next stage**. + +In the final container image **only the final stage** is preserved. The previous stage(s) will be discarded. + +When using Poetry, it would make sense to use **Docker multi-stage builds** because you don't really need to have Poetry and its dependencies installed in the final container image, you **only need** to have the generated `requirements.txt` file to install your project dependencies. + +Then in the next (and final) stage you would build the image more or less in the same way as described before. + +### Behind a TLS Termination Proxy - Poetry + +Again, if you are running your container behind a TLS Termination Proxy (load balancer) like Nginx or Traefik, add the option `--proxy-headers` to the command: + +```Dockerfile +CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"] +``` + +## Recap + +Using container systems (e.g. with **Docker** and **Kubernetes**) it becomes fairly straightforward to handle all the **deployment concepts**: + +* HTTPS +* Running on startup +* Restarts +* Replication (the number of processes running) +* Memory +* Previous steps before starting + +In most cases, you probably won't want to use any base image, and instead **build a container image from scratch** one based on the official Python Docker image. + +Taking care of the **order** of instructions in the `Dockerfile` and the **Docker cache** you can **minimize build times**, to maximize your productivity (and avoid boredom). 😎 + +In certain special cases, you might want to use the official Docker image for FastAPI. 🤓 diff --git a/docs/en/docs/deployment/index.md b/docs/en/docs/deployment/index.md index d898cfefc..d1941ad93 100644 --- a/docs/en/docs/deployment/index.md +++ b/docs/en/docs/deployment/index.md @@ -2,6 +2,20 @@ Deploying a **FastAPI** application is relatively easy. +## What Does Deployment Mean + +To **deploy** an application means to perform the necessary steps to make it **available to the users**. + +For a **web API**, it normally involves putting it in a **remote machine**, with a **server program** that provides good performance, stability, etc, so that your **users** can **access** the application efficiently and without interruptions or problems. + +This is in contrast to the the **development** stages, where you are constantly changing the code, breaking it and fixing it, stopping and restarting the development server, etc. + +## Deployment Strategies + There are several ways to do it depending on your specific use case and the tools that you use. -You will see more details to have in mind and some of the techniques to do it in the next sections. +You could **deploy a server** yourself using a combination of tools, you could use a **cloud service** that does part of the work for you, or other possible options. + +I will show you some of the main concepts you should probably have in mind when deploying a **FastAPI** application (although most of it applies to any other type of web application). + +You will see more details to have in mind and some of the techniques to do it in the next sections. ✨ diff --git a/docs/en/docs/deployment/manually.md b/docs/en/docs/deployment/manually.md index daa31a304..80a7df7e6 100644 --- a/docs/en/docs/deployment/manually.md +++ b/docs/en/docs/deployment/manually.md @@ -1,8 +1,26 @@ -# Deploy manually +# Run a Server Manually - Uvicorn -You can deploy **FastAPI** manually as well. +The main thing you need to run a **FastAPI** application in a remote server machine is an ASGI server program like **Uvicorn**. -You just need to install an ASGI compatible server like: +There are 3 main alternatives: + +* Uvicorn: a high performance ASGI server. +* Hypercorn: an ASGI server compatible with HTTP/2 and Trio among other features. +* Daphne: the ASGI server built for Django Channels. + +## Server Machine and Server Program + +There's a small detail about names to have in mind. 💡 + +The word "**server**" is commonly used to refer to both the remote/cloud computer (the physical or virtual machine) and also the program that is running on that machine (e.g. Uvicorn). + +Just have that in mind when you read "server" in general, it could refer to one of those two things. + +When referring to the remote machine, it's common to call it **server**, but also **machine**, **VM** (virtual machine), **node**. Those all refer to some type of remote machine, normally running Linux, where you run programs. + +## Install the Server Program + +You can install an ASGI compatible server with: === "Uvicorn" @@ -39,7 +57,9 @@ You just need to install an ASGI compatible server like: ...or any other ASGI server. -And run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.: +## Run the Server Program + +You can then your application the same way you have done in the tutorials, but without the `--reload` option, e.g.: === "Uvicorn" @@ -65,10 +85,24 @@ And run your application the same way you have done in the tutorials, but withou
-You might want to set up some tooling to make sure it is restarted automatically if it stops. +!!! warning + Remember to remove the `--reload` option if you were using it. -You might also want to install Gunicorn and use it as a manager for Uvicorn, or use Hypercorn with multiple workers. + The `--reload` option consumes much more resources, is more unstable, etc. + + It helps a lot during **development**, but you **shouldn't** use it in **production**. -Making sure to fine-tune the number of workers, etc. +## Deployment Concepts -But if you are doing all that, you might just use the Docker image that does it automatically. +These examples run the server program (e.g Uvicorn), starting **a single process**, listening on all the IPs (`0.0.0.0`) on a predefined port (e.g. `80`). + +This is the basic idea. But you will probably want to take care of some additional things, like: + +* Security - HTTPS +* Running on startup +* Restarts +* Replication (the number of processes running) +* Memory +* Previous steps before starting + +I'll tell you more about each of these concepts, how to think about them, and some concrete examples with strategies to handle them in the next chapters. 🚀 diff --git a/docs/en/docs/deployment/server-workers.md b/docs/en/docs/deployment/server-workers.md new file mode 100644 index 000000000..2892d5797 --- /dev/null +++ b/docs/en/docs/deployment/server-workers.md @@ -0,0 +1,178 @@ +# Server Workers - Gunicorn with Uvicorn + +Let's check back those deployment concepts from before: + +* Security - HTTPS +* Running on startup +* Restarts +* **Replication (the number of processes running)** +* Memory +* Previous steps before starting + +Up to this point, with all the tutorials in the docs, you have probably been running a **server program** like Uvicorn, running a **single process**. + +When deploying applications you will probably want to have some **replication of processes** to take advantage of **multiple cores** and to be able to handle more requests. + +As you saw in the previous chapter about [Deployment Concepts](./concepts.md){.internal-link target=_blank}, there are multiple strategies you can use. + +Here I'll show you how to use **Gunicorn** with **Uvicorn worker processes**. + +!!! info + If you are using containers, for example with Docker or Kubernetes, I'll tell you more about that in the next chapter: [FastAPI in Containers - Docker](./docker.md){.internal-link target=_blank}. + + In particular, when running on **Kubernetes** you will probably **not** want to use Gunicorn, and instead run **a single Uvicorn process per container**, but I'll tell you about it later in that chapter. + +## Gunicorn with Uvicorn Workers + +**Gunicorn** is mainly an application server using the **WSGI standard**. That means that Gunicorn can serve applications like Flask and Django. Gunicorn by itself is not compatible with **FastAPI**, as FastAPI uses the newest **ASGI standard**. + +But Gunicorn supports working as a **process manager** and allowing users to tell it which specific **worker process class** to use. Then Gunicorn would start one or more **worker processes** using that class. + +And **Uvicorn** has a **Gunicorn-compatible worker class**. + +Using that combination, Gunicorn would act as a **process manager**, listening on the **port** and the **IP**. And it would **transmit** the communication to the worker processes running the **Uvicorn class**. + +And then the Gunicorn-compatible **Uvicorn worker** class would be in charge of converting the data sent by Gunicorn to the ASGI standard for FastAPI to use it. + +## Install Gunicorn and Uvicorn + +
+ +```console +$ pip install uvicorn[standard] gunicorn + +---> 100% +``` + +
+ +That will install both Uvicorn with the `standard` extra packages (to get high performance) and Gunicorn. + +## Run Gunicorn with Uvicorn Workers + +Then you can run Gunicorn with: + +
+ +```console +$ gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80 + +[19499] [INFO] Starting gunicorn 20.1.0 +[19499] [INFO] Listening at: http://0.0.0.0:80 (19499) +[19499] [INFO] Using worker: uvicorn.workers.UvicornWorker +[19511] [INFO] Booting worker with pid: 19511 +[19513] [INFO] Booting worker with pid: 19513 +[19514] [INFO] Booting worker with pid: 19514 +[19515] [INFO] Booting worker with pid: 19515 +[19511] [INFO] Started server process [19511] +[19511] [INFO] Waiting for application startup. +[19511] [INFO] Application startup complete. +[19513] [INFO] Started server process [19513] +[19513] [INFO] Waiting for application startup. +[19513] [INFO] Application startup complete. +[19514] [INFO] Started server process [19514] +[19514] [INFO] Waiting for application startup. +[19514] [INFO] Application startup complete. +[19515] [INFO] Started server process [19515] +[19515] [INFO] Waiting for application startup. +[19515] [INFO] Application startup complete. +``` + +
+ +Let's see what each of those options mean: + +* `main:app`: This is the same syntax used by Uvicorn, `main` means the Python module named "`main`", so, a file `main.py`. And `app` is the name of the variable that is the **FastAPI** application. + * You can imagine that `main:app` is equivalent to a Python `import` statement like: + + ```Python + from main import app + ``` + + * So, the colon in `main:app` would be equivalent to the Python `import` part in `from main import app`. +* `--workers`: The number of worker processes to use, each will run a Uvicorn worker, in this case 4 workers. +* `--worker-class`: The Gunicorn-compatible worker class to use in the worker processes. + * Here we pass the class that Gunicorn can import and use with: + + ```Python + import uvicorn.workers.UvicornWorker + ``` + +* `--bind`: This tells Gunicorn the IP and the port to listen to, using a colon (`:`) to separate the IP and the port. + * If you were running Uvicorn directly, instead of `--bind 0.0.0.0:80` (the Gunicorn option) you would use `--host 0.0.0.0` and `--port 80`. + +In the output you can see that it shows the **PID** (process ID) of each process (it's just a number). + +You can see that: + +* The Gunicorn **process manager** starts with PID `19499` (in your case it will be a different number). +* Then it starts `Listening at: http://0.0.0.0:80`. +* Then it detects that it has to use the worker class at `uvicorn.workers.UvicornWorker`. +* And then it starts **4 workers**, each with its own PID: `19511`, `19513`, `19514`, and `19515`. + +Gunicorn would also take care of managing **dead processes** and **restarting** new ones if needed to keep the number of workers. So that helps in part with the **restart** concept from the list above. + +Nevertheless, you would probably also want to have something outside making sure to **restart Gunicorn** if necessary, and also to **run it on startup**, etc. + +## Uvicorn with Workers + +Uvicorn also has an option to start and run several **worker processes**. + +Nevertheless, as of now, Uvicorn's capabilities for handling worker processes are more limited than Gunicorn's. So, if you want to have a process manager at this level (at the Python level), then it might be better to try with Gunicorn as the process manager. + +In any case, you would run it like this: + +
+ +```console +$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4 +INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit) +INFO: Started parent process [27365] +INFO: Started server process [27368] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Started server process [27369] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Started server process [27370] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Started server process [27367] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +The only new option here is `--workers` telling Uvicorn to start 4 worker processes. + +You can also see that it shows the **PID** of each process, `27365` for the parent process (this is the **process manager**) and one for each worker process: `27368`, `27369`, `27370`, and `27367`. + +## Deployment Concepts + +Here you saw how to use **Gunicorn** (or Uvicorn) managing **Uvicorn worker processes** to **parallelize** the execution of the application, take advantage of **multiple cores** in the CPU, and be able to serve **more requests**. + +From the list of deployment concepts from above, using workers would mainly help with the **replication** part, and a little bit with the **restarts**, but you still need to take care of the others: + +* **Security - HTTPS** +* **Running on startup** +* ***Restarts*** +* Replication (the number of processes running) +* **Memory** +* **Previous steps before starting** + +## Containers and Docker + +In the next chapter about [FastAPI in Containers - Docker](./docker.md){.internal-link target=_blank} I'll tell some strategies you could use to handle the other **deployment concepts**. + +I'll also show you the **official Docker image** that includes **Gunicorn with Uvicorn workers** and some default configurations that can be useful for simple cases. + +There I'll also show you how to **build your own image from scratch** to run a single Uvicorn process (without Gunicorn). It is a simple process and is probably what you would want to do when using a distributed container management system like **Kubernetes**. + +## Recap + +You can use **Gunicorn** (or also Uvicorn) as a process manager with Uvicorn workers to take advantage of **multi-core CPUs**, to run **multiple processes in parallel**. + +You could use these tools and ideas if you are setting up **your own deployment system** while taking care of the other deployment concepts yourself. + +Check out the next chapter to learn about **FastAPI** with containers (e.g. Docker and Kubernetes). You will see that those tools have simple ways to solve the other **deployment concepts** as well. ✨ diff --git a/docs/en/docs/img/deployment/concepts/image01.png b/docs/en/docs/img/deployment/concepts/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..fdce75e983509b17ff6fdb0a1bef0f2806791163 GIT binary patch literal 124827 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 s!MNjY0r`9Ne+uG#|5C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/deployment/concepts/process-ram.svg b/docs/en/docs/img/deployment/concepts/process-ram.svg new file mode 100644 index 000000000..cd086c36b --- /dev/null +++ b/docs/en/docs/img/deployment/concepts/process-ram.svg @@ -0,0 +1,59 @@ +
Server
Server
RAM
RAM +
CPU
CPU +
Process Manager
Process Manager
Worker Process
Worker Process
Worker Process
Worker Process
Another Process
Another Process
1 GB
1 GB
1 GB
1 GB
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index a11ac6871..b32468783 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -147,9 +147,11 @@ nav: - deployment/index.md - deployment/versions.md - deployment/https.md - - deployment/deta.md - - deployment/docker.md - deployment/manually.md + - deployment/concepts.md + - deployment/deta.md + - deployment/server-workers.md + - deployment/docker.md - project-generation.md - alternatives.md - history-design-future.md From 1b6350ad9e67cd700ecec2d360bd06b946c3231c Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 1 Oct 2021 20:44:53 +0000 Subject: [PATCH 199/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f67b11f0f..7206c6a6f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Re-write and extend Deployment guide: Concepts, Uvicorn, Gunicorn, Docker, Containers, Kubernetes. PR [#3974](https://github.com/tiangolo/fastapi/pull/3974) by [@tiangolo](https://github.com/tiangolo). * 📝 Upgrade HTTPS guide with more explanations and diagrams. PR [#3950](https://github.com/tiangolo/fastapi/pull/3950) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add German translation for `docs/features.md`. PR [#3699](https://github.com/tiangolo/fastapi/pull/3699) by [@mawassk](https://github.com/mawassk). * 🎨 Tweak CSS styles for shell animations. PR [#3888](https://github.com/tiangolo/fastapi/pull/3888) by [@tiangolo](https://github.com/tiangolo). From d29aa3d436849c7abb7c5fd6988ef4531b08f9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 2 Oct 2021 12:16:55 +0200 Subject: [PATCH 200/814] =?UTF-8?q?=E2=9C=A8=20Add=20Deepset=20Sponsorship?= =?UTF-8?q?=20(#3976)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/en/data/sponsors.yml | 3 + docs/en/data/sponsors_badge.yml | 1 + .../en/docs/img/sponsors/haystack-fastapi.svg | 192 ++++++++++++++++++ 4 files changed, 197 insertions(+) create mode 100644 docs/en/docs/img/sponsors/haystack-fastapi.svg diff --git a/README.md b/README.md index bdc8c3b07..233e8ed57 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index e0a4ee783..4949e6c56 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -18,6 +18,9 @@ silver: - url: https://testdriven.io/courses/tdd-fastapi/ title: Learn to build high-quality web apps with best practices img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg + - url: https://github.com/deepset-ai/haystack/ + title: Build powerful search from composable, open source building blocks + img: https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg bronze: - url: https://calmcode.io title: Code. Simply. Clearly. Calmly. diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index 9e95a6255..0496c6279 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -5,3 +5,4 @@ logins: - vimsoHQ - mikeckennedy - koaning + - deepset-ai diff --git a/docs/en/docs/img/sponsors/haystack-fastapi.svg b/docs/en/docs/img/sponsors/haystack-fastapi.svg new file mode 100644 index 000000000..6303ba61f --- /dev/null +++ b/docs/en/docs/img/sponsors/haystack-fastapi.svg @@ -0,0 +1,192 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1db0fc29535f91fd026d3e439b9663a4ca6a44b1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Oct 2021 10:17:32 +0000 Subject: [PATCH 201/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7206c6a6f..062f295fb 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add Deepset Sponsorship. PR [#3976](https://github.com/tiangolo/fastapi/pull/3976) by [@tiangolo](https://github.com/tiangolo). * 📝 Re-write and extend Deployment guide: Concepts, Uvicorn, Gunicorn, Docker, Containers, Kubernetes. PR [#3974](https://github.com/tiangolo/fastapi/pull/3974) by [@tiangolo](https://github.com/tiangolo). * 📝 Upgrade HTTPS guide with more explanations and diagrams. PR [#3950](https://github.com/tiangolo/fastapi/pull/3950) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add German translation for `docs/features.md`. PR [#3699](https://github.com/tiangolo/fastapi/pull/3699) by [@mawassk](https://github.com/mawassk). From 4b968c4e3907066a994e125de1fa90768e9c9188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 3 Oct 2021 20:00:28 +0200 Subject: [PATCH 202/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20GraphQL=20docs,?= =?UTF-8?q?=20recommend=20Strawberry=20(#3981)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- docs/de/docs/features.md | 1 - docs/de/docs/index.md | 2 -- docs/en/docs/advanced/graphql.md | 62 +++++++++++++++++++------------- docs/en/docs/alternatives.md | 3 +- docs/en/docs/features.md | 1 - docs/en/docs/index.md | 3 +- docs_src/graphql/tutorial001.py | 26 ++++++++++---- 8 files changed, 59 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 233e8ed57..5bdd9e6db 100644 --- a/README.md +++ b/README.md @@ -418,9 +418,9 @@ For a more complete example including more features, see the Dependency Injection** system. * Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. * More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). +* **GraphQL** integration with Strawberry and other libraries. * Many extra features (thanks to Starlette) as: * **WebSockets** - * **GraphQL** * extremely easy tests based on `requests` and `pytest` * **CORS** * **Cookie Sessions** @@ -447,7 +447,6 @@ Used by Starlette: * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. * pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). -* graphene - Required for `GraphQLApp` support. * ujson - Required if you want to use `UJSONResponse`. Used by FastAPI / Starlette: diff --git a/docs/de/docs/features.md b/docs/de/docs/features.md index e5b38616f..f56257e7e 100644 --- a/docs/de/docs/features.md +++ b/docs/de/docs/features.md @@ -167,7 +167,6 @@ Mit **FastAPI** bekommen Sie viele von **Starlette**'s Funktionen (da FastAPI nu * Stark beeindruckende Performanz. Es ist eines der schnellsten Python frameworks, auf Augenhöhe mit **NodeJS** und **Go**. * **WebSocket**-Unterstützung. -* **GraphQL**-Unterstützung. * Hintergrundaufgaben im selben Prozess. * Ereignisse für das Starten und Herunterfahren. * Testclient basierend auf `requests`. diff --git a/docs/de/docs/index.md b/docs/de/docs/index.md index 95fb7ae21..d09ce70a0 100644 --- a/docs/de/docs/index.md +++ b/docs/de/docs/index.md @@ -425,7 +425,6 @@ For a more complete example including more features, see the python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. * pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). -* graphene - Required for `GraphQLApp` support. * ujson - Required if you want to use `UJSONResponse`. Used by FastAPI / Starlette: diff --git a/docs/en/docs/advanced/graphql.md b/docs/en/docs/advanced/graphql.md index acc1a39f2..154606406 100644 --- a/docs/en/docs/advanced/graphql.md +++ b/docs/en/docs/advanced/graphql.md @@ -1,44 +1,56 @@ # GraphQL -**FastAPI** has optional support for GraphQL (provided by Starlette directly), using the `graphene` library. +As **FastAPI** is based on the **ASGI** standard, it's very easy to integrate any **GraphQL** library also compatible with ASGI. You can combine normal FastAPI *path operations* with GraphQL on the same application. -## Import and use `graphene` +!!! tip + **GraphQL** solves some very specific use cases. -GraphQL is implemented with Graphene, you can check Graphene's docs for more details. + It has **advantages** and **disadvantages** when compared to common **web APIs**. -Import `graphene` and define your GraphQL data: + Make sure you evaluate if the **benefits** for your use case compensate the **drawbacks**. 🤓 -```Python hl_lines="1 6-10" +## GraphQL Libraries + +Here are some of the **GraphQL** libraries that have **ASGI** support. You could use them with **FastAPI**: + +* Strawberry 🍓 + * With docs for FastAPI +* Ariadne + * With docs for Starlette (that also apply to FastAPI) +* Tartiflette + * With Tartiflette ASGI to provide ASGI integration +* Graphene + * With starlette-graphene3 + +## GraphQL with Strawberry + +If you need or want to work with **GraphQL**, **Strawberry** is the **recommended** library as it has the design closest to **FastAPI's** design, it's all based on **type annotations**. + +Depending on your use case, you might prefer to use a different library, but if you asked me, I would probably suggest you try **Strawberry**. + +Here's a small preview of how you could integrate Strawberry with FastAPI: + +```Python hl_lines="3 22 25-26" {!../../../docs_src/graphql/tutorial001.py!} ``` -## Add Starlette's `GraphQLApp` +You can learn more about Strawberry in the Strawberry documentation. -Then import and add Starlette's `GraphQLApp`: +And also the docs about Strawberry with FastAPI. -```Python hl_lines="3 14" -{!../../../docs_src/graphql/tutorial001.py!} -``` +## Older `GraphQLApp` from Starlette -!!! info - Here we are using `.add_route`, that is the way to add a route in Starlette (inherited by FastAPI) without declaring the specific operation (as would be with `.get()`, `.post()`, etc). +Previous versions of Starlette included a `GraphQLApp` class to integrate with Graphene. -## Check it +It was deprecated from Starlette, but if you have code that used it, you can easily **migrate** to starlette-graphene3, that covers the same use case and has an **almost identical interface**. -Run it with Uvicorn and open your browser at http://127.0.0.1:8000. +!!! tip + If you need GraphQL, I still would recommend you check out Strawberry, as it's based on type annotations instead of custom classes and types. -You will see GraphiQL web user interface: +## Learn More - +You can learn more about **GraphQL** in the official GraphQL documentation. -## More details - -For more details, including: - -* Accessing request information -* Adding background tasks -* Using normal or async functions - -check the official Starlette GraphQL docs. +You can also read more about each those libraries described above in their links. diff --git a/docs/en/docs/alternatives.md b/docs/en/docs/alternatives.md index 8b1fa7786..d2792eb0c 100644 --- a/docs/en/docs/alternatives.md +++ b/docs/en/docs/alternatives.md @@ -367,7 +367,6 @@ It has: * Seriously impressive performance. * WebSocket support. -* GraphQL support. * In-process background tasks. * Startup and shutdown events. * Test client built on requests. @@ -375,7 +374,7 @@ It has: * Session and Cookie support. * 100% test coverage. * 100% type annotated codebase. -* Zero hard dependencies. +* Few hard dependencies. Starlette is currently the fastest Python framework tested. Only surpassed by Uvicorn, which is not a framework, but a server. diff --git a/docs/en/docs/features.md b/docs/en/docs/features.md index c92795d4a..36f80783a 100644 --- a/docs/en/docs/features.md +++ b/docs/en/docs/features.md @@ -164,7 +164,6 @@ With **FastAPI** you get all of **Starlette**'s features (as FastAPI is just Sta * Seriously impressive performance. It is one of the fastest Python frameworks available, on par with **NodeJS** and **Go**. * **WebSocket** support. -* **GraphQL** support. * In-process background tasks. * Startup and shutdown events. * Test client built on `requests`. diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index 33aadb8ef..ef593153f 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -419,9 +419,9 @@ For a more complete example including more features, see the Dependency Injection** system. * Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. * More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). +* **GraphQL** integration with Strawberry and other libraries. * Many extra features (thanks to Starlette) as: * **WebSockets** - * **GraphQL** * extremely easy tests based on `requests` and `pytest` * **CORS** * **Cookie Sessions** @@ -448,7 +448,6 @@ Used by Starlette: * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. * pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). -* graphene - Required for `GraphQLApp` support. * ujson - Required if you want to use `UJSONResponse`. Used by FastAPI / Starlette: diff --git a/docs_src/graphql/tutorial001.py b/docs_src/graphql/tutorial001.py index 41da361d3..3b4ca99cf 100644 --- a/docs_src/graphql/tutorial001.py +++ b/docs_src/graphql/tutorial001.py @@ -1,14 +1,26 @@ -import graphene +import strawberry from fastapi import FastAPI -from starlette.graphql import GraphQLApp +from strawberry.asgi import GraphQL -class Query(graphene.ObjectType): - hello = graphene.String(name=graphene.String(default_value="stranger")) +@strawberry.type +class User: + name: str + age: int - def resolve_hello(self, info, name): - return "Hello " + name +@strawberry.type +class Query: + @strawberry.field + def user(self) -> User: + return User(name="Patrick", age=100) + + +schema = strawberry.Schema(query=Query) + + +graphql_app = GraphQL(schema) app = FastAPI() -app.add_route("/", GraphQLApp(schema=graphene.Schema(query=Query))) +app.add_route("/graphql", graphql_app) +app.add_websocket_route("/graphql", graphql_app) From 54c02d402a47cccb337652f033c6ad2e852e768d Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 3 Oct 2021 18:01:11 +0000 Subject: [PATCH 203/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 062f295fb..cf503d50d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update GraphQL docs, recommend Strawberry. PR [#3981](https://github.com/tiangolo/fastapi/pull/3981) by [@tiangolo](https://github.com/tiangolo). * ✨ Add Deepset Sponsorship. PR [#3976](https://github.com/tiangolo/fastapi/pull/3976) by [@tiangolo](https://github.com/tiangolo). * 📝 Re-write and extend Deployment guide: Concepts, Uvicorn, Gunicorn, Docker, Containers, Kubernetes. PR [#3974](https://github.com/tiangolo/fastapi/pull/3974) by [@tiangolo](https://github.com/tiangolo). * 📝 Upgrade HTTPS guide with more explanations and diagrams. PR [#3950](https://github.com/tiangolo/fastapi/pull/3950) by [@tiangolo](https://github.com/tiangolo). From 099c4786554be070eadf47edf80bf4071bccdb47 Mon Sep 17 00:00:00 2001 From: Andy Challis Date: Mon, 4 Oct 2021 05:13:47 +1100 Subject: [PATCH 204/814] =?UTF-8?q?=F0=9F=92=9A=20Fix=20badges=20in=20READ?= =?UTF-8?q?ME=20and=20main=20page=20(#3979)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Anthony Lukach Co-authored-by: Sebastián Ramírez --- .github/workflows/test.yml | 2 ++ README.md | 8 ++++---- docs/en/docs/index.md | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1867cbb00..02507a9d0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,8 @@ name: Test on: push: + branches: + - master pull_request: types: [opened, synchronize] diff --git a/README.md b/README.md index 5bdd9e6db..3055e670d 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ FastAPI framework, high performance, easy to learn, fast to code, ready for production

- - Test + + Test Coverage @@ -316,7 +316,7 @@ And now, go to FastAPI framework, high performance, easy to learn, fast to code, ready for production

- - Test + + Test Coverage @@ -317,7 +317,7 @@ And now, go to Date: Sun, 3 Oct 2021 18:14:25 +0000 Subject: [PATCH 205/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index cf503d50d..bff7aa48f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 💚 Fix badges in README and main page. PR [#3979](https://github.com/tiangolo/fastapi/pull/3979) by [@ghandic](https://github.com/ghandic). * 📝 Update GraphQL docs, recommend Strawberry. PR [#3981](https://github.com/tiangolo/fastapi/pull/3981) by [@tiangolo](https://github.com/tiangolo). * ✨ Add Deepset Sponsorship. PR [#3976](https://github.com/tiangolo/fastapi/pull/3976) by [@tiangolo](https://github.com/tiangolo). * 📝 Re-write and extend Deployment guide: Concepts, Uvicorn, Gunicorn, Docker, Containers, Kubernetes. PR [#3974](https://github.com/tiangolo/fastapi/pull/3974) by [@tiangolo](https://github.com/tiangolo). From 2680f369d0f5ec69645e1cdf42e2b9f197f8edf5 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Tue, 5 Oct 2021 10:06:35 +0200 Subject: [PATCH 206/814] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Bump=20Uvicorn=20m?= =?UTF-8?q?ax=20range=20to=200.15.0=20(#3345)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eddbb92aa..f48d034b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,7 @@ dev = [ "passlib[bcrypt] >=1.7.2,<2.0.0", "autoflake >=1.3.1,<2.0.0", "flake8 >=3.8.3,<4.0.0", - "uvicorn[standard] >=0.12.0,<0.14.0", + "uvicorn[standard] >=0.12.0,<0.16.0", "graphene >=2.1.8,<3.0.0" ] all = [ @@ -92,7 +92,7 @@ all = [ "ujson >=4.0.1,<5.0.0", "orjson >=3.2.1,<4.0.0", "email_validator >=1.1.1,<2.0.0", - "uvicorn[standard] >=0.12.0,<0.14.0", + "uvicorn[standard] >=0.12.0,<0.16.0", "async_exit_stack >=1.0.1,<2.0.0", "async_generator >=1.10,<2.0.0" ] From 189ac3e280a3b5698ac40d2f412818106e3f05cf Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 08:07:20 +0000 Subject: [PATCH 207/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bff7aa48f..fc8e32c9f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Bump Uvicorn max range to 0.15.0. PR [#3345](https://github.com/tiangolo/fastapi/pull/3345) by [@Kludex](https://github.com/Kludex). * 💚 Fix badges in README and main page. PR [#3979](https://github.com/tiangolo/fastapi/pull/3979) by [@ghandic](https://github.com/ghandic). * 📝 Update GraphQL docs, recommend Strawberry. PR [#3981](https://github.com/tiangolo/fastapi/pull/3981) by [@tiangolo](https://github.com/tiangolo). * ✨ Add Deepset Sponsorship. PR [#3976](https://github.com/tiangolo/fastapi/pull/3976) by [@tiangolo](https://github.com/tiangolo). From 8c102814fd9ac0f0ff329273f65a743849cb2267 Mon Sep 17 00:00:00 2001 From: ArcLight_Slavik Date: Tue, 5 Oct 2021 11:40:08 +0300 Subject: [PATCH 208/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20internal=20testin?= =?UTF-8?q?g=20dependencies:=20mypy=20to=20version=200.910,=20add=20newly?= =?UTF-8?q?=20needed=20type=20packages=20(#3350)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- mypy.ini | 25 ------------------------- pyproject.toml | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 27 deletions(-) delete mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index e6a33cffb..000000000 --- a/mypy.ini +++ /dev/null @@ -1,25 +0,0 @@ -[mypy] - -# --strict -disallow_any_generics = True -disallow_subclassing_any = True -disallow_untyped_calls = True -disallow_untyped_defs = True -disallow_incomplete_defs = True -check_untyped_defs = True -disallow_untyped_decorators = True -no_implicit_optional = True -warn_redundant_casts = True -warn_unused_ignores = True -warn_return_any = True -implicit_reexport = False -strict_equality = True -# --strict end - -[mypy-fastapi.concurrency] -warn_unused_ignores = False -ignore_missing_imports = True - -[mypy-fastapi.tests.*] -ignore_missing_imports = True -check_untyped_defs = True diff --git a/pyproject.toml b/pyproject.toml index f48d034b3..7c986dbd7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ test = [ "pytest >=6.2.4,<7.0.0", "pytest-cov >=2.12.0,<3.0.0", "pytest-asyncio >=0.14.0,<0.15.0", - "mypy ==0.812", + "mypy ==0.910", "flake8 >=3.8.3,<4.0.0", "black ==20.8b1", "isort >=5.0.6,<6.0.0", @@ -63,7 +63,12 @@ test = [ "async_generator >=1.10,<2.0.0", "python-multipart >=0.0.5,<0.0.6", "aiofiles >=0.5.0,<0.6.0", - "flask >=1.1.2,<2.0.0" + "flask >=1.1.2,<2.0.0", + + # types + "types-ujson ==0.1.1", + "types-orjson ==3.6.0", + "types-dataclasses ==0.1.7; python_version<'3.7'", ] doc = [ "mkdocs >=1.1.2,<2.0.0", @@ -101,6 +106,33 @@ all = [ profile = "black" known_third_party = ["fastapi", "pydantic", "starlette"] +[tool.mypy] +# --strict +disallow_any_generics = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_defs = true +disallow_incomplete_defs = true +check_untyped_defs = true +disallow_untyped_decorators = true +no_implicit_optional = true +warn_redundant_casts = true +warn_unused_ignores = true +warn_return_any = true +implicit_reexport = false +strict_equality = true +# --strict end + +[[tool.mypy.overrides]] +module = "fastapi.concurrency" +warn_unused_ignores = false +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = "fastapi.tests.*" +ignore_missing_imports = true +check_untyped_defs = true + [tool.pytest.ini_options] addopts = [ "--strict-config", From 655db2af1f4175b7ef0dd7004d27325d980b90e4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 08:40:44 +0000 Subject: [PATCH 209/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fc8e32c9f..ea32949b2 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade internal testing dependencies: mypy to version 0.910, add newly needed type packages. PR [#3350](https://github.com/tiangolo/fastapi/pull/3350) by [@ArcLightSlavik](https://github.com/ArcLightSlavik). * ⬆️ Bump Uvicorn max range to 0.15.0. PR [#3345](https://github.com/tiangolo/fastapi/pull/3345) by [@Kludex](https://github.com/Kludex). * 💚 Fix badges in README and main page. PR [#3979](https://github.com/tiangolo/fastapi/pull/3979) by [@ghandic](https://github.com/ghandic). * 📝 Update GraphQL docs, recommend Strawberry. PR [#3981](https://github.com/tiangolo/fastapi/pull/3981) by [@tiangolo](https://github.com/tiangolo). From cf5e67590a6585355e3169072732cd73a3de4e28 Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen <3275109+hukkin@users.noreply.github.com> Date: Tue, 5 Oct 2021 10:46:42 +0200 Subject: [PATCH 210/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20required=20Python?= =?UTF-8?q?=20version=20to=20>=3D=203.6.1,=20needed=20by=20typing.Deque,?= =?UTF-8?q?=20used=20by=20Pydantic=20(#2733)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Taneli Hukkinen Co-authored-by: Sebastián Ramírez --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7c986dbd7..b2be66fa1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ requires = [ "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0" ] description-file = "README.md" -requires-python = ">=3.6" +requires-python = ">=3.6.1" [tool.flit.metadata.urls] Documentation = "https://fastapi.tiangolo.com/" From 5607c198c47da11a7998f0ca2d3aad2c0bcb7411 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 08:47:25 +0000 Subject: [PATCH 211/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ea32949b2..68c03d0eb 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade required Python version to >= 3.6.1, needed by typing.Deque, used by Pydantic. PR [#2733](https://github.com/tiangolo/fastapi/pull/2733) by [@hukkin](https://github.com/hukkin). * ⬆ Upgrade internal testing dependencies: mypy to version 0.910, add newly needed type packages. PR [#3350](https://github.com/tiangolo/fastapi/pull/3350) by [@ArcLightSlavik](https://github.com/ArcLightSlavik). * ⬆️ Bump Uvicorn max range to 0.15.0. PR [#3345](https://github.com/tiangolo/fastapi/pull/3345) by [@Kludex](https://github.com/Kludex). * 💚 Fix badges in README and main page. PR [#3979](https://github.com/tiangolo/fastapi/pull/3979) by [@ghandic](https://github.com/ghandic). From 8a02a471240b5f7991f05c2ff6bb0f49caa7d198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Tue, 5 Oct 2021 09:58:00 +0100 Subject: [PATCH 212/814] =?UTF-8?q?=E2=9E=96=20Do=20not=20require=20backpo?= =?UTF-8?q?rts=20in=20Python=20>=3D=203.7=20(#1880)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b2be66fa1..30ebe55cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,11 +59,11 @@ test = [ "databases[sqlite] >=0.3.2,<0.4.0", "orjson >=3.2.1,<4.0.0", "ujson >=4.0.1,<5.0.0", - "async_exit_stack >=1.0.1,<2.0.0", - "async_generator >=1.10,<2.0.0", "python-multipart >=0.0.5,<0.0.6", "aiofiles >=0.5.0,<0.6.0", "flask >=1.1.2,<2.0.0", + "async_exit_stack >=1.0.1,<2.0.0; python_version < '3.7'", + "async_generator >=1.10,<2.0.0; python_version < '3.7'", # types "types-ujson ==0.1.1", @@ -98,8 +98,8 @@ all = [ "orjson >=3.2.1,<4.0.0", "email_validator >=1.1.1,<2.0.0", "uvicorn[standard] >=0.12.0,<0.16.0", - "async_exit_stack >=1.0.1,<2.0.0", - "async_generator >=1.10,<2.0.0" + "async_exit_stack >=1.0.1,<2.0.0; python_version < '3.7'", + "async_generator >=1.10,<2.0.0; python_version < '3.7'", ] [tool.isort] From 69784e514161827f1702444ffd9b50585d79d6eb Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 08:58:41 +0000 Subject: [PATCH 213/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 68c03d0eb..b9fd722a9 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ➖ Do not require backports in Python >= 3.7. PR [#1880](https://github.com/tiangolo/fastapi/pull/1880) by [@FFY00](https://github.com/FFY00). * ⬆ Upgrade required Python version to >= 3.6.1, needed by typing.Deque, used by Pydantic. PR [#2733](https://github.com/tiangolo/fastapi/pull/2733) by [@hukkin](https://github.com/hukkin). * ⬆ Upgrade internal testing dependencies: mypy to version 0.910, add newly needed type packages. PR [#3350](https://github.com/tiangolo/fastapi/pull/3350) by [@ArcLightSlavik](https://github.com/ArcLightSlavik). * ⬆️ Bump Uvicorn max range to 0.15.0. PR [#3345](https://github.com/tiangolo/fastapi/pull/3345) by [@Kludex](https://github.com/Kludex). From ba8c78d87fe3901ed74e57199d4f282ea2ceb5c2 Mon Sep 17 00:00:00 2001 From: SnkSynthesis <63564282+SnkSynthesis@users.noreply.github.com> Date: Tue, 5 Oct 2021 02:17:14 -0700 Subject: [PATCH 214/814] =?UTF-8?q?=E2=AC=86Increase=20supported=20version?= =?UTF-8?q?=20of=20aiofiles=20to=20suppress=20warnings=20(#2899)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 30ebe55cc..49af63663 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ test = [ "orjson >=3.2.1,<4.0.0", "ujson >=4.0.1,<5.0.0", "python-multipart >=0.0.5,<0.0.6", - "aiofiles >=0.5.0,<0.6.0", + "aiofiles >=0.5.0,<0.8.0", "flask >=1.1.2,<2.0.0", "async_exit_stack >=1.0.1,<2.0.0; python_version < '3.7'", "async_generator >=1.10,<2.0.0; python_version < '3.7'", @@ -88,7 +88,7 @@ dev = [ ] all = [ "requests >=2.24.0,<3.0.0", - "aiofiles >=0.5.0,<0.6.0", + "aiofiles >=0.5.0,<0.8.0", "jinja2 >=2.11.2,<3.0.0", "python-multipart >=0.0.5,<0.0.6", "itsdangerous >=1.1.0,<2.0.0", From f6a3bc2902ecec1cd66b36b2f2de146055d8e26b Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 09:17:56 +0000 Subject: [PATCH 215/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b9fd722a9..c7e29cd5d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆Increase supported version of aiofiles to suppress warnings. PR [#2899](https://github.com/tiangolo/fastapi/pull/2899) by [@SnkSynthesis](https://github.com/SnkSynthesis). * ➖ Do not require backports in Python >= 3.7. PR [#1880](https://github.com/tiangolo/fastapi/pull/1880) by [@FFY00](https://github.com/FFY00). * ⬆ Upgrade required Python version to >= 3.6.1, needed by typing.Deque, used by Pydantic. PR [#2733](https://github.com/tiangolo/fastapi/pull/2733) by [@hukkin](https://github.com/hukkin). * ⬆ Upgrade internal testing dependencies: mypy to version 0.910, add newly needed type packages. PR [#3350](https://github.com/tiangolo/fastapi/pull/3350) by [@ArcLightSlavik](https://github.com/ArcLightSlavik). From 24749aef7185b2d98f22650a71e73d90f29c7f56 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:54:36 +0200 Subject: [PATCH 216/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#3986)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/people.yml | 228 ++++++++++++++++++++++------------------ 1 file changed, 124 insertions(+), 104 deletions(-) diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 1e4ee30ce..8f1710d33 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,12 +1,12 @@ maintainers: - login: tiangolo - answers: 1229 - prs: 250 - avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=05f95ca7fdead36edd9c86be46b4ef6c3c71f876&v=4 + answers: 1230 + prs: 260 + avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=5cad72c846b7aba2e960546af490edc7375dafc4&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 278 + count: 299 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: dmontagu @@ -14,11 +14,11 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu - login: ycd - count: 217 + count: 219 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: Mause - count: 202 + count: 207 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause - login: euri10 @@ -30,7 +30,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 - login: ArcLightSlavik - count: 66 + count: 68 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik - login: falkben @@ -42,7 +42,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 url: https://github.com/sm-Fifteen - login: raphaelauv - count: 47 + count: 48 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv - login: includeamin @@ -69,18 +69,26 @@ experts: count: 29 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes +- login: frankie567 + count: 29 + avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 + url: https://github.com/frankie567 - login: dbanty count: 25 - avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4 url: https://github.com/dbanty +- login: chbndrhnns + count: 24 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: SirTelemak count: 24 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak -- login: chbndrhnns - count: 23 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns +- login: STeveShary + count: 24 + avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 + url: https://github.com/STeveShary - login: acnebs count: 22 avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=bfd127b3e6200f4d00afd714f0fc95c2512df19b&v=4 @@ -89,10 +97,6 @@ experts: count: 22 avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4 url: https://github.com/nsidnev -- login: frankie567 - count: 21 - avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 - url: https://github.com/frankie567 - login: chris-allnutt count: 21 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 @@ -101,10 +105,18 @@ experts: count: 19 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 url: https://github.com/retnikt +- login: ghandic + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 + url: https://github.com/ghandic - login: Hultner count: 18 avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 url: https://github.com/Hultner +- login: panla + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla - login: jorgerpo count: 17 avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4 @@ -113,42 +125,38 @@ experts: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4 url: https://github.com/nkhitrov +- login: adriangb + count: 17 + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 + url: https://github.com/adriangb - login: waynerv count: 16 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 url: https://github.com/waynerv -- login: adriangb - count: 14 - avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 - url: https://github.com/adriangb -- login: panla - count: 14 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 - url: https://github.com/panla - login: haizaar count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar -- login: STeveShary - count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 - url: https://github.com/STeveShary - login: acidjunk - count: 11 + count: 13 avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 url: https://github.com/acidjunk +- login: David-Lor + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4 + url: https://github.com/David-Lor - login: zamiramir count: 11 avatarUrl: https://avatars.githubusercontent.com/u/40475662?u=e58ef61034e8d0d6a312cc956fb09b9c3332b449&v=4 url: https://github.com/zamiramir -- login: David-Lor - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4 - url: https://github.com/David-Lor - login: juntatalor count: 11 avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4 url: https://github.com/juntatalor +- login: dstlny + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 + url: https://github.com/dstlny - login: valentin994 count: 11 avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4 @@ -166,42 +174,42 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/47581948?v=4 url: https://github.com/hellocoldworld last_month_active: -- login: Mause - count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 - url: https://github.com/Mause - login: Kludex - count: 9 + count: 13 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex -- login: panla - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 - url: https://github.com/panla -- login: adriangb - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 - url: https://github.com/adriangb -- login: Dustyposa - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 - url: https://github.com/Dustyposa +- login: ghandic + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 + url: https://github.com/ghandic - login: STeveShary - count: 5 + count: 8 avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 url: https://github.com/STeveShary -- login: Cosmicoppai +- login: Honda-a count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/63765823?u=b97c98ddd6eaf06cd5a0d312db36f97996ac5b23&v=4 - url: https://github.com/Cosmicoppai -- login: AlexanderPodorov + avatarUrl: https://avatars.githubusercontent.com/u/22759187?u=f45bd5fb17b4dca331529b8e9e5eab6122b84b8b&v=4 + url: https://github.com/Honda-a +- login: frankie567 count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/54511144?v=4 - url: https://github.com/AlexanderPodorov -- login: SamuelHeath + avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 + url: https://github.com/frankie567 +- login: panla count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/12291364?v=4 - url: https://github.com/SamuelHeath + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla +- login: dstlny + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 + url: https://github.com/dstlny +- login: trevorwang + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/121966?v=4 + url: https://github.com/trevorwang +- login: klaa97 + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/39653693?v=4 + url: https://github.com/klaa97 top_contributors: - login: waynerv count: 25 @@ -224,19 +232,19 @@ top_contributors: avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 url: https://github.com/mariacamilagl - login: jaystone776 - count: 9 + count: 11 avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 url: https://github.com/jaystone776 +- login: Serrones + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 + url: https://github.com/Serrones - login: RunningIkkyu count: 7 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 url: https://github.com/RunningIkkyu -- login: Serrones - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 - url: https://github.com/Serrones - login: Kludex - count: 6 + count: 7 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: hard-coders @@ -255,6 +263,10 @@ top_contributors: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4 url: https://github.com/Attsun1031 +- login: Smlep + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 + url: https://github.com/Smlep - login: jekirl count: 4 avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4 @@ -267,15 +279,15 @@ top_contributors: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki -- login: Smlep - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 - url: https://github.com/Smlep top_reviewers: - login: Kludex - count: 85 + count: 90 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex +- login: waynerv + count: 47 + avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 + url: https://github.com/waynerv - login: Laineyzhang55 count: 47 avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4 @@ -284,18 +296,18 @@ top_reviewers: count: 46 avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 url: https://github.com/tokusumi -- login: waynerv - count: 43 - avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 - url: https://github.com/waynerv - login: ycd - count: 41 + count: 43 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: AdrianDeAnda - count: 28 + count: 32 avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4 url: https://github.com/AdrianDeAnda +- login: ArcLightSlavik + count: 27 + avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 + url: https://github.com/ArcLightSlavik - login: dmontagu count: 23 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 @@ -304,12 +316,8 @@ top_reviewers: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki -- login: ArcLightSlavik - count: 20 - avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 - url: https://github.com/ArcLightSlavik - login: cassiobotaro - count: 18 + count: 19 avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 url: https://github.com/cassiobotaro - login: yanever @@ -320,6 +328,10 @@ top_reviewers: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4 url: https://github.com/SwftAlpc +- login: hard-coders + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 + url: https://github.com/hard-coders - login: pedabraham count: 15 avatarUrl: https://avatars.githubusercontent.com/u/16860088?u=abf922a7b920bf8fdb7867d8b43e091f1e796178&v=4 @@ -328,10 +340,18 @@ top_reviewers: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4 url: https://github.com/delhi09 +- login: Smlep + count: 15 + avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 + url: https://github.com/Smlep - login: lsglucas - count: 13 + count: 14 avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 url: https://github.com/lsglucas +- login: rjNemo + count: 13 + avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 + url: https://github.com/rjNemo - login: RunningIkkyu count: 12 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 @@ -340,14 +360,6 @@ top_reviewers: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4 url: https://github.com/sh0nk -- login: rjNemo - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 - url: https://github.com/rjNemo -- login: hard-coders - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 - url: https://github.com/hard-coders - login: mariacamilagl count: 10 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 @@ -360,10 +372,6 @@ top_reviewers: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4 url: https://github.com/maoyibo -- login: Smlep - count: 9 - avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 - url: https://github.com/Smlep - login: PandaHun count: 9 avatarUrl: https://avatars.githubusercontent.com/u/13096845?u=646eba44db720e37d0dbe8e98e77ab534ea78a20&v=4 @@ -400,10 +408,22 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause +- login: solomein-sv + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 + url: https://github.com/solomein-sv +- login: ComicShrimp + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 + url: https://github.com/ComicShrimp - login: jovicon count: 6 avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 url: https://github.com/jovicon +- login: BilalAlpaslan + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 + url: https://github.com/BilalAlpaslan - login: nimctl count: 5 avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4 @@ -416,18 +436,10 @@ top_reviewers: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/63564282?u=0078826509dbecb2fdb543f4e881c9cd06157893&v=4 url: https://github.com/SnkSynthesis -- login: solomein-sv - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 - url: https://github.com/solomein-sv - login: anthonycepeda count: 5 avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 url: https://github.com/anthonycepeda -- login: ComicShrimp - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 - url: https://github.com/ComicShrimp - login: oandersonmagalhaes count: 5 avatarUrl: https://avatars.githubusercontent.com/u/83456692?v=4 @@ -440,6 +452,10 @@ top_reviewers: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/23391143?u=56ab6bff50be950fa8cae5cf736f2ae66e319ff3&v=4 url: https://github.com/rkbeatss +- login: izaguerreiro + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4 + url: https://github.com/izaguerreiro - login: aviramha count: 4 avatarUrl: https://avatars.githubusercontent.com/u/41201924?u=6883cc4fc13a7b2e60d4deddd4be06f9c5287880&v=4 @@ -452,6 +468,10 @@ top_reviewers: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/31370133?v=4 url: https://github.com/Zxilly +- login: dukkee + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/36825394?u=ccfd86e6a4f2d093dad6f7544cc875af67fa2df8&v=4 + url: https://github.com/dukkee - login: Bluenix2 count: 4 avatarUrl: https://avatars.githubusercontent.com/u/38372706?u=c9d28aff15958d6ebf1971148bfb3154ff943c4f&v=4 From c86a4e1dd3a83f82eafb67fd2b41b8ec8a6b93d4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 09:55:12 +0000 Subject: [PATCH 217/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c7e29cd5d..04a4a8c7e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#3986](https://github.com/tiangolo/fastapi/pull/3986) by [@github-actions[bot]](https://github.com/apps/github-actions). * ⬆Increase supported version of aiofiles to suppress warnings. PR [#2899](https://github.com/tiangolo/fastapi/pull/2899) by [@SnkSynthesis](https://github.com/SnkSynthesis). * ➖ Do not require backports in Python >= 3.7. PR [#1880](https://github.com/tiangolo/fastapi/pull/1880) by [@FFY00](https://github.com/FFY00). * ⬆ Upgrade required Python version to >= 3.6.1, needed by typing.Deque, used by Pydantic. PR [#2733](https://github.com/tiangolo/fastapi/pull/2733) by [@hukkin](https://github.com/hukkin). From 96ca425b1f7c4918d8cd2b79342b883c2fb97a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 5 Oct 2021 12:07:40 +0200 Subject: [PATCH 218/814] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Increase=20depende?= =?UTF-8?q?ncy=20ranges=20for=20tests=20and=20docs:=20pytest-cov,=20pytest?= =?UTF-8?q?-asyncio,=20black,=20httpx,=20sqlalchemy,=20databases,=20mkdocs?= =?UTF-8?q?-markdownextradata-plugin=20(#3987)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 49af63663..06802aba9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,22 +45,23 @@ Documentation = "https://fastapi.tiangolo.com/" [tool.flit.metadata.requires-extra] test = [ "pytest >=6.2.4,<7.0.0", - "pytest-cov >=2.12.0,<3.0.0", - "pytest-asyncio >=0.14.0,<0.15.0", + "pytest-cov >=2.12.0,<4.0.0", + "pytest-asyncio >=0.14.0,<0.16.0", "mypy ==0.910", "flake8 >=3.8.3,<4.0.0", - "black ==20.8b1", + "black ==21.9b0", "isort >=5.0.6,<6.0.0", "requests >=2.24.0,<3.0.0", - "httpx >=0.14.0,<0.15.0", + "httpx >=0.14.0,<0.19.0", "email_validator >=1.1.1,<2.0.0", - "sqlalchemy >=1.3.18,<1.4.0", + "sqlalchemy >=1.3.18,<1.5.0", "peewee >=3.13.3,<4.0.0", - "databases[sqlite] >=0.3.2,<0.4.0", + "databases[sqlite] >=0.3.2,<0.6.0", "orjson >=3.2.1,<4.0.0", "ujson >=4.0.1,<5.0.0", "python-multipart >=0.0.5,<0.0.6", "aiofiles >=0.5.0,<0.8.0", + # TODO: try to upgrade after upgrading Starlette "flask >=1.1.2,<2.0.0", "async_exit_stack >=1.0.1,<2.0.0; python_version < '3.7'", "async_generator >=1.10,<2.0.0; python_version < '3.7'", @@ -74,7 +75,7 @@ doc = [ "mkdocs >=1.1.2,<2.0.0", "mkdocs-material >=7.1.9,<8.0.0", "mdx-include >=1.4.1,<2.0.0", - "mkdocs-markdownextradata-plugin >=0.1.7,<0.2.0", + "mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0", "typer-cli >=0.0.12,<0.0.13", "pyyaml >=5.3.1,<6.0.0" ] @@ -84,15 +85,19 @@ dev = [ "autoflake >=1.3.1,<2.0.0", "flake8 >=3.8.3,<4.0.0", "uvicorn[standard] >=0.12.0,<0.16.0", + # TODO: remove in the next major version "graphene >=2.1.8,<3.0.0" ] all = [ "requests >=2.24.0,<3.0.0", "aiofiles >=0.5.0,<0.8.0", + # TODO: try to upgrade after upgrading Starlette "jinja2 >=2.11.2,<3.0.0", "python-multipart >=0.0.5,<0.0.6", + # TODO: try to upgrade after upgrading Starlette "itsdangerous >=1.1.0,<2.0.0", "pyyaml >=5.3.1,<6.0.0", + # TODO: remove in the next major version "graphene >=2.1.8,<3.0.0", "ujson >=4.0.1,<5.0.0", "orjson >=3.2.1,<4.0.0", From 9229ba8078897d5ad1210d42b0cf4b672dc06457 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 10:08:26 +0000 Subject: [PATCH 219/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 04a4a8c7e..dc623d9b0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Increase dependency ranges for tests and docs: pytest-cov, pytest-asyncio, black, httpx, sqlalchemy, databases, mkdocs-markdownextradata-plugin. PR [#3987](https://github.com/tiangolo/fastapi/pull/3987) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#3986](https://github.com/tiangolo/fastapi/pull/3986) by [@github-actions[bot]](https://github.com/apps/github-actions). * ⬆Increase supported version of aiofiles to suppress warnings. PR [#2899](https://github.com/tiangolo/fastapi/pull/2899) by [@SnkSynthesis](https://github.com/SnkSynthesis). * ➖ Do not require backports in Python >= 3.7. PR [#1880](https://github.com/tiangolo/fastapi/pull/1880) by [@FFY00](https://github.com/FFY00). From ae22bca9fea481eb0bd20e08dcd5f89d9e158894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 5 Oct 2021 12:17:31 +0200 Subject: [PATCH 220/814] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20developm?= =?UTF-8?q?ent=20`autoflake`,=20supporting=20multi-line=20imports=20(#3988?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/contributing.md | 14 -------------- pyproject.toml | 2 +- scripts/format-imports.sh | 6 ------ 3 files changed, 1 insertion(+), 21 deletions(-) delete mode 100755 scripts/format-imports.sh diff --git a/docs/en/docs/contributing.md b/docs/en/docs/contributing.md index cd87faa4e..9ef6e22c8 100644 --- a/docs/en/docs/contributing.md +++ b/docs/en/docs/contributing.md @@ -163,20 +163,6 @@ It will also auto-sort all your imports. For it to sort them correctly, you need to have FastAPI installed locally in your environment, with the command in the section above using `--symlink` (or `--pth-file` on Windows). -### Format imports - -There is another script that formats all the imports and makes sure you don't have unused imports: - -

- -As it runs one command after the other and modifies and reverts many files, it takes a bit longer to run, so it might be easier to use `scripts/format.sh` frequently and `scripts/format-imports.sh` only before committing. - ## Docs First, make sure you set up your environment as described above, that will install all the requirements. diff --git a/pyproject.toml b/pyproject.toml index 06802aba9..5b6b272a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,7 @@ doc = [ dev = [ "python-jose[cryptography] >=3.3.0,<4.0.0", "passlib[bcrypt] >=1.7.2,<2.0.0", - "autoflake >=1.3.1,<2.0.0", + "autoflake >=1.4.0,<2.0.0", "flake8 >=3.8.3,<4.0.0", "uvicorn[standard] >=0.12.0,<0.16.0", # TODO: remove in the next major version diff --git a/scripts/format-imports.sh b/scripts/format-imports.sh deleted file mode 100755 index 1fe193b97..000000000 --- a/scripts/format-imports.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -e -set -x - -# Sort imports one per line, so autoflake can remove unused imports -isort fastapi tests docs_src scripts --force-single-line-imports -sh ./scripts/format.sh From 458a7fbf15034d848ab0f099a965e4c622fb41db Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 10:18:13 +0000 Subject: [PATCH 221/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index dc623d9b0..005d024ba 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade development `autoflake`, supporting multi-line imports. PR [#3988](https://github.com/tiangolo/fastapi/pull/3988) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Increase dependency ranges for tests and docs: pytest-cov, pytest-asyncio, black, httpx, sqlalchemy, databases, mkdocs-markdownextradata-plugin. PR [#3987](https://github.com/tiangolo/fastapi/pull/3987) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#3986](https://github.com/tiangolo/fastapi/pull/3986) by [@github-actions[bot]](https://github.com/apps/github-actions). * ⬆Increase supported version of aiofiles to suppress warnings. PR [#2899](https://github.com/tiangolo/fastapi/pull/2899) by [@SnkSynthesis](https://github.com/SnkSynthesis). From 557fe61d9298d213f26357439c59bf3002b78979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 5 Oct 2021 12:24:02 +0200 Subject: [PATCH 222/814] =?UTF-8?q?=E2=9C=A8=20Update=20GitHub=20Action:?= =?UTF-8?q?=20notify-translations,=20to=20avoid=20a=20race=20conditon=20(#?= =?UTF-8?q?3989)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../actions/notify-translations/app/main.py | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/actions/notify-translations/app/main.py b/.github/actions/notify-translations/app/main.py index 79850513a..7d6c1a4d2 100644 --- a/.github/actions/notify-translations/app/main.py +++ b/.github/actions/notify-translations/app/main.py @@ -1,5 +1,7 @@ import logging +import time from pathlib import Path +import random from typing import Dict, Optional import yaml @@ -45,8 +47,11 @@ if __name__ == "__main__": github_event = PartialGitHubEvent.parse_raw(contents) translations_map: Dict[str, int] = yaml.safe_load(translations_path.read_text()) logging.debug(f"Using translations map: {translations_map}") + sleep_time = random.random() * 10 # random number between 0 and 10 seconds pr = repo.get_pull(github_event.pull_request.number) - logging.debug(f"Processing PR: {pr.number}") + logging.debug( + f"Processing PR: {pr.number}, with anti-race condition sleep time: {sleep_time}" + ) if pr.state == "open": logging.debug(f"PR is open: {pr.number}") label_strs = set([label.name for label in pr.get_labels()]) @@ -67,19 +72,31 @@ if __name__ == "__main__": for lang in langs: if lang in translations_map: num = translations_map[lang] - logging.info(f"Found a translation issue for language: {lang} in issue: {num}") + logging.info( + f"Found a translation issue for language: {lang} in issue: {num}" + ) issue = repo.get_issue(num) message = f"Good news everyone! 😉 There's a new translation PR to be reviewed: #{pr.number} 🎉" already_notified = False - logging.info(f"Checking current comments in issue: {num} to see if already notified about this PR: {pr.number}") + time.sleep(sleep_time) + logging.info( + f"Sleeping for {sleep_time} seconds to avoid race conditions and multiple comments" + ) + logging.info( + f"Checking current comments in issue: {num} to see if already notified about this PR: {pr.number}" + ) for comment in issue.get_comments(): if message in comment.body: already_notified = True if not already_notified: - logging.info(f"Writing comment in issue: {num} about PR: {pr.number}") + logging.info( + f"Writing comment in issue: {num} about PR: {pr.number}" + ) issue.create_comment(message) else: - logging.info(f"Issue: {num} was already notified of PR: {pr.number}") + logging.info( + f"Issue: {num} was already notified of PR: {pr.number}" + ) else: logging.info( f"Changing labels in a closed PR doesn't trigger comments, PR: {pr.number}" From 39ec5b33d9d4109333d9429352db792464b159a6 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 10:24:47 +0000 Subject: [PATCH 223/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 005d024ba..1e260585f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Update GitHub Action: notify-translations, to avoid a race conditon. PR [#3989](https://github.com/tiangolo/fastapi/pull/3989) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade development `autoflake`, supporting multi-line imports. PR [#3988](https://github.com/tiangolo/fastapi/pull/3988) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Increase dependency ranges for tests and docs: pytest-cov, pytest-asyncio, black, httpx, sqlalchemy, databases, mkdocs-markdownextradata-plugin. PR [#3987](https://github.com/tiangolo/fastapi/pull/3987) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#3986](https://github.com/tiangolo/fastapi/pull/3986) by [@github-actions[bot]](https://github.com/apps/github-actions). From 6de87487888b762b2c4f83b67db97b8c8d6b0584 Mon Sep 17 00:00:00 2001 From: Lucas <61513630+lsglucas@users.noreply.github.com> Date: Tue, 5 Oct 2021 07:40:05 -0300 Subject: [PATCH 224/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/deployment/https.md`=20(#3754)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/pt/docs/deployment/https.md | 48 ++++++++++++++++++++++++++++++++ docs/pt/mkdocs.yml | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 docs/pt/docs/deployment/https.md diff --git a/docs/pt/docs/deployment/https.md b/docs/pt/docs/deployment/https.md new file mode 100644 index 000000000..f85861e92 --- /dev/null +++ b/docs/pt/docs/deployment/https.md @@ -0,0 +1,48 @@ +# Sobre HTTPS + +É fácil assumir que HTTPS é algo que é apenas "habilitado" ou não. + +Mas é bem mais complexo do que isso. + +!!! tip "Dica" + Se você está com pressa ou não se importa, continue com as seções seguintes para instruções passo a passo para configurar tudo com diferentes técnicas. + +Para aprender o básico de HTTPS de uma perspectiva do usuário, verifique https://howhttps.works/pt-br/. + +Agora, a partir de uma perspectiva do desenvolvedor, aqui estão algumas coisas para ter em mente ao pensar em HTTPS: + +* Para HTTPS, o servidor precisa ter certificados gerados por um terceiro. + * Esses certificados são adquiridos de um terceiro, eles não são simplesmente "gerados". +* Certificados têm um tempo de vida. + * Eles expiram. + * E então eles precisam ser renovados, adquirindo-os novamente de um terceiro. +* A criptografia da conexão acontece no nível TCP. + * Essa é uma camada abaixo do HTTP. + * Portanto, o manuseio do certificado e da criptografia é feito antes do HTTP. +* O TCP não sabe sobre "domínios". Apenas sobre endereços IP. + * As informações sobre o domínio solicitado vão nos dados HTTP. +* Os certificados HTTPS “certificam” um determinado domínio, mas o protocolo e a encriptação acontecem ao nível do TCP, antes de sabermos de que domínio se trata. +* Por padrão, isso significa que você só pode ter um certificado HTTPS por endereço IP. + * Não importa o tamanho do seu servidor ou quão pequeno cada aplicativo que você tem nele possa ser. + * No entanto, existe uma solução para isso. +* Há uma extensão para o protocolo TLS (aquele que lida com a criptografia no nível TCP, antes do HTTP) chamado SNI. + * Esta extensão SNI permite que um único servidor (com um único endereço IP) tenha vários certificados HTTPS e atenda a vários domínios / aplicativos HTTPS. + * Para que isso funcione, um único componente (programa) em execução no servidor, ouvindo no endereço IP público, deve ter todos os certificados HTTPS no servidor. +* Depois de obter uma conexão segura, o protocolo de comunicação ainda é HTTP. + * Os conteúdos são criptografados, embora sejam enviados com o protocolo HTTP. + +É uma prática comum ter um programa/servidor HTTP em execução no servidor (máquina, host, etc.) e gerenciar todas as partes HTTPS: enviando as solicitações HTTP descriptografadas para o aplicativo HTTP real em execução no mesmo servidor (a aplicação **FastAPI**, neste caso), pegue a resposta HTTP do aplicativo, criptografe-a usando o certificado apropriado e envie-a de volta ao cliente usando HTTPS. Este servidor é frequentemente chamado de TLS Termination Proxy. + +## Let's Encrypt + +Antes de Let's Encrypt, esses certificados HTTPS eram vendidos por terceiros confiáveis. + +O processo de aquisição de um desses certificados costumava ser complicado, exigia bastante papelada e os certificados eram bastante caros. + +Mas então Let's Encrypt foi criado. + +Ele é um projeto da Linux Foundation que fornece certificados HTTPS gratuitamente. De forma automatizada. Esses certificados usam toda a segurança criptográfica padrão e têm vida curta (cerca de 3 meses), então a segurança é realmente melhor por causa de sua vida útil reduzida. + +Os domínios são verificados com segurança e os certificados são gerados automaticamente. Isso também permite automatizar a renovação desses certificados. + +A ideia é automatizar a aquisição e renovação desses certificados, para que você tenha HTTPS seguro, de graça e para sempre. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index ec0684d54..63c524d84 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -67,6 +67,7 @@ nav: - Implantação: - deployment/index.md - deployment/versions.md + - deployment/https.md - alternatives.md - history-design-future.md - external-links.md @@ -140,4 +141,3 @@ extra_css: extra_javascript: - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js - From 4e2595f9283f9151c22dc6a4104b59b668ea6357 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 10:40:42 +0000 Subject: [PATCH 225/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1e260585f..a2bace259 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/deployment/https.md`. PR [#3754](https://github.com/tiangolo/fastapi/pull/3754) by [@lsglucas](https://github.com/lsglucas). * ✨ Update GitHub Action: notify-translations, to avoid a race conditon. PR [#3989](https://github.com/tiangolo/fastapi/pull/3989) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade development `autoflake`, supporting multi-line imports. PR [#3988](https://github.com/tiangolo/fastapi/pull/3988) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Increase dependency ranges for tests and docs: pytest-cov, pytest-asyncio, black, httpx, sqlalchemy, databases, mkdocs-markdownextradata-plugin. PR [#3987](https://github.com/tiangolo/fastapi/pull/3987) by [@tiangolo](https://github.com/tiangolo). From e0e32245883616f944794abaddeace967a9edd13 Mon Sep 17 00:00:00 2001 From: jaystone776 Date: Tue, 5 Oct 2021 19:03:59 +0800 Subject: [PATCH 226/814] =?UTF-8?q?=F0=9F=8C=90=20Delete=20old=20Chinese?= =?UTF-8?q?=20translation=20for=20`docs/deployment.md`=20(#3840)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/zh/docs/deployment.md | 392 ------------------------------------- docs/zh/mkdocs.yml | 1 - 2 files changed, 393 deletions(-) delete mode 100644 docs/zh/docs/deployment.md diff --git a/docs/zh/docs/deployment.md b/docs/zh/docs/deployment.md deleted file mode 100644 index 4dac57bef..000000000 --- a/docs/zh/docs/deployment.md +++ /dev/null @@ -1,392 +0,0 @@ -# 部署 - -部署 **FastAPI** 应用相对比较简单。 - -根据特定使用情况和使用工具有几种不同的部署方式。 - -接下来的章节,你将了解到一些关于部署方式的内容。 - -## FastAPI 版本 - -许多应用和系统已经在生产环境使用 **FastAPI**。其测试覆盖率保持在 100%。但该项目仍在快速开发。 - -我们会经常加入新的功能,定期错误修复,同时也在不断的优化项目代码。 - -这也是为什么当前版本仍然是 `0.x.x`,我们以此表明每个版本都可能有重大改变。 - -现在就可以使用 **FastAPI** 创建生产应用(你可能已经使用一段时间了)。你只需要确保使用的版本和代码其他部分能够正常兼容。 - -### 指定你的 `FastAPI` 版本 - -你应该做的第一件事情,是为你正在使用的 **FastAPI** 指定一个能够正确运行你的应用的最新版本。 - -例如,假设你的应用中正在使用版本 `0.45.0`。 - -如果你使用 `requirements.txt` 文件,你可以这样指定版本: - -```txt -fastapi==0.45.0 -``` - -这表明你将使用 `0.45.0` 版本的 `FastAPI`。 - -或者你也可以这样指定: - -```txt -fastapi>=0.45.0,<0.46.0 -``` - -这表明你将使用 `0.45.0` 及以上,但低于 `0.46.0` 的版本,例如,`0.45.2` 依然可以接受。 - -如果使用其他工具管理你的安装,比如 Poetry,Pipenv,或者其他工具,它们都有各自指定包的版本的方式。 - -### 可用版本 - -你可以在 [发行说明](release-notes.md){.internal-link target=_blank} 中查看可用的版本(比如:检查最新版本是什么)。 - - -### 关于版本 - -FastAPI 遵循语义版本控制约定,`1.0.0` 以下的任何版本都可能加入重大变更。 - -FastAPI 也遵循这样的约定:任何 ”PATCH“ 版本变更都是用来修复 bug 和向下兼容的变更。 - -!!! tip - "PATCH" 是指版本号的最后一个数字,例如,在 `0.2.3` 中,PATCH 版本是 `3`。 - -所以,你应该像这样指定版本: - -```txt -fastapi>=0.45.0,<0.46.0 -``` - -不兼容变更和新特性在 "MINOR" 版本中添加。 - -!!! tip - "MINOR" 是版本号中间的数字,例如,在 `0.2.3` 中,MINOR 版本是 `2`。 - -### 更新 FaseAPI 版本 - -你应该为你的应用添加测试。 - -使用 **FastAPI** 测试应用非常容易(归功于 Starlette),查看文档:[测试](tutorial/testing.md){.internal-link target=_blank} - -有了测试之后,就可以将 **FastAPI** 更新到最近的一个的版本,然后通过运行测试来确定你所有代码都可以正确工作。 - -如果一切正常,或者做了必要的修改之后,所有的测试都通过了,就可以把 `FastAPI` 版本指定为那个比较新的版本了。 - -### 关于 Starlette - -不要指定 `starlette` 的版本。 - -不同版本的 **FastAPI** 会使用特定版本的 Starlette。 - -所以你只要让 **FastAPI** 自行选择正确的 Starlette 版本。 - -### 关于 Pydantic - -Pydantic 自身的测试中已经包含了 **FastAPI** 的测试,所以最新版本的 Pydantic (`1.0.0` 以上版本)总是兼容 **FastAPI**。 - -你可以指定 Pydantic 为任意一个高于 `1.0.0` 且低于的 `2.0.0` 的版本。 - -例如: - -```txt -pydantic>=1.2.0,<2.0.0 -``` - -## Docker - -这部分,你将通过指引和链接了解到: - -* 如何将你的 **FastAPI** 应用制作成最高性能的 **Docker** 映像/容器。约需五分钟。 -* (可选)理解作为一个开发者需要知道的 HTTPS 相关知识。 -* 使用自动化 HTTPS 设置一个 Docker Swarm 模式的集群,即使是在一个简单的 $5 USD/month 的服务器上。约需要 20 分钟。 -* 使用 Docker Swarm 集群以及 HTTP 等等,生成和部署一个完整的 **FastAPI** 应用。约需 10 分钟。 - -可以使用 **Docker** 进行部署。它具有安全性、可复制性、开发简单性等优点。 - -如果你正在使用 Docker,你可以使用官方 Docker 镜像: - -### tiangolo/uvicorn-gunicorn-fastapi - -该映像包含一个「自动调优」的机制,这样就可以仅仅添加代码就能自动获得超高性能,而不用做出牺牲。 - -不过你仍然可以使用环境变量或配置文件更改和更新所有配置。 - -!!! tip - 查看全部配置和选项,请移步 Docker 镜像页面:tiangolo/uvicorn-gunicorn-fastapi。 - -### 创建 `Dockerfile` - -* 进入你的项目目录。 -* 使用如下命令创建一个 `Dockerfile`: - -```Dockerfile -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 - -COPY ./app /app -``` - -#### 大型应用 - -如果遵循创建 [多文件大型应用](tutorial/bigger-applications.md){.internal-link target=_blank} 的章节,你的 Dockerfile 可能看起来是这样: - -```Dockerfile -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 - -COPY ./app /app/app -``` - -#### 树莓派以及其他架构 - -如果你在树莓派或者任何其他架构中运行 Docker,可以基于 Python 基础镜像(它是多架构的)从头创建一个 `Dockerfile` 并单独使用 Uvicorn。 - -这种情况下,你的 `Dockerfile` 可能是这样的: - -```Dockerfile -FROM python:3.7 - -RUN pip install fastapi uvicorn - -EXPOSE 80 - -COPY ./app /app - -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] -``` - -### 创建 **FastAPI** 代码 - -* 创建一个 `app` 目录并进入该目录。 -* 创建一个 `main.py` 文件,内容如下: - -```Python -from typing import Optional - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): - return {"item_id": item_id, "q": q} -``` - -* 现在目录结构如下: - -``` -. -├── app -│ └── main.py -└── Dockerfile -``` - -### 构建 Docker 镜像 - -* 进入项目目录(在 `Dockerfile` 所在的位置,包含 `app` 目录) -* 构建 **FastAPI** 镜像 - -
- -```console -$ docker build -t myimage . - ----> 100% -``` - -
- -### 启动 Docker 容器 - -* 运行基于你的镜像容器: - -
- -```console -$ docker run -d --name mycontainer -p 80:80 myimage -``` - -
- -现在你在 Docker 容器中有了一个根据当前服务器(和CPU核心的数量)自动优化好的 FastAPI 服务器。 - -### 检查一下 - -你应该能够在 Docker 容器的 URL 中检查它。例如:http://192.168.99.100/items/5?q=somequery 或者 http://127.0.0.1/items/5?q=somequery (或者类似的,使用Docker主机)。 - -得到类似的输出: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -### 交互式 API 文档 - -现在可以访问 http://192.168.99.100/docs 或者 http://127.0.0.1/docs (或者类似的,使用Docker主机)。 - -你会看到一个交互式的 API 文档 (由 Swagger UI 提供): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### 可选的 API 文档 - -你也可以访问 http://192.168.99.100/redoc 或者 http://127.0.0.1/redoc (或者类似的,使用Docker主机)。 - -你将看到一个可选的自动化文档(由 ReDoc 提供) - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## HTTPS - -### 关于 HTTPS - -我们当然可以假设 HTTPS 只是某种「启用」或「不启用」的东西。 - -但是事实比这要复杂的多。 - -!!! tip - 如果你着急或者不关心这部分内容,请继续按照下一章节的步骤进行配置。 - -要从用户的角度学习 HTTPS 的基础,请移步 https://howhttps.works/。 - -从开发人员的角度来看,在考虑 HTTPS 时有以下几点需要注意: - -* 对 HTTPS 来说,服务端需要有第三方生成的「证书」。 - * 实际上这些证书是从第三方获取的,而非「生成」的。 -* 证书有生命周期。 - * 证书会过期。 - * 证书过期之后需要更新,重新从第三方获取。 -* 连接的加密发生在 TCP 层。 - * TCP 层在 HTTP 之下一层。 - * 因此,证书和加密处理在 HTTP 之前完成。 -* TCP 不知道「域名」,只知道 IP 地址。 - * 指定域名的请求信息在 HTTP 的数据中。 -* HTTPS 证书「认证」某个特定域名,但是协议和加密在知道要处理哪个域名之前就已经在 TCP 层发生了。 -* 默认情况下,一个 IP 地址仅有一个 HTTPS 证书。 - * 无论你的服务器大小,都是如此。 - * 但是对此有解决办法。 -* TSL 协议(在 TCP 层处理加密的协议,发生在 HTTP 之前)有一个扩展,叫 SNI。 - * SNI 扩展允许一个服务器(一个 IP 地址)有多个 HTTPS 证书,为多个 HTTPS 域名/应用 提供服务。 - * 要使其工作,服务器运行的单一组件(程序)监听公网 IP 地址,所有 HTTPS 证书必须都在该服务器上。 -* 在获得一个安全连接之后,通讯协议仍然是 HTTP。 - * HTTP 内容是加密的,即使这些内容使用 HTTP 协议传输。 - -常见的做法是在服务器(机器,主机等等)上运行一个程序或 HTTP 服务来管理所有的 HTTPS 部分:将解密后的 HTTP 请求发送给在同一服务器运行的真实 HTTP 应用(在这里是 **FastAPI** 应用),从应用获得 HTTP 响应,使用适当的证书加密响应然后使用 HTTPS 将其发回客户端。这个服务器常被称作 TLS 终止代理。 - - -### Let's Encrypt - -在 Let's Encrypt 出现之前,这些 HTTPS 证书由受信任的第三方出售。 - -获取这些证书的过程曾经非常繁琐,需要大量的文书工作,而且证书的价格也相当昂贵。 - -但是紧接着 Let's Encrypt 被创造了。 - -这是一个来自 Linux 基金会的项目。它以自动化的方式免费提供 HTTPS 证书。这些证书使用所有的标准加密措施,且证书生命周期很短(大约 3 个月),正是由于它们生命周期的减短,所以实际上安全性更高。 - -对域名进行安全验证并自动生成证书。同时也允许自动更新这些证书。 - -其想法是自动获取和更新这些证书,这样就可以一直免费获得安全的 HTTPS。 - -### Traefik - -Traefik 是一个高性能的反向代理/负载均衡器。它能够完成「TLS 终止代理」的工作(其他特性除外)。 - -Traefik 集成了 Let's Encrypt,所以能够处理全部 HTTPS 的部分,包括证书获取与更新。 - -Traefik 也集成了 Docker,所以你也可以在每个应用的配置中声明你的域名并可以让它读取这些配置,生成 HTTPS 证书并自动将 HTTPS 提供给你的应用程序,而你不需要对其配置进行任何更改。 - ---- - -有了这些信息和工具,就可以进入下一节把所有内容结合到一起。 - -## 通过 Traefik 和 HTTPS 搭建 Docker Swarm mode 集群 - -通过一个主要的 Traefik 来处理 HTTPS (包括证书获取和更新),大约 20 分钟就可以搭建好一个 Docker Swarm mode 集群。 - -借助 Docker Swarm mode,你可以从单个机器的集群开始(甚至可以是 $5 /月的服务器),然后你可以根据需要添加更多的服务器来进行扩展。 - -要使用 Traefik 和 HTTPS 处理来构建 Docker Swarm Mode 集群,请遵循以下指南: - -### Docker Swarm Mode 和 Traefik 用于 HTTPS 集群 - -### 部署一个 FastAPI 应用 - -部署的最简单方式就是使用 [**FastAPI** 项目生成器](project-generation.md){.internal-link target=_blank}。 - -它被设计成与上述带有 Traefik 和 HTTPS 的 Docker Swarm 集群整合到一起。 - -你可以在大概两分钟内生成一个项目。 - -生成的项目有部署说明,需要再花两分钟部署项目。 - -## 或者,不用 Docker 部署 **FastAPI** - -你也可以不用 Docker 直接部署 **FastAPI**。 - -只需要安装一个兼容 ASGI 的服务器: - -* Uvicorn,一个轻量快速的 ASGI 服务器,基于 uvloop 和 httptools 构建。 - -
- -```console -$ pip install uvicorn[standard] - ----> 100% -``` - -
- -* Hypercorn,一个也兼容 HTTP/2 的 ASGI 服务器。 - -
- -```console -$ pip install hypercorn - ----> 100% -``` - -
- -...或者任何其他的 ASGI 服务器。 - -然后使用教程中同样的方式来运行你的应用,但是不要加 `--reload` 选项,比如: - -
- -```console -$ uvicorn main:app --host 0.0.0.0 --port 80 - -INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit) -``` - -
- -或者使用 Hypercorn: - -
- -```console -$ hypercorn main:app --bind 0.0.0.0:80 - -Running on 0.0.0.0:8080 over http (CTRL + C to quit) -``` - -
- -也许你想编写一些工具来确保它停止时会自动重启。 - -或者安装 Gunicorn将其作为 Uvicorn 的管理器,或者使用多职程(worker)的 Hypercorn。 - -或者保证精确调整职程的数量等等。 - -但是如果你正做这些,你可能只需要使用 Docker 镜像就能够自动做到这些了。 diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index d73afaa93..713919934 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -101,7 +101,6 @@ nav: - advanced/additional-status-codes.md - advanced/response-directly.md - advanced/custom-response.md -- deployment.md - contributing.md - help-fastapi.md - benchmarks.md From 8c36572d23893a39732290a1ad74df60cb16fd61 Mon Sep 17 00:00:00 2001 From: Felipe Silva <66804965+FelipeSilva93@users.noreply.github.com> Date: Tue, 5 Oct 2021 09:19:03 -0300 Subject: [PATCH 227/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/tutorial/path-params.md`=20(#3664)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mário Victor Ribeiro Silva Co-authored-by: Izabela Guerreiro Co-authored-by: Marcelo Trylesinski Co-authored-by: Lucas <61513630+lsglucas@users.noreply.github.com> Co-authored-by: Felipe Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/path-params.md | 246 +++++++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 247 insertions(+) create mode 100644 docs/pt/docs/tutorial/path-params.md diff --git a/docs/pt/docs/tutorial/path-params.md b/docs/pt/docs/tutorial/path-params.md new file mode 100644 index 000000000..20913a564 --- /dev/null +++ b/docs/pt/docs/tutorial/path-params.md @@ -0,0 +1,246 @@ +# Parâmetros da rota da URL + +Você pode declarar os "parâmetros" ou "variáveis" com a mesma sintaxe utilizada pelo formato de strings do Python: + +```Python hl_lines="6-7" +{!../../../docs_src/path_params/tutorial001.py!} +``` + +O valor do parâmetro que foi passado à `item_id` será passado para a sua função como o argumento `item_id`. + +Então, se você rodar este exemplo e for até http://127.0.0.1:8000/items/foo, você verá a seguinte resposta: + +```JSON +{"item_id":"foo"} +``` + +## Parâmetros da rota com tipos + +Você pode declarar o tipo de um parâmetro na função usando as anotações padrões do Python: + +```Python hl_lines="7" +{!../../../docs_src/path_params/tutorial002.py!} +``` + +Nesse caso, `item_id` está sendo declarado como um `int`. + +!!! Check Verifique + Isso vai dar à você suporte do seu editor dentro das funções, com verificações de erros, autocompletar, etc. + +## Conversão de dados + +Se você rodar esse exemplo e abrir o seu navegador em http://127.0.0.1:8000/items/3, você verá a seguinte resposta: + +```JSON +{"item_id":3} +``` + +!!! Verifique + Observe que o valor recebido pela função (e também retornado por ela) é `3`, como um Python `int`, não como uma string `"3"`. + + Então, com essa declaração de tipo, o **FastAPI** dá pra você um "parsing" automático no request . + +## Validação de dados + +Mas se você abrir o seu navegador em http://127.0.0.1:8000/items/foo, você verá um belo erro HTTP: + +```JSON +{ + "detail": [ + { + "loc": [ + "path", + "item_id" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ] +} +``` + +devido ao parâmetro da rota `item_id` ter um valor `"foo"`, que não é um `int`. + +O mesmo erro apareceria se você tivesse fornecido um `float` ao invés de um `int`, como em: http://127.0.0.1:8000/items/4.2 + +!!! Verifique + Então, com a mesma declaração de tipo do Python, o **FastAPI** dá pra você validação de dados. + + Observe que o erro também mostra claramente o ponto exato onde a validação não passou. + + Isso é incrivelmente útil enquanto se desenvolve e debuga o código que interage com a sua API. + +## Documentação + +Quando você abrir o seu navegador em http://127.0.0.1:8000/docs, você verá de forma automática e interativa a documtação da API como: + + + +!!! check + Novamente, apenas com a mesma declaração de tipo do Python, o **FastAPI** te dá de forma automática e interativa a documentação (integrada com o Swagger UI). + + Veja que o parâmetro de rota está declarado como sendo um inteiro (int). + +## Beneficios baseados em padrões, documentação alternativa + +Devido ao schema gerado ser o padrão do OpenAPI, existem muitas ferramentas compatíveis. + +Por esse motivo, o próprio **FastAPI** fornece uma API alternativa para documentação (utilizando ReDoc), que você pode acessar em http://127.0.0.1:8000/redoc: + + + +Da mesma forma, existem muitas ferramentas compatíveis. Incluindo ferramentas de geração de código para muitas linguagens. + +## Pydantic + +Toda a validação de dados é feita por baixo dos panos pelo Pydantic, então você tem todos os benefícios disso. E assim você sabe que está em boas mãos. + +Você pode usar as mesmas declarações de tipo com `str`, `float`, `bool` e muitos outros tipos complexos de dados. + +Vamos explorar muitos destes tipos nos próximos capítulos do tutorial. + +## A ordem importa + +Quando você cria operações de rota, você pode se deparar com situações onde você pode ter uma rota fixa. + +Algo como `/users/me` por exemplo, digamos que essa rota seja utilizada para pegar dados sobre o usuário atual. + +E então você pode ter também uma rota `/users/{user_id}` para pegar dados sobre um usuário específico associado a um ID de usuário. + +Porque as operações de rota são avaliadas em ordem, você precisa ter certeza que a rota para `/users/me` está sendo declarado antes da rota `/users/{user_id}`: + +```Python hl_lines="6 11" +{!../../../docs_src/path_params/tutorial003.py!} +``` + +Caso contrário, a rota para `/users/{user_id}` coincidiria também para `/users/me`, "pensando" que estaria recebendo o parâmetro `user_id` com o valor de `"me"`. + +## Valores predefinidos + +Se você tem uma operação de rota que recebe um parâmetro da rota, mas que você queira que esses valores possíveis do parâmetro da rota sejam predefinidos, você pode usar `Enum` padrão do Python. + +### Criando uma classe `Enum` + +Importe `Enum` e crie uma sub-classe que herde de `str` e de `Enum`. + +Por herdar de `str` a documentação da API vai ser capaz de saber que os valores devem ser do tipo `string` e assim ser capaz de mostrar eles corretamente. + +Assim, crie atributos de classe com valores fixos, que serão os valores válidos disponíveis. + +```Python hl_lines="1 6-9" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +!!! informação + Enumerations (ou enums) estão disponíveis no Python desde a versão 3.4. + +!!! dica + Se você está se perguntando, "AlexNet", "ResNet", e "LeNet" são apenas nomes de modelos de Machine Learning (aprendizado de máquina). + +### Declare um *parâmetro de rota* + +Logo, crie um *parâmetro de rota* com anotações de tipo usando a classe enum que você criou (`ModelName`): + +```Python hl_lines="16" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +### Revise a documentação + +Visto que os valores disponíveis para o parâmetro da rota estão predefinidos, a documentação interativa pode mostrar esses valores de uma forma bem legal: + + + +### Trabalhando com os *enumeration* do Python + +O valor do *parâmetro da rota* será um *membro de enumeration*. + +#### Compare *membros de enumeration* + +Você pode comparar eles com o *membro de enumeration* no enum `ModelName` que você criou: + +```Python hl_lines="17" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +#### Obtenha o *valor de enumerate* + +Você pode ter o valor exato de enumerate (um `str` nesse caso) usando `model_name.value`, ou em geral, `your_enum_member.value`: + +```Python hl_lines="20" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +!!! conselho + Você também poderia acessar o valor `"lenet"` com `ModelName.lenet.value` + +#### Retorne *membros de enumeration* + +Você pode retornar *membros de enum* da sua *rota de operação*, em um corpo JSON aninhado (por exemplo um `dict`). + +Eles serão convertidos para o seus valores correspondentes (strings nesse caso) antes de serem retornados ao cliente: + +```Python hl_lines="18 21 23" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +No seu cliente você vai obter uma resposta JSON como: + +```JSON +{ + "model_name": "alexnet", + "message": "Deep Learning FTW!" +} +``` + +## Parâmetros de rota que contém caminhos + +Digamos que você tenha uma *operação de rota* com uma rota `/files/{file_path}`. + +Mas você precisa que o próprio `file_path` contenha uma *rota*, como `home/johndoe/myfile.txt`. + +Então, a URL para este arquivo deveria ser algo como: `/files/home/johndoe/myfile.txt`. + +### Suporte do OpenAPI + +O OpenAPI não suporta uma maneira de declarar um *parâmetro de rota* que contenha uma *rota* dentro, dado que isso poderia levar a cenários que são difíceis de testar e definir. + +No entanto, você pode fazer isso no **FastAPI**, usando uma das ferramentas internas do Starlette. + +A documentação continuaria funcionando, ainda que não adicionaria nenhuma informação dizendo que o parâmetro deveria conter uma rota. + +### Conversor de rota + +Usando uma opção direta do Starlette você pode declarar um *parâmetro de rota* contendo uma *rota* usando uma URL como: + +``` +/files/{file_path:path} +``` + +Nesse caso, o nome do parâmetro é `file_path`, e a última parte, `:path`, diz que o parâmetro deveria coincidir com qualquer *rota*. + +Então, você poderia usar ele com: + +```Python hl_lines="6" +{!../../../docs_src/path_params/tutorial004.py!} +``` + +!!! dica + Você poderia precisar que o parâmetro contivesse `/home/johndoe/myfile.txt`, com uma barra no inicio (`/`). + + Neste caso, a URL deveria ser: `/files//home/johndoe/myfile.txt`, com barra dupla (`//`) entre `files` e `home`. + + +## Recapitulando + +Com o **FastAPI**, usando as declarações de tipo do Python, você obtém: + +* Suporte no editor: verificação de erros, e opção de autocompletar, etc. +* Parsing de dados +* "Parsing" de dados +* Validação de dados +* Anotação da API e documentação automática + +Você apenas tem que declará-los uma vez. + +Essa é provavelmente a vantagem mais visível do **FastAPI** se comparado com frameworks alternativos (além do desempenho puro). diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 63c524d84..567d21cc0 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -59,6 +59,7 @@ nav: - Tutorial - Guia de Usuário: - tutorial/index.md - tutorial/first-steps.md + - tutorial/path-params.md - tutorial/body-fields.md - Segurança: - tutorial/security/index.md From d8b0a9dc6e08d55623d4f84a0ed268e5b3ad05c9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 12:19:45 +0000 Subject: [PATCH 228/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a2bace259..849303bbf 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/tutorial/path-params.md`. PR [#3664](https://github.com/tiangolo/fastapi/pull/3664) by [@FelipeSilva93](https://github.com/FelipeSilva93). * 🌐 Add Portuguese translation for `docs/deployment/https.md`. PR [#3754](https://github.com/tiangolo/fastapi/pull/3754) by [@lsglucas](https://github.com/lsglucas). * ✨ Update GitHub Action: notify-translations, to avoid a race conditon. PR [#3989](https://github.com/tiangolo/fastapi/pull/3989) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade development `autoflake`, supporting multi-line imports. PR [#3988](https://github.com/tiangolo/fastapi/pull/3988) by [@tiangolo](https://github.com/tiangolo). From 00ac07f65c4dd8fa9fa3a78ed6b81d9aa190e521 Mon Sep 17 00:00:00 2001 From: Ruidy Date: Tue, 5 Oct 2021 14:27:24 +0200 Subject: [PATCH 229/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20`deployment/docker.md`=20(#3694)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sam Courtemanche Co-authored-by: Sebastián Ramírez --- docs/fr/docs/deployment/docker.md | 182 ++++++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 2 + 2 files changed, 184 insertions(+) create mode 100644 docs/fr/docs/deployment/docker.md diff --git a/docs/fr/docs/deployment/docker.md b/docs/fr/docs/deployment/docker.md new file mode 100644 index 000000000..e4b59afbf --- /dev/null +++ b/docs/fr/docs/deployment/docker.md @@ -0,0 +1,182 @@ +# Déployer avec Docker + +Dans cette section, vous verrez des instructions et des liens vers des guides pour savoir comment : + +* Faire de votre application **FastAPI** une image/conteneur Docker avec une performance maximale. En environ **5 min**. +* (Optionnellement) comprendre ce que vous, en tant que développeur, devez savoir sur HTTPS. +* Configurer un cluster en mode Docker Swarm avec HTTPS automatique, même sur un simple serveur à 5 dollars US/mois. En environ **20 min**. +* Générer et déployer une application **FastAPI** complète, en utilisant votre cluster Docker Swarm, avec HTTPS, etc. En environ **10 min**. + +Vous pouvez utiliser **Docker** pour le déploiement. Il présente plusieurs avantages comme la sécurité, la réplicabilité, la simplicité de développement, etc. + +Si vous utilisez Docker, vous pouvez utiliser l'image Docker officielle : + +## tiangolo/uvicorn-gunicorn-fastapi + +Cette image est dotée d'un mécanisme d'"auto-tuning", de sorte qu'il vous suffit d'ajouter votre code pour obtenir automatiquement des performances très élevées. Et sans faire de sacrifices. + +Mais vous pouvez toujours changer et mettre à jour toutes les configurations avec des variables d'environnement ou des fichiers de configuration. + +!!! tip "Astuce" + Pour voir toutes les configurations et options, rendez-vous sur la page de l'image Docker : tiangolo/uvicorn-gunicorn-fastapi. + +## Créer un `Dockerfile` + +* Allez dans le répertoire de votre projet. +* Créez un `Dockerfile` avec : + +```Dockerfile +FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 + +COPY ./app /app +``` + +### Applications plus larges + +Si vous avez suivi la section sur la création d' [Applications avec plusieurs fichiers](../tutorial/bigger-applications.md){.internal-link target=_blank}, votre `Dockerfile` pourrait ressembler à ceci : + +```Dockerfile +FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 + +COPY ./app /app/app +``` + +### Raspberry Pi et autres architectures + +Si vous utilisez Docker sur un Raspberry Pi (qui a un processeur ARM) ou toute autre architecture, vous pouvez créer un `Dockerfile` à partir de zéro, basé sur une image de base Python (qui est multi-architecture) et utiliser Uvicorn seul. + +Dans ce cas, votre `Dockerfile` pourrait ressembler à ceci : + +```Dockerfile +FROM python:3.7 + +RUN pip install fastapi uvicorn + +EXPOSE 80 + +COPY ./app /app + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] +``` + +## Créer le code **FastAPI**. + +* Créer un répertoire `app` et y entrer. +* Créez un fichier `main.py` avec : + +```Python +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +* Vous devriez maintenant avoir une structure de répertoire telle que : + +``` +. +├── app +│ └── main.py +└── Dockerfile +``` + +## Construire l'image Docker + +* Allez dans le répertoire du projet (dans lequel se trouve votre `Dockerfile`, contenant votre répertoire `app`). +* Construisez votre image FastAPI : + +
+ +```console +$ docker build -t myimage . + +---> 100% +``` + +
+ +## Démarrer le conteneur Docker + +* Exécutez un conteneur basé sur votre image : + +
+ +```console +$ docker run -d --name mycontainer -p 80:80 myimage +``` + +
+ +Vous disposez maintenant d'un serveur FastAPI optimisé dans un conteneur Docker. Configuré automatiquement pour votre +serveur actuel (et le nombre de cœurs du CPU). + +## Vérifier + +Vous devriez pouvoir accéder à votre application via l'URL de votre conteneur Docker, par exemple : http://192.168.99.100/items/5?q=somequery ou http://127.0.0.1/items/5?q=somequery (ou équivalent, en utilisant votre hôte Docker). + +Vous verrez quelque chose comme : + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +## Documentation interactive de l'API + +Vous pouvez maintenant visiter http://192.168.99.100/docs ou http://127.0.0.1/docs (ou équivalent, en utilisant votre hôte Docker). + +Vous verrez la documentation interactive automatique de l'API (fournie par Swagger UI) : + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +## Documentation de l'API alternative + +Et vous pouvez également aller sur http://192.168.99.100/redoc ou http://127.0.0.1/redoc (ou équivalent, en utilisant votre hôte Docker). + +Vous verrez la documentation automatique alternative (fournie par ReDoc) : + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Traefik + +Traefik est un reverse proxy/load balancer +haute performance. Il peut faire office de "Proxy de terminaison TLS" (entre autres fonctionnalités). + +Il est intégré à Let's Encrypt. Ainsi, il peut gérer toutes les parties HTTPS, y compris l'acquisition et le renouvellement des certificats. + +Il est également intégré à Docker. Ainsi, vous pouvez déclarer vos domaines dans les configurations de chaque application et faire en sorte qu'elles lisent ces configurations, génèrent les certificats HTTPS et servent via HTTPS à votre application automatiquement, sans nécessiter aucune modification de leurs configurations. + +--- + +Avec ces informations et ces outils, passez à la section suivante pour tout combiner. + +## Cluster en mode Docker Swarm avec Traefik et HTTPS + +Vous pouvez avoir un cluster en mode Docker Swarm configuré en quelques minutes (environ 20 min) avec un processus Traefik principal gérant HTTPS (y compris l'acquisition et le renouvellement des certificats). + +En utilisant le mode Docker Swarm, vous pouvez commencer par un "cluster" d'une seule machine (il peut même s'agir +d'un serveur à 5 USD/mois) et ensuite vous pouvez vous développer autant que vous le souhaitez en ajoutant d'autres serveurs. + +Pour configurer un cluster en mode Docker Swarm avec Traefik et la gestion de HTTPS, suivez ce guide : + +### Docker Swarm Mode et Traefik pour un cluster HTTPS + +### Déployer une application FastAPI + +La façon la plus simple de tout mettre en place, serait d'utiliser les [**Générateurs de projet FastAPI**](../project-generation.md){.internal-link target=_blank}. + +Le génerateur de projet adéquat est conçu pour être intégré à ce cluster Docker Swarm avec Traefik et HTTPS décrit ci-dessus. + +Vous pouvez générer un projet en 2 min environ. + +Le projet généré a des instructions pour le déployer et le faire prend 2 min de plus. diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 4891a29ca..c1fb0f23d 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -60,6 +60,8 @@ nav: - Tutoriel - Guide utilisateur: - tutorial/background-tasks.md - async.md +- Déploiement: + - deployment/docker.md - project-generation.md - alternatives.md - external-links.md From 68c43eb12677edf8b2863216f710d6f1d44031f7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 12:28:05 +0000 Subject: [PATCH 230/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 849303bbf..9564600a3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for `deployment/docker.md`. PR [#3694](https://github.com/tiangolo/fastapi/pull/3694) by [@rjNemo](https://github.com/rjNemo). * 🌐 Add Portuguese translation for `docs/tutorial/path-params.md`. PR [#3664](https://github.com/tiangolo/fastapi/pull/3664) by [@FelipeSilva93](https://github.com/FelipeSilva93). * 🌐 Add Portuguese translation for `docs/deployment/https.md`. PR [#3754](https://github.com/tiangolo/fastapi/pull/3754) by [@lsglucas](https://github.com/lsglucas). * ✨ Update GitHub Action: notify-translations, to avoid a race conditon. PR [#3989](https://github.com/tiangolo/fastapi/pull/3989) by [@tiangolo](https://github.com/tiangolo). From 0eb27ab4d033ef409aa359cfba8c8552e05b9eb6 Mon Sep 17 00:00:00 2001 From: Sam Courtemanche Date: Tue, 5 Oct 2021 14:30:41 +0200 Subject: [PATCH 231/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20`docs/tutorial/body.md`=20(#3671)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/fr/docs/tutorial/body.md | 165 ++++++++++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 166 insertions(+) create mode 100644 docs/fr/docs/tutorial/body.md diff --git a/docs/fr/docs/tutorial/body.md b/docs/fr/docs/tutorial/body.md new file mode 100644 index 000000000..c0953f49f --- /dev/null +++ b/docs/fr/docs/tutorial/body.md @@ -0,0 +1,165 @@ +# Corps de la requête + +Quand vous avez besoin d'envoyer de la donnée depuis un client (comme un navigateur) vers votre API, vous l'envoyez en tant que **corps de requête**. + +Le corps d'une **requête** est de la donnée envoyée par le client à votre API. Le corps d'une **réponse** est la donnée envoyée par votre API au client. + +Votre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un corps de **requête**. + +Pour déclarer un corps de **requête**, on utilise les modèles de Pydantic en profitant de tous leurs avantages et fonctionnalités. + +!!! info + Pour envoyer de la donnée, vous devriez utiliser : `POST` (le plus populaire), `PUT`, `DELETE` ou `PATCH`. + + Envoyer un corps dans une requête `GET` a un comportement non défini dans les spécifications, cela est néanmoins supporté par **FastAPI**, seulement pour des cas d'utilisation très complexes/extrêmes. + + Ceci étant découragé, la documentation interactive générée par Swagger UI ne montrera pas de documentation pour le corps d'une requête `GET`, et les proxys intermédiaires risquent de ne pas le supporter. + +## Importez le `BaseModel` de Pydantic + +Commencez par importer la classe `BaseModel` du module `pydantic` : + +```Python hl_lines="4" +{!../../../docs_src/body/tutorial001.py!} +``` + +## Créez votre modèle de données + +Déclarez ensuite votre modèle de données en tant que classe qui hérite de `BaseModel`. + +Utilisez les types Python standard pour tous les attributs : + +```Python hl_lines="7-11" +{!../../../docs_src/body/tutorial001.py!} +``` + +Tout comme pour la déclaration de paramètres de requête, quand un attribut de modèle a une valeur par défaut, il n'est pas nécessaire. Sinon, cet attribut doit être renseigné dans le corps de la requête. Pour rendre ce champ optionnel simplement, utilisez `None` comme valeur par défaut. + +Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) tel que : + +```JSON +{ + "name": "Foo", + "description": "An optional description", + "price": 45.2, + "tax": 3.5 +} +``` + +...`description` et `tax` étant des attributs optionnels (avec `None` comme valeur par défaut), cet "objet" JSON serait aussi valide : + +```JSON +{ + "name": "Foo", + "price": 45.2 +} +``` + +## Déclarez-le comme paramètre + +Pour l'ajouter à votre *opération de chemin*, déclarez-le comme vous déclareriez des paramètres de chemin ou de requête : + +```Python hl_lines="18" +{!../../../docs_src/body/tutorial001.py!} +``` + +...et déclarez que son type est le modèle que vous avez créé : `Item`. + +## Résultats + +En utilisant uniquement les déclarations de type Python, **FastAPI** réussit à : + +* Lire le contenu de la requête en tant que JSON. +* Convertir les types correspondants (si nécessaire). +* Valider la donnée. + * Si la donnée est invalide, une erreur propre et claire sera renvoyée, indiquant exactement où était la donnée incorrecte. +* Passer la donnée reçue dans le paramètre `item`. + * Ce paramètre ayant été déclaré dans la fonction comme étant de type `Item`, vous aurez aussi tout le support offert par l'éditeur (auto-complétion, etc.) pour tous les attributs de ce paramètre et les types de ces attributs. +* Générer des définitions JSON Schema pour votre modèle, qui peuvent être utilisées où vous en avez besoin dans votre projet ensuite. +* Ces schémas participeront à la constitution du schéma généré OpenAPI, et seront donc utilisés par les documentations automatiquement générées. + +## Documentation automatique + +Les schémas JSON de vos modèles seront intégrés au schéma OpenAPI global de votre application, et seront donc affichés dans la documentation interactive de l'API : + + + +Et seront aussi utilisés dans chaque *opération de chemin* de la documentation utilisant ces modèles : + + + +## Support de l'éditeur + +Dans votre éditeur, vous aurez des annotations de types et de l'auto-complétion partout dans votre fonction (ce qui n'aurait pas été le cas si vous aviez utilisé un classique `dict` plutôt qu'un modèle Pydantic) : + + + +Et vous obtenez aussi de la vérification d'erreur pour les opérations incorrectes de types : + + + +Ce n'est pas un hasard, ce framework entier a été bati avec ce design comme objectif. + +Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour s'assurer que cela fonctionnerait avec tous les éditeurs. + +Des changements sur Pydantic ont même été faits pour supporter cela. + +Les captures d'écrans précédentes ont été prises sur Visual Studio Code. + +Mais vous auriez le même support de l'éditeur avec PyCharm et la majorité des autres éditeurs de code Python. + + + +!!! tip "Astuce" + Si vous utilisez PyCharm comme éditeur, vous pouvez utiliser le Plugin PyCharm. + + Ce qui améliore le support pour les modèles Pydantic avec : + + * de l'auto-complétion + * des vérifications de type + * du "refactoring" (ou remaniement de code) + * de la recherche + * de l'inspection + +## Utilisez le modèle + +Dans la fonction, vous pouvez accéder à tous les attributs de l'objet du modèle directement : + +```Python hl_lines="21" +{!../../../docs_src/body/tutorial002.py!} +``` + +## Corps de la requête + paramètres de chemin + +Vous pouvez déclarer des paramètres de chemin et un corps de requête pour la même *opération de chemin*. + +**FastAPI** est capable de reconnaître que les paramètres de la fonction qui correspondent aux paramètres de chemin doivent être **récupérés depuis le chemin**, et que les paramètres de fonctions déclarés comme modèles Pydantic devraient être **récupérés depuis le corps de la requête**. + +```Python hl_lines="17-18" +{!../../../docs_src/body/tutorial003.py!} +``` + +## Corps de la requête + paramètres de chemin et de requête + +Vous pouvez aussi déclarer un **corps**, et des paramètres de **chemin** et de **requête** dans la même *opération de chemin*. + +**FastAPI** saura reconnaître chacun d'entre eux et récupérer la bonne donnée au bon endroit. + +```Python hl_lines="18" +{!../../../docs_src/body/tutorial004.py!} +``` + +Les paramètres de la fonction seront reconnus comme tel : + +* Si le paramètre est aussi déclaré dans le **chemin**, il sera utilisé comme paramètre de chemin. +* Si le paramètre est d'un **type singulier** (comme `int`, `float`, `str`, `bool`, etc.), il sera interprété comme un paramètre de **requête**. +* Si le paramètre est déclaré comme ayant pour type un **modèle Pydantic**, il sera interprété comme faisant partie du **corps** de la requête. + +!!! note + **FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `=None`. + + Le type `Optional` dans `Optional[str]` n'est pas utilisé par **FastAPI**, mais sera utile à votre éditeur pour améliorer le support offert par ce dernier et détecter plus facilement des erreurs de type. + +## Sans Pydantic + +Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Corps**. Pour cela, allez voir la partie de la documentation sur [Corps de la requête - Paramètres multiples](body-multiple-params.md){.internal-link target=_blank}. \ No newline at end of file diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index c1fb0f23d..018c2bd30 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -58,6 +58,7 @@ nav: - fastapi-people.md - python-types.md - Tutoriel - Guide utilisateur: + - tutorial/body.md - tutorial/background-tasks.md - async.md - Déploiement: From bc99d2b7b82764eeb0c74da4b89f7d0c8e2590b1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 12:31:22 +0000 Subject: [PATCH 232/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9564600a3..553fe0be6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for `docs/tutorial/body.md`. PR [#3671](https://github.com/tiangolo/fastapi/pull/3671) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for `deployment/docker.md`. PR [#3694](https://github.com/tiangolo/fastapi/pull/3694) by [@rjNemo](https://github.com/rjNemo). * 🌐 Add Portuguese translation for `docs/tutorial/path-params.md`. PR [#3664](https://github.com/tiangolo/fastapi/pull/3664) by [@FelipeSilva93](https://github.com/FelipeSilva93). * 🌐 Add Portuguese translation for `docs/deployment/https.md`. PR [#3754](https://github.com/tiangolo/fastapi/pull/3754) by [@lsglucas](https://github.com/lsglucas). From 5fbf597cd5599fd0f578476129e1f861b8223f49 Mon Sep 17 00:00:00 2001 From: Yagiz Degirmenci <62724709+ycd@users.noreply.github.com> Date: Tue, 5 Oct 2021 15:46:11 +0300 Subject: [PATCH 233/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Turkish=20translat?= =?UTF-8?q?ion=20for=20`docs/index.md`=20(#1908)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/tr/docs/index.md | 310 ++++++++++++++++++++++-------------------- 1 file changed, 159 insertions(+), 151 deletions(-) diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md index 282e2b603..88660f7eb 100644 --- a/docs/tr/docs/index.md +++ b/docs/tr/docs/index.md @@ -6,7 +6,7 @@ FastAPI

- FastAPI framework, high performance, easy to learn, fast to code, ready for production + FastAPI framework, yüksek performanslı, öğrenmesi kolay, geliştirmesi hızlı, kullanıma sunulmaya hazır.

@@ -22,27 +22,27 @@ --- -**Documentation**: https://fastapi.tiangolo.com +**dokümantasyon**: https://fastapi.tiangolo.com -**Source Code**: https://github.com/tiangolo/fastapi +**Kaynak kodu**: https://github.com/tiangolo/fastapi --- -FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. +FastAPI, Python 3.6+'nın standart type hintlerine dayanan modern ve hızlı (yüksek performanslı) API'lar oluşturmak için kullanılabilecek web framework'ü. -The key features are: +Ana özellikleri: -* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). +* **Hızlı**: çok yüksek performanslı, **NodeJS** ve **Go** ile eşdeğer seviyede performans sağlıyor, (Starlette ve Pydantic sayesinde.) [Python'un en hızlı frameworklerinden bir tanesi.](#performans). +* **Kodlaması hızlı**: Yeni özellikler geliştirmek neredeyse %200 - %300 daha hızlı. * +* **Daha az bug**: Geliştirici (insan) kaynaklı hatalar neredeyse %40 azaltıldı. * +* **Sezgileri güçlü**: Editor (otomatik-tamamlama) desteği harika. Otomatik tamamlama her yerde. Debuglamak ile daha az zaman harcayacaksınız. +* **Kolay**: Öğrenmesi ve kullanması kolay olacak şekilde. Doküman okumak için harcayacağınız süre azaltıldı. +* **Kısa**: Kod tekrarını minimuma indirdik. Fonksiyon parametrelerinin tiplerini belirtmede farklı yollar sunarak karşılaşacağınız bug'ları azalttık. +* **Güçlü**: Otomatik dokümantasyon ile beraber, kullanıma hazır kod yaz. -* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * -* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * -* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. -* **Easy**: Designed to be easy to use and learn. Less time reading docs. -* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. -* **Robust**: Get production-ready code. With automatic interactive documentation. -* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. +* **Standartlar belirli**: Tamamiyle API'ların açık standartlara bağlı ve (tam uyumlululuk içerisinde); OpenAPI (eski adıyla Swagger) ve JSON Schema. -* estimation based on tests on an internal development team, building production applications. +* Bahsi geçen rakamsal ifadeler tamamiyle, geliştirme takımının kendi sundukları ürünü geliştirirken yaptıkları testlere dayanmakta. ## Sponsors @@ -61,64 +61,72 @@ The key features are: Other sponsors -## Opinions +## Görüşler -"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" + +"_[...] Bugünlerde **FastAPI**'ı çok fazla kullanıyorum [...] Aslına bakarsanız **Microsoft'taki Machine Learning servislerimizin** hepsinde kullanmayı düşünüyorum. FastAPI ile geliştirdiğimiz servislerin bazıları çoktan **Windows**'un ana ürünlerine ve **Office** ürünlerine entegre edilmeye başlandı bile._"

Kabir Khan - Microsoft (ref)
--- -"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" + +"_**FastAPI**'ı **tahminlerimiz**'i sorgulanabilir hale getirmek için **REST** mimarisı ile beraber server üzerinde kullanmaya başladık._" +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
--- -"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" + +"_**Netflix** **kriz yönetiminde** orkestrasyon yapabilmek için geliştirdiği yeni framework'ü **Dispatch**'in, açık kaynak versiyonunu paylaşmaktan gurur duyuyor. [**FastAPI** ile yapıldı.]_"
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
--- -"_I’m over the moon excited about **FastAPI**. It’s so fun!_" + +"_**FastAPI** için ayın üzerindeymişcesine heyecanlıyım. Çok eğlenceli!_" +
Brian Okken - Python Bytes podcast host (ref)
--- -"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" +"_Dürüst olmak gerekirse, geliştirdiğin şey bir çok açıdan çok sağlam ve parlak gözüküyor. Açıkcası benim **Hug**'ı tasarlarken yapmaya çalıştığım şey buydu - bunu birisinin başardığını görmek gerçekten çok ilham verici._" -
Timothy Crosley - Hug creator (ref)
+
Timothy Crosley - Hug'ın Yaratıcısı (ref)
--- -"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" +"_Eğer REST API geliştirmek için **modern bir framework** öğrenme arayışında isen, **FastAPI**'a bir göz at [...] Hızlı, kullanımı ve öğrenmesi kolay. [...]_" -"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" +"_Biz **API** servislerimizi **FastAPI**'a geçirdik [...] Sizin de beğeneceğinizi düşünüyoruz. [...]_" -
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ + +
Ines Montani - Matthew Honnibal - Explosion AI kurucuları - spaCy yaratıcıları (ref) - (ref)
--- -## **Typer**, the FastAPI of CLIs +## **Typer**, komut satırı uygulamalarının FastAPI'ı -If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. +Eğer API yerine komut satırı uygulaması geliştiriyor isen **Typer**'a bir göz at. -**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 +**Typer** kısaca FastAPI'ın küçük kız kardeşi. Komut satırı uygulamalarının **FastAPI'ı** olması hedeflendi. ⌨️ 🚀 -## Requirements +## Gereksinimler Python 3.6+ -FastAPI stands on the shoulders of giants: +FastAPI iki devin omuzları üstünde duruyor: -* Starlette for the web parts. -* Pydantic for the data parts. +* Web tarafı için Starlette. +* Data tarafı için Pydantic. -## Installation +## Yükleme
@@ -130,7 +138,7 @@ $ pip install fastapi
-You will also need an ASGI server, for production such as Uvicorn or Hypercorn. +Uygulamanı kullanılabilir hale getirmek için Uvicorn ya da Hypercorn gibi bir ASGI serverına ihtiyacın olacak.
@@ -142,11 +150,11 @@ $ pip install uvicorn[standard]
-## Example +## Örnek -### Create it +### Şimdi dene -* Create a file `main.py` with: +* `main.py` adında bir dosya oluştur : ```Python from typing import Optional @@ -167,9 +175,9 @@ def read_item(item_id: int, q: Optional[str] = None): ```
-Or use async def... +Ya da async def... -If your code uses `async` / `await`, use `async def`: +Eğer kodunda `async` / `await` var ise, `async def` kullan: ```Python hl_lines="9 14" from typing import Optional @@ -189,15 +197,15 @@ async def read_item(item_id: int, q: Optional[str] = None): return {"item_id": item_id, "q": q} ``` -**Note**: +**Not**: -If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. +Eğer ne olduğunu bilmiyor isen _"Acelen mi var?"_ kısmını oku `async` ve `await`.
-### Run it +### Çalıştır -Run the server with: +Serverı aşağıdaki komut ile çalıştır:
@@ -214,54 +222,54 @@ INFO: Application startup complete.
-About the command uvicorn main:app --reload... +Çalıştırdığımız uvicorn main:app --reload hakkında... -The command `uvicorn main:app` refers to: +`uvicorn main:app` şunları ifade ediyor: -* `main`: the file `main.py` (the Python "module"). -* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. -* `--reload`: make the server restart after code changes. Only do this for development. +* `main`: dosya olan `main.py` (yani Python "modülü"). +* `app`: ise `main.py` dosyasının içerisinde oluşturduğumuz `app = FastAPI()` 'a denk geliyor. +* `--reload`: ise kodda herhangi bir değişiklik yaptığımızda serverın yapılan değişiklerileri algılayıp, değişiklikleri siz herhangi bir şey yapmadan uygulamasını sağlıyor.
-### Check it +### Dokümantasyonu kontrol et -Open your browser at http://127.0.0.1:8000/items/5?q=somequery. +Browserını aç ve şu linke git http://127.0.0.1:8000/items/5?q=somequery. -You will see the JSON response as: +Bir JSON yanıtı göreceksin: ```JSON {"item_id": 5, "q": "somequery"} ``` -You already created an API that: +Az önce oluşturduğun API: -* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. -* Both _paths_ take `GET` operations (also known as HTTP _methods_). -* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. -* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. +* `/` ve `/items/{item_id}` adreslerine HTTP talebi alabilir hale geldi. +* İki _adresde_ `GET` operasyonlarını (HTTP _metodları_ olarakta bilinen) yapabilir hale geldi. +* `/items/{item_id}` _adresi_ ayrıca bir `item_id` _adres parametresine_ sahip ve bu bir `int` olmak zorunda. +* `/items/{item_id}` _adresi_ opsiyonel bir `str` _sorgu paramtersine_ sahip bu da `q`. -### Interactive API docs +### İnteraktif API dokümantasyonu -Now go to http://127.0.0.1:8000/docs. +Şimdi http://127.0.0.1:8000/docs adresine git. -You will see the automatic interactive API documentation (provided by Swagger UI): +Senin için otomatik oluşturulmuş(Swagger UI tarafından sağlanan) interaktif bir API dokümanı göreceksin: ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -### Alternative API docs +### Alternatif API dokümantasyonu -And now, go to http://127.0.0.1:8000/redoc. +Şimdi http://127.0.0.1:8000/redoc adresine git. -You will see the alternative automatic documentation (provided by ReDoc): +Senin için alternatif olarak (ReDoc tarafından sağlanan) bir API dokümantasyonu daha göreceksin: ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## Example upgrade +## Örnek bir değişiklik -Now modify the file `main.py` to receive a body from a `PUT` request. +Şimdi `main.py` dosyasını değiştirelim ve body ile `PUT` talebi alabilir hale getirelim. -Declare the body using standard Python types, thanks to Pydantic. +Şimdi Pydantic sayesinde, Python'un standart tiplerini kullanarak bir body tanımlayacağız. ```Python hl_lines="4 9 10 11 12 25 26 27" from typing import Optional @@ -293,175 +301,175 @@ def update_item(item_id: int, item: Item): return {"item_name": item.name, "item_id": item_id} ``` -The server should reload automatically (because you added `--reload` to the `uvicorn` command above). +Server otomatik olarak yeniden başlamalı (çünkü yukarıda `uvicorn`'u çalıştırırken `--reload` parametresini kullandık.). -### Interactive API docs upgrade +### İnteraktif API dokümantasyonu'nda değiştirme yapmak -Now go to http://127.0.0.1:8000/docs. +Şimdi http://127.0.0.1:8000/docs bağlantısına tekrar git. -* The interactive API documentation will be automatically updated, including the new body: +* İnteraktif API dokümantasyonu, yeni body ile beraber çoktan yenilenmiş olması lazım: ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) -* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: +* "Try it out"a tıkla, bu senin API parametleri üzerinde deneme yapabilmene izin veriyor: ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) -* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: +* Şimdi "Execute" butonuna tıkla, kullanıcı arayüzü otomatik olarak API'ın ile bağlantı kurarak ona bu parametreleri gönderecek ve sonucu karşına getirecek. ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) -### Alternative API docs upgrade +### Alternatif API dokümantasyonunda değiştirmek -And now, go to http://127.0.0.1:8000/redoc. +Şimdi ise http://127.0.0.1:8000/redoc adresine git. -* The alternative documentation will also reflect the new query parameter and body: +* Alternatif dokümantasyonda koddaki değişimler ile beraber kendini yeni query ve body ile güncelledi. ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) -### Recap +### Özet -In summary, you declare **once** the types of parameters, body, etc. as function parameters. +Özetleyecek olursak, URL, sorgu veya request body'deki parametrelerini fonksiyon parametresi olarak kullanıyorsun. Bu parametrelerin veri tiplerini bir kere belirtmen yeterli. -You do that with standard modern Python types. +Type-hinting işlemini Python dilindeki standart veri tipleri ile yapabilirsin -You don't have to learn a new syntax, the methods or classes of a specific library, etc. +Yeni bir syntax'e alışmana gerek yok, metodlar ve classlar zaten spesifik kütüphanelere ait. -Just standard **Python 3.6+**. +Sadece standart **Python 3.6+**. -For example, for an `int`: +Örnek olarak, `int` tanımlamak için: ```Python item_id: int ``` -or for a more complex `Item` model: +ya da daha kompleks `Item` tipi: ```Python item: Item ``` -...and with that single declaration you get: +...sadece kısa bir parametre tipi belirtmekle beraber, sahip olacakların: -* Editor support, including: - * Completion. - * Type checks. -* Validation of data: - * Automatic and clear errors when the data is invalid. - * Validation even for deeply nested JSON objects. -* Conversion of input data: coming from the network to Python data and types. Reading from: +* Editör desteği dahil olmak üzere: + * Otomatik tamamlama. + * Tip sorguları. +* Datanın tipe uyumunun sorgulanması: + * Eğer data geçersiz ise, otomatik olarak hataları ayıklar. + * Çok derin JSON objelerinde bile veri tipi sorgusu yapar. +* Gelen verinin dönüşümünü aşağıdaki veri tiplerini kullanarak gerçekleştirebiliyor. * JSON. - * Path parameters. - * Query parameters. + * Path parametreleri. + * Query parametreleri. * Cookies. * Headers. * Forms. * Files. -* Conversion of output data: converting from Python data and types to network data (as JSON): - * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). - * `datetime` objects. - * `UUID` objects. - * Database models. - * ...and many more. -* Automatic interactive API documentation, including 2 alternative user interfaces: +* Giden verinin dönüşümünü aşağıdaki veri tiplerini kullanarak gerçekleştirebiliyor (JSON olarak): + * Python tiplerinin (`str`, `int`, `float`, `bool`, `list`, vs) çevirisi. + * `datetime` objesi. + * `UUID` objesi. + * Veritabanı modelleri. + * ve daha fazlası... +* 2 alternatif kullanıcı arayüzü dahil olmak üzere, otomatik interaktif API dokümanu: * Swagger UI. * ReDoc. --- -Coming back to the previous code example, **FastAPI** will: +Az önceki kod örneğine geri dönelim, **FastAPI**'ın yapacaklarına bir bakış atalım: -* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. -* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. - * If it is not, the client will see a useful, clear error. -* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. - * As the `q` parameter is declared with `= None`, it is optional. - * Without the `None` it would be required (as is the body in the case with `PUT`). -* For `PUT` requests to `/items/{item_id}`, Read the body as JSON: - * Check that it has a required attribute `name` that should be a `str`. - * Check that it has a required attribute `price` that has to be a `float`. - * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. - * All this would also work for deeply nested JSON objects. -* Convert from and to JSON automatically. -* Document everything with OpenAPI, that can be used by: - * Interactive documentation systems. - * Automatic client code generation systems, for many languages. -* Provide 2 interactive documentation web interfaces directly. +* `item_id`'nin `GET` ve `PUT` talepleri içinde olup olmadığının doğruluğunu kontol edecek. +* `item_id`'nin tipinin `int` olduğunu `GET` ve `PUT` talepleri içinde olup olmadığının doğruluğunu kontol edecek. + * Eğer `GET` ve `PUT` içinde yok ise ve `int` değil ise, sebebini belirten bir hata mesajı gösterecek +* Opsiyonel bir `q` parametresinin `GET` talebi için (`http://127.0.0.1:8000/items/foo?q=somequery` içinde) olup olmadığını kontrol edecek + * `q` parametresini `= None` ile oluşturduğumuz için, opsiyonel bir parametre olacak. + * Eğer `None` olmasa zorunlu bir parametre olacak idi (bu yüzden body'de `PUT` parametresi var). +* `PUT` talebi için `/items/{item_id}`'nin body'sini, JSON olarak okuyor: + * `name` adında bir parametetre olup olmadığını ve var ise onun `str` olup olmadığını kontol ediyor. + * `price` adında bir parametetre olup olmadığını ve var ise onun `float` olup olmadığını kontol ediyor. + * `is_offer` adında bir parametetre olup olmadığını ve var ise onun `bool` olup olmadığını kontol ediyor. + * Bunların hepsini en derin JSON modellerinde bile yapacaktır. +* Bütün veri tiplerini otomatik olarak JSON'a çeviriyor veya tam tersi. +* Her şeyi dokümanlayıp, çeşitli yerlerde: + * İnteraktif dokümantasyon sistemleri. + * Otomatik alıcı kodu üretim sistemlerinde ve çeşitli dillerde. +* İki ayrı web arayüzüyle direkt olarak interaktif bir dokümantasyon sunuyor. --- -We just scratched the surface, but you already get the idea of how it all works. +Henüz yüzeysel bir bakış attık, fakat sen çoktan çalışma mantığını anladın. -Try changing the line with: +Şimdi aşağıdaki satırı değiştirmeyi dene: ```Python return {"item_name": item.name, "item_id": item_id} ``` -...from: +...bundan: ```Python ... "item_name": item.name ... ``` -...to: +...buna: ```Python ... "item_price": item.price ... ``` -...and see how your editor will auto-complete the attributes and know their types: +...şimdi editör desteğinin nasıl veri tiplerini bildiğini ve otomatik tamamladığını gör: ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) -For a more complete example including more features, see the Tutorial - User Guide. +Daha fazla örnek ve özellik için Tutorial - User Guide sayfasını git. -**Spoiler alert**: the tutorial - user guide includes: +**Spoiler**: Öğretici - Kullanıcı rehberi şunları içeriyor: -* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. -* How to set **validation constraints** as `maximum_length` or `regex`. -* A very powerful and easy to use **Dependency Injection** system. -* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. -* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). -* Many extra features (thanks to Starlette) as: +* **Parameterlerini** nasıl **headers**, **cookies**, **form fields** ve **files** olarak deklare edebileceğini. +* `maximum_length` ya da `regex` gibi şeylerle nasıl **doğrulama** yapabileceğini. +* Çok güçlü ve kullanımı kolay **Zorunluluk Entegrasyonu** oluşturmayı. +* Güvenlik ve kimlik doğrulama, **JWT tokenleri**'yle beraber **OAuth2** desteği, ve **HTTP Basic** doğrulaması. +* İleri seviye fakat ona göre oldukça basit olan **derince oluşturulmuş JSON modelleri** (Pydantic sayesinde). +* Diğer ekstra özellikler (Starlette sayesinde): * **WebSockets** * **GraphQL** - * extremely easy tests based on `requests` and `pytest` + * `requests` ve `pytest` sayesinde aşırı kolay testler. * **CORS** * **Cookie Sessions** - * ...and more. + * ...ve daha fazlası. -## Performance +## Performans -Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) +Bağımsız TechEmpower kıyaslamaları gösteriyor ki, Uvicorn'la beraber çalışan **FastAPI** uygulamaları Python'un en hızlı frameworklerinden birisi , sadece Starlette ve Uvicorn'dan daha yavaş ki FastAPI bunların üzerine kurulu. -To understand more about it, see the section Benchmarks. +Daha fazla bilgi için, bu bölüme bir göz at Benchmarks. -## Optional Dependencies +## Opsiyonel gereksinimler -Used by Pydantic: +Pydantic tarafında kullanılan: -* ujson - for faster JSON "parsing". -* email_validator - for email validation. +* ujson - daha hızlı JSON "dönüşümü" için. +* email_validator - email doğrulaması için. -Used by Starlette: +Starlette tarafında kullanılan: -* requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. -* jinja2 - Required if you want to use the default template configuration. -* python-multipart - Required if you want to support form "parsing", with `request.form()`. -* itsdangerous - Required for `SessionMiddleware` support. -* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). -* graphene - Required for `GraphQLApp` support. -* ujson - Required if you want to use `UJSONResponse`. +* requests - Eğer `TestClient` kullanmak istiyorsan gerekli. +* aiofiles - `FileResponse` ya da `StaticFiles` kullanmak istiyorsan gerekli. +* jinja2 - Eğer kendine ait template konfigürasyonu oluşturmak istiyorsan gerekli +* python-multipart - Form kullanmak istiyorsan gerekli ("dönüşümü"). +* itsdangerous - `SessionMiddleware` desteği için gerekli. +* pyyaml - `SchemaGenerator` desteği için gerekli (Muhtemelen FastAPI kullanırken ihtiyacınız olmaz). +* graphene - `GraphQLApp` desteği için gerekli. +* ujson - `UJSONResponse` kullanmak istiyorsan gerekli. -Used by FastAPI / Starlette: +Hem FastAPI hem de Starlette tarafından kullanılan: -* uvicorn - for the server that loads and serves your application. -* orjson - Required if you want to use `ORJSONResponse`. +* uvicorn - oluşturduğumuz uygulamayı bir web sunucusuna servis etmek için gerekli +* orjson - `ORJSONResponse` kullanmak istiyor isen gerekli. -You can install all of these with `pip install fastapi[all]`. +Bunların hepsini `pip install fastapi[all]` ile yükleyebilirsin. -## License +## Lisans -This project is licensed under the terms of the MIT license. +Bu proje, MIT lisansı şartlarına göre lisanslanmıştır. From c6461ad7dc9d37646a74ff0154cd202922b5e91e Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 12:46:49 +0000 Subject: [PATCH 234/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 553fe0be6..0b1cf1abd 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Turkish translation for `docs/index.md`. PR [#1908](https://github.com/tiangolo/fastapi/pull/1908) by [@ycd](https://github.com/ycd). * 🌐 Add French translation for `docs/tutorial/body.md`. PR [#3671](https://github.com/tiangolo/fastapi/pull/3671) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for `deployment/docker.md`. PR [#3694](https://github.com/tiangolo/fastapi/pull/3694) by [@rjNemo](https://github.com/rjNemo). * 🌐 Add Portuguese translation for `docs/tutorial/path-params.md`. PR [#3664](https://github.com/tiangolo/fastapi/pull/3664) by [@FelipeSilva93](https://github.com/FelipeSilva93). From 507e9baf9eb4d5164bea4eb4173c3cabeefc3149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Emre=20Arma=C4=9Fan?= Date: Tue, 5 Oct 2021 15:50:38 +0300 Subject: [PATCH 235/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Turkish=20translat?= =?UTF-8?q?ion=20for=20`docs/benchmarks.md`=20(#2729)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/tr/docs/benchmarks.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 docs/tr/docs/benchmarks.md diff --git a/docs/tr/docs/benchmarks.md b/docs/tr/docs/benchmarks.md new file mode 100644 index 000000000..1ce3c758f --- /dev/null +++ b/docs/tr/docs/benchmarks.md @@ -0,0 +1,34 @@ +# Kıyaslamalar + +Bağımsız TechEmpower kıyaslamaları gösteriyor ki Uvicorn'la beraber çalışan **FastAPI** uygulamaları Python'un en hızlı frameworklerinden birisi , sadece Starlette ve Uvicorn'dan daha düşük sıralamada (FastAPI bu frameworklerin üzerine kurulu). (*) + +Fakat kıyaslamaları ve karşılaştırmaları incelerken şunları aklınızda bulundurmalısınız. + +## Kıyaslamalar ve hız + +Kıyaslamaları incelediğinizde, farklı özelliklere sahip birçok araçların eşdeğer olarak karşılaştırıldığını görmek yaygındır. + +Özellikle, Uvicorn, Starlette ve FastAPI'ın birlikte karşılaştırıldığını görmek için (diğer birçok araç arasında). + +Araç tarafından çözülen sorun ne kadar basitse, o kadar iyi performans alacaktır. Ve kıyaslamaların çoğu, araç tarafından sağlanan ek özellikleri test etmez. + +Hiyerarşi şöyledir: + +* **Uvicorn**: bir ASGI sunucusu + * **Starlette**: (Uvicorn'u kullanır) bir web microframeworkü + * **FastAPI**: (Starlette'i kullanır) data validation vb. ile API'lar oluşturmak için çeşitli ek özelliklere sahip bir API frameworkü + +* **Uvicorn**: + * Sunucunun kendisi dışında ekstra bir kod içermediği için en iyi performansa sahip olacaktır + * Direkt olarak Uvicorn'da bir uygulama yazmazsınız. Bu, en azından Starlette tarafından sağlanan tüm kodu (veya **FastAPI**) az çok içermesi gerektiği anlamına gelir. Ve eğer bunu yaptıysanız, son uygulamanız bir framework kullanmak ve uygulama kodlarını ve bugları en aza indirmekle aynı ek yüke sahip olacaktır. + * Eğer Uvicorn'u karşılaştırıyorsanız, Daphne, Hypercorn, uWSGI, vb. uygulama sunucuları ile karşılaştırın. +* **Starlette**: + * Uvicorn'dan sonraki en iyi performansa sahip olacak. Aslında, Starlette çalışmak için Uvicorn'u kullanıyor. Dolayısıyla, muhtemelen daha fazla kod çalıştırmak zorunda kaldığında Uvicorn'dan sadece "daha yavaş" olabilir. + * Ancak routing based on paths ile vb. basit web uygulamaları oluşturmak için araçlar sağlar. + * Eğer Starlette'i karşılaştırıyorsanız, Sanic, Flask, Django, vb. frameworkler (veya microframeworkler) ile karşılaştırın. +* **FastAPI**: + * Starlette'in Uvicorn'u kullandığı ve ondan daha hızlı olamayacağı gibi, **FastAPI** da Starlette'i kullanır, bu yüzden ondan daha hızlı olamaz. + * FastAPI, Starlette'e ek olarak daha fazla özellik sunar. Data validation ve serialization gibi API'lar oluştururken neredeyse ve her zaman ihtiyaç duyduğunuz özellikler. Ve bunu kullanarak, ücretsiz olarak otomatik dokümantasyon elde edersiniz (otomatik dokümantasyon çalışan uygulamalara ek yük getirmez, başlangıçta oluşturulur). + * FastAPI'ı kullanmadıysanız ve Starlette'i doğrudan kullandıysanız (veya başka bir araç, Sanic, Flask, Responder, vb.) tüm data validation'ı ve serialization'ı kendiniz sağlamanız gerekir. Dolayısıyla, son uygulamanız FastAPI kullanılarak oluşturulmuş gibi hâlâ aynı ek yüke sahip olacaktır. Çoğu durumda, uygulamalarda yazılan kodun büyük çoğunluğunu data validation ve serialization oluşturur. + * Dolayısıyla, FastAPI'ı kullanarak geliştirme süresinden, buglardan, kod satırlarından tasarruf edersiniz ve muhtemelen kullanmasaydınız aynı performansı (veya daha iyisini) elde edersiniz. (hepsini kodunuza uygulamak zorunda kalacağınız gibi) + * Eğer FastAPI'ı karşılaştırıyorsanız, Flask-apispec, NestJS, Molten, vb. gibi data validation, serialization ve dokümantasyon sağlayan bir web uygulaması frameworkü ile (veya araç setiyle) karşılaştırın. Entegre otomatik data validation, serialization ve dokümantasyon içeren frameworkler. From 85f0d2b924389faaf5b0a533d407738481803a51 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 12:51:14 +0000 Subject: [PATCH 236/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0b1cf1abd..435d54c2d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Turkish translation for `docs/benchmarks.md`. PR [#2729](https://github.com/tiangolo/fastapi/pull/2729) by [@Telomeraz](https://github.com/Telomeraz). * 🌐 Add Turkish translation for `docs/index.md`. PR [#1908](https://github.com/tiangolo/fastapi/pull/1908) by [@ycd](https://github.com/ycd). * 🌐 Add French translation for `docs/tutorial/body.md`. PR [#3671](https://github.com/tiangolo/fastapi/pull/3671) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for `deployment/docker.md`. PR [#3694](https://github.com/tiangolo/fastapi/pull/3694) by [@rjNemo](https://github.com/rjNemo). From 63744b2e8a14e07faa64e6442b0ea6d3298101a6 Mon Sep 17 00:00:00 2001 From: Yagiz Degirmenci <62724709+ycd@users.noreply.github.com> Date: Tue, 5 Oct 2021 16:01:50 +0300 Subject: [PATCH 237/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Turkish=20translat?= =?UTF-8?q?ion=20for=20`docs/features.md`=20(#1950)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/tr/docs/features.md | 209 +++++++++++++++++++++++++++++++++++++++ docs/tr/mkdocs.yml | 1 + 2 files changed, 210 insertions(+) create mode 100644 docs/tr/docs/features.md diff --git a/docs/tr/docs/features.md b/docs/tr/docs/features.md new file mode 100644 index 000000000..c06c27c16 --- /dev/null +++ b/docs/tr/docs/features.md @@ -0,0 +1,209 @@ +# Özelikler + +## FastAPI özellikleri + +**FastAPI** sana bunları sağlıyor + +### Açık standartları temel alır + +* API oluşturma işlemlerinde OpenAPI buna path operasyonları parametreleri, body talebi, güvenlik gibi şeyler dahil olmak üzere deklare bunların deklare edilmesi. +* Otomatik olarak data modelinin JSON Schema ile beraber dokümante edilmesi (OpenAPI'n kendisi zaten JSON Schema'ya dayanıyor). +* Titiz bir çalışmanın sonucunda yukarıdaki standartlara uygun bir framework oluşturduk. Standartları pastanın üzerine sonradan eklenmiş bir çilek olarak görmedik. +* Ayrıca bu bir çok dilde kullanılabilecek **client code generator** kullanımına da izin veriyor. + +### Otomatik dokümantasyon + + +OpenAPI standartlarına dayalı olan bir framework olarak, geliştiricilerin birden çok seçeneği var, varsayılan olarak gelen 2 farklı interaktif API dokümantasyonu ve web kullanıcı arayüzü var. + + +* Swagger UI interaktif olarak API'ınızı tarayıcı üzerinden çağırıp test edebilmenize olanak sağlıyor. + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* ReDoc ile beraber alternatif API dokümantasyonu. + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Sadece modern Python + +Tamamiyle standartlar **Python 3.6**'nın type hintlerine dayanıyor (Pydantic'in sayesinde). Yeni bir syntax öğrenmene gerek yok. Sadece modern Python. + + +Eğer Python type hintlerini bilmiyorsan veya bir hatırlatmaya ihtiyacın var ise(FastAPI kullanmasan bile) şu iki dakikalık küçük bilgilendirici içeriğe bir göz at: [Python Types](python-types.md){.internal-link target=_blank}. + +Standart Python'u typelarını belirterek yazıyorsun: + +```Python +from typing import List, Dict +from datetime import date + +from pydantic import BaseModel + +# Değişkeni str olarak belirt +# ve o fonksiyon için harika bir editör desteği al +def main(user_id: str): + return user_id + + +# Pydantic modeli +class User(BaseModel): + id: int + name: str + joined: date +``` + +Sonrasında bu şekilde kullanabilirsin + +```Python +my_user: User = User(id=3, name="John Doe", joined="2018-07-19") + +second_user_data = { + "id": 4, + "name": "Mary", + "joined": "2018-11-30", +} + +my_second_user: User = User(**second_user_data) +``` + +!!! info + `**second_user_data` şu anlama geliyor: + + Key-Value çiftini direkt olarak `second_user_data` dictionarysine kaydet , yaptığın şey buna eşit olacak: `User(id=4, name="Mary", joined="2018-11-30")` + +### Editor desteği + +Bütün framework kullanılması kolay ve sezgileri güçlü olması için tasarlandı, verilen bütün kararlar geliştiricilere en iyi geliştirme deneyimini yaşatmak üzere, bir çok editör üzerinde test edildi. + +Son yapılan Python geliştiricileri anketinde, açık ara en çok kullanılan özellik "oto-tamamlama" idi.. + +Bütün **FastAPI** frameworkü oto-tamamlama açısından geliştiriciyi tatmin etmek üzerine tasarlandı. Otomatik tamamlama her yerde çalışıyor. + +Dokümantasyona tekrardan çok nadir olarak geleceksin. + +Editörün sana nasıl yardım ettiğine bir bak: + +* Visual Studio Code ile: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +* PyCharm ile: + +![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png) + + +Daha önceden düşünüp en imkansız diyebileceğin durumlarda bile otomatik tamamlama alacaksın, örnek olarak `price` JSON body içerisinde (nested bir JSON body de olabilirdi.) direkt olarak istekten geliyor, bu durumda bile oto-tammalama sağlıyor. + +Artık key isimlerini yanlış yazma, dokümantasyona dönüp deliler gibi yukarı aşağı sayfada gezmek ve en sonunda `username` mi yoksa `user_name` mi kullandım gibi sorular yok. + +### Kısa + +Her şey için mantıklı bir **varsayılanı** var. Parametrelerini opsiyonel olarak tanımlayıp API'nı istediğin gibi modifiye edebilirsin. + +Hepsi varsayılan olarak **çalışıyor**. + + +### Doğrulama + +* Neredeyse bütün (ya da hepsi?) Python **data typeları** için doğrulama, kapsadıkları: + * JSON objeleri (`dict`). + * JSON array (`list`) item type'ı belirtirken. + * String (`str`) parametresi, minimum ve maksimum uzunluk gibi sınırlandırmalar yaparken. + * Numaralar (`int`, `float`) maksimum ve minimum gibi sınırlandırmalar yaparken. + +* Bunlar gibi en egzotik typelarla bile doğrulama yapabiliyorsunuz.: + * URL. + * Email. + * UUID. + * ...ve diğerleri. + +Bütün doğrulama olayları çok güçlü bir kütüphane sayesinde yapılıyor, **Pydantic**. + +### Güvenlik ve kimlik doğrulama + +Güvenlik ve doğrulama database ve data modellerinden taviz vermeden entegre edilebilir durumda. + +Bütün güvenlik şemaları OpenAPI'da tanımlanmış durumda, kapsadıkları: + +* HTTP Basic. +* **OAuth2** (ve **JWT tokenleriyle** beraber). Bu öğretici içeriğe göz atabilirsin [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. +* API anahtarları: + * Headerlar. + * Query parametreleri. + * Cookies, vs. + +Bütün güvenlik özellikleri Starlette'den geliyor (**session cookies'de** dahil olmak üzere). + +Bütün hepsi tekrardan kullanılabilir aletler ve bileşenler olarak, kolayca sistemlerinize, data depolarınıza, ilişkisel ve NoSQL databaselerinize entegre edebileceğiniz şekilde yapıldı. + +### Dependency injection + +FastAPI'ın inanılmaz derecede kullanımı kolay, fakat inanılmaz derecede güçlü Dependency Injection sistemi var. + +* Dependencylerin bile dependencies'i olabiliyor, FastAPI bunun için **graph of "dependency"** yaratıyor. +* Hepsi **otomatik olarak** FastAPI tarafından hallediliyor. +* Bütün zorunlulukların gelen datalara bağlı olarak farklı gereksinimleri olabiliyor, ilave path operasyonlarının kısıtlamaları ve otomatik dokümantasyonu da ayrıca yapılıyor . +* Path operasyonu parametreleri içerisinde belirtilen gereksinimler için bile **Otomatik doğrulama** yapılabiliyor. +* Kompleks kimlik doğrulama sistemleri için destek, **database bağlantıları**, vs. +* **Taviz yok** hiçbir şeyden taviz vermeden, database frontend vs. Bütün hepsinin kolayca entegre edilebiliyor. + +### Sınırsız "plug-inler" + +Başka bir deyişle, plug-inlere ihtiyacımız yok, import edip direkt olarak kullanmaya başlayabiliriz. + +Bütün entegrasyonlar kullanımı kolay olmak üzere (zorunluluklar ile beraber) tasarlandı, sen bir "plug-in" yaratıp 2 satır kod ile, *path operasyonlarında* kullandığımız syntax ve aynı yapı ile koduna entregre edebilirsin. + + +### Test edildi + +* 100% test coverage. +* 100% typeları belirtilmiş codebase. +* FastAPI ile yapılan bir çok proje insanlar tarafından kullanılıyor. + +## Starlette özellikleri + +**FastAPI**, Starlette ile tamamiyle uyumlu ve üzerine kurulu. Yani FastAPI üzerine ekleme yapacağınız herhangi bir Starlette kodu da çalışacaktır. + +`FastAPI` aslında `Starlette`'nin bir sub-class'ı. Eğer Starlette'nin nasıl kullanılacağını biliyor isen, çoğu işlevini aynı şekilde yapıyor. + +**FastAPI** ile beraber **Starlette**'nin bütün özelliklerine de sahip olacaksınız (FastAPI aslında Starlette'nin steroid basmış hali): + +* Gerçekten etkileyici bir performansa sahip.Python'un ise en hızlı frameworklerinden bir tanesi, **NodeJS** ve **Go** ile ise eşdeğer performansa sahip.. +* **WebSocket** desteği. +* **GraphQL** desteği. +* Kullanım halinde arka plan işlevleri. +* Başlatma ve kapatma eventleri(startup and shutdown). +* Test sunucusu `requests` üzerine kurulu. +* **CORS**, GZip, Static dosyalar, Streaming responseları. +* **Session and Cookie** desteği. +* 100% test kapsayıcılığı. +* 100% typeları belirtilmiş codebase. + +## Pydantic özellikleri + +**FastAPI** ile Pydantic tamamiyle uyumlu ve üzerine kurulu. Yani FastAPI üzerine ekleme yapacağınız herhangi bir Pydantic kodu da çalışacaktır. + +Bunlara Pydantic üzerine kurulu ORM databaseler ve , ODM kütüphaneler de dahil olmak üzere. + +Bu ayrıca şu anlama da geliyor, bir çok durumda requestten gelen objeyi **direkt olarak database**'e her şeyi otomatik olarak doğrulanmış bir biçimde aktarabilirisin. + +Aynı şekilde, databaseden gelen objeyi de **direkt olarak isteğe** de tamamiyle doğrulanmış bir biçimde gönderebilirsiniz. + +**FastAPI** ile beraber **Pydantic**'in bütün özelliklerine sahip olacaksınız (FastAPI data kontrolünü Pydantic'in üzerine kurduğu için): + +* **Kafa karıştırmaz**: + * Farklı bir syntax öğrenmenize gerek kalmaz, + * Eğer Python typelarını nasıl kullanacağını biliyorsan Pydantic kullanmayı da biliyorsundur. +* Kullandığın geliştirme araçları ile iyi çalışır **IDE/linter/brain**: + * Pydantic'in veri yapıları aslında sadece senin tanımladığın classlar; Bu yüzden doğrulanmış dataların ile otomatik tamamlama, linting ve mypy'ı kullanarak sorunsuz bir şekilde çalışabilirsin +* **Hızlı**: + * Benchmarklarda, Pydantic'in diğer bütün test edilmiş bütün kütüphanelerden daha hızlı. +* **En kompleks** yapıları bile doğrula: + * Hiyerarşik Pydantic modellerinin kullanımı ile beraber, Python `typing`’s `List` and `Dict`, vs gibi şeyleri doğrula. + * Doğrulayıcılar en kompleks data şemalarının bile temiz ve kolay bir şekilde tanımlanmasına izin veriyor, ve hepsi JSON şeması olarak dokümante ediliyor + * Pydantic, JSON objen ne kadar derin (nested) olursa olsun doğrulamasını ve gösterimini yapıyor +* **Genişletilebilir**: + * Pydantic özelleştirilmiş data tiplerinin tanımlanmasının yapılmasına izin veriyor ayrıca validator decoratorü ile senin doğrulamaları genişletip, kendi doğrulayıcılarını yazmana izin veriyor. +* 100% test kapsayıcılığı. + diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 5e429fdef..d4ff63d0c 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -54,6 +54,7 @@ nav: - tr: /tr/ - uk: /uk/ - zh: /zh/ +- features.md markdown_extensions: - toc: permalink: true From 19fd336cde290606e37cfbc059ca15360f2de9bc Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 13:02:28 +0000 Subject: [PATCH 238/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 435d54c2d..16a807dd7 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Turkish translation for `docs/features.md`. PR [#1950](https://github.com/tiangolo/fastapi/pull/1950) by [@ycd](https://github.com/ycd). * 🌐 Add Turkish translation for `docs/benchmarks.md`. PR [#2729](https://github.com/tiangolo/fastapi/pull/2729) by [@Telomeraz](https://github.com/Telomeraz). * 🌐 Add Turkish translation for `docs/index.md`. PR [#1908](https://github.com/tiangolo/fastapi/pull/1908) by [@ycd](https://github.com/ycd). * 🌐 Add French translation for `docs/tutorial/body.md`. PR [#3671](https://github.com/tiangolo/fastapi/pull/3671) by [@Smlep](https://github.com/Smlep). From eb515b1af75d9d1bf7c00a0ca4c994ba346b6978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 5 Oct 2021 15:31:39 +0200 Subject: [PATCH 239/814] =?UTF-8?q?=F0=9F=93=9D=20Re-structure=20release?= =?UTF-8?q?=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 16a807dd7..2cf6f9ea9 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,22 @@ ## Latest Changes + +### Features + +* ⬆Increase supported version of aiofiles to suppress warnings. PR [#2899](https://github.com/tiangolo/fastapi/pull/2899) by [@SnkSynthesis](https://github.com/SnkSynthesis). +* ➖ Do not require backports in Python >= 3.7. PR [#1880](https://github.com/tiangolo/fastapi/pull/1880) by [@FFY00](https://github.com/FFY00). +* ⬆ Upgrade required Python version to >= 3.6.1, needed by typing.Deque, used by Pydantic. PR [#2733](https://github.com/tiangolo/fastapi/pull/2733) by [@hukkin](https://github.com/hukkin). +* ⬆️ Bump Uvicorn max range to 0.15.0. PR [#3345](https://github.com/tiangolo/fastapi/pull/3345) by [@Kludex](https://github.com/Kludex). + +### Docs + +* 📝 Update GraphQL docs, recommend Strawberry. PR [#3981](https://github.com/tiangolo/fastapi/pull/3981) by [@tiangolo](https://github.com/tiangolo). +* 📝 Re-write and extend Deployment guide: Concepts, Uvicorn, Gunicorn, Docker, Containers, Kubernetes. PR [#3974](https://github.com/tiangolo/fastapi/pull/3974) by [@tiangolo](https://github.com/tiangolo). +* 📝 Upgrade HTTPS guide with more explanations and diagrams. PR [#3950](https://github.com/tiangolo/fastapi/pull/3950) by [@tiangolo](https://github.com/tiangolo). + +### Translations + * 🌐 Add Turkish translation for `docs/features.md`. PR [#1950](https://github.com/tiangolo/fastapi/pull/1950) by [@ycd](https://github.com/ycd). * 🌐 Add Turkish translation for `docs/benchmarks.md`. PR [#2729](https://github.com/tiangolo/fastapi/pull/2729) by [@Telomeraz](https://github.com/Telomeraz). * 🌐 Add Turkish translation for `docs/index.md`. PR [#1908](https://github.com/tiangolo/fastapi/pull/1908) by [@ycd](https://github.com/ycd). @@ -9,21 +25,17 @@ * 🌐 Add French translation for `deployment/docker.md`. PR [#3694](https://github.com/tiangolo/fastapi/pull/3694) by [@rjNemo](https://github.com/rjNemo). * 🌐 Add Portuguese translation for `docs/tutorial/path-params.md`. PR [#3664](https://github.com/tiangolo/fastapi/pull/3664) by [@FelipeSilva93](https://github.com/FelipeSilva93). * 🌐 Add Portuguese translation for `docs/deployment/https.md`. PR [#3754](https://github.com/tiangolo/fastapi/pull/3754) by [@lsglucas](https://github.com/lsglucas). -* ✨ Update GitHub Action: notify-translations, to avoid a race conditon. PR [#3989](https://github.com/tiangolo/fastapi/pull/3989) by [@tiangolo](https://github.com/tiangolo). +* 🌐 Add German translation for `docs/features.md`. PR [#3699](https://github.com/tiangolo/fastapi/pull/3699) by [@mawassk](https://github.com/mawassk). + +### Internal + +* ✨ Update GitHub Action: notify-translations, to avoid a race conditions. PR [#3989](https://github.com/tiangolo/fastapi/pull/3989) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade development `autoflake`, supporting multi-line imports. PR [#3988](https://github.com/tiangolo/fastapi/pull/3988) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Increase dependency ranges for tests and docs: pytest-cov, pytest-asyncio, black, httpx, sqlalchemy, databases, mkdocs-markdownextradata-plugin. PR [#3987](https://github.com/tiangolo/fastapi/pull/3987) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#3986](https://github.com/tiangolo/fastapi/pull/3986) by [@github-actions[bot]](https://github.com/apps/github-actions). -* ⬆Increase supported version of aiofiles to suppress warnings. PR [#2899](https://github.com/tiangolo/fastapi/pull/2899) by [@SnkSynthesis](https://github.com/SnkSynthesis). -* ➖ Do not require backports in Python >= 3.7. PR [#1880](https://github.com/tiangolo/fastapi/pull/1880) by [@FFY00](https://github.com/FFY00). -* ⬆ Upgrade required Python version to >= 3.6.1, needed by typing.Deque, used by Pydantic. PR [#2733](https://github.com/tiangolo/fastapi/pull/2733) by [@hukkin](https://github.com/hukkin). -* ⬆ Upgrade internal testing dependencies: mypy to version 0.910, add newly needed type packages. PR [#3350](https://github.com/tiangolo/fastapi/pull/3350) by [@ArcLightSlavik](https://github.com/ArcLightSlavik). -* ⬆️ Bump Uvicorn max range to 0.15.0. PR [#3345](https://github.com/tiangolo/fastapi/pull/3345) by [@Kludex](https://github.com/Kludex). * 💚 Fix badges in README and main page. PR [#3979](https://github.com/tiangolo/fastapi/pull/3979) by [@ghandic](https://github.com/ghandic). -* 📝 Update GraphQL docs, recommend Strawberry. PR [#3981](https://github.com/tiangolo/fastapi/pull/3981) by [@tiangolo](https://github.com/tiangolo). +* ⬆ Upgrade internal testing dependencies: mypy to version 0.910, add newly needed type packages. PR [#3350](https://github.com/tiangolo/fastapi/pull/3350) by [@ArcLightSlavik](https://github.com/ArcLightSlavik). * ✨ Add Deepset Sponsorship. PR [#3976](https://github.com/tiangolo/fastapi/pull/3976) by [@tiangolo](https://github.com/tiangolo). -* 📝 Re-write and extend Deployment guide: Concepts, Uvicorn, Gunicorn, Docker, Containers, Kubernetes. PR [#3974](https://github.com/tiangolo/fastapi/pull/3974) by [@tiangolo](https://github.com/tiangolo). -* 📝 Upgrade HTTPS guide with more explanations and diagrams. PR [#3950](https://github.com/tiangolo/fastapi/pull/3950) by [@tiangolo](https://github.com/tiangolo). -* 🌐 Add German translation for `docs/features.md`. PR [#3699](https://github.com/tiangolo/fastapi/pull/3699) by [@mawassk](https://github.com/mawassk). * 🎨 Tweak CSS styles for shell animations. PR [#3888](https://github.com/tiangolo/fastapi/pull/3888) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add new Sponsor Calmcode.io. PR [#3777](https://github.com/tiangolo/fastapi/pull/3777) by [@tiangolo](https://github.com/tiangolo). From 378fa4ef755a0f814cd61daf571466fde3af9b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 5 Oct 2021 15:32:18 +0200 Subject: [PATCH 240/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.68?= =?UTF-8?q?.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 7 +++++++ fastapi/__init__.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2cf6f9ea9..56bb42bdc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,13 @@ ## Latest Changes +## 0.68.2 + +This release has **no breaking changes**. 🎉 + +It upgrades the version ranges of sub-dependencies to allow applications using FastAPI to easily upgrade them. + +Soon there will be a new FastAPI release upgrading Starlette to take advantage of recent improvements, but as that has a higher chance of having breaking changes, it will be in a separate release. ### Features diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 316362669..ba2b9abf4 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.68.1" +__version__ = "0.68.2" from starlette import status as status From 2210c84efd16668e9561fd448f80abe6249b27da Mon Sep 17 00:00:00 2001 From: bilal alpaslan <47563997+BilalAlpaslan@users.noreply.github.com> Date: Tue, 5 Oct 2021 18:47:51 +0300 Subject: [PATCH 241/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Turkish=20translat?= =?UTF-8?q?ion=20for=20`docs/fastapi-people.md`=20(#3848)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/tr/docs/fastapi-people.md | 178 +++++++++++++++++++++++++++++++++ docs/tr/mkdocs.yml | 1 + 2 files changed, 179 insertions(+) create mode 100644 docs/tr/docs/fastapi-people.md diff --git a/docs/tr/docs/fastapi-people.md b/docs/tr/docs/fastapi-people.md new file mode 100644 index 000000000..3e459036a --- /dev/null +++ b/docs/tr/docs/fastapi-people.md @@ -0,0 +1,178 @@ +# FastAPI Topluluğu + +FastAPI, her kökenden insanı ağırlayan harika bir topluluğa sahip. + +## Yazan - Geliştiren + +Hey! 👋 + +İşte bu benim: + +{% if people %} +
+{% for user in people.maintainers %} + +
@{{ user.login }}
Answers: {{ user.answers }}
Pull Requests: {{ user.prs }}
+{% endfor %} + +
+{% endif %} + +Ben **FastAPI** 'nin yazarı ve geliştiricisiyim. Bununla ilgili daha fazla bilgiyi şurada okuyabilirsiniz: + [FastAPI yardım - yardım al - Yazar ile iletişime geç](help-fastapi.md#connect-with-the-author){.internal-link target=_blank}. + +... Burada size harika FastAPI topluluğunu göstermek istiyorum. + +--- + +**FastAPI** topluluğundan destek alıyor. Ve katkıda bulunanları vurgulamak istiyorum. + +İşte o mükemmel insanlar: + +* [GitHubdaki sorunları (issues) çözmelerinde diğerlerine yardım et](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}. +* [Pull Requests oluşturun](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}. +* Pull Requests 'leri gözden geçirin, [özelliklede çevirileri](contributing.md#translations){.internal-link target=_blank}. + +Onlara bir alkış. 👏 🙇 + +## Geçen ayın en aktif kullanıcıları + +Bunlar geçen ay boyunca [GitHub' da başkalarına sorunlarında (issues) en çok yardımcı olan ](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} kullanıcılar ☕ + +{% if people %} +
+{% for user in people.last_month_active %} + +
@{{ user.login }}
Issues replied: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +## Uzmanlar + +İşte **FastAPI Uzmanları**. 🤓 + +Bunlar *tüm zamanlar boyunca* [GitHub' da başkalarına sorunlarında (issues) en çok yardımcı olan](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} kullanıcılar. + +Başkalarına yardım ederek uzman olduklarını kanıtladılar. ✨ + +{% if people %} +
+{% for user in people.experts %} + +
@{{ user.login }}
Issues replied: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +## En fazla katkıda bulunanlar + +işte **En fazla katkıda bulunanlar**. 👷 + +Bu kullanıcılar en çok [Pull Requests oluşturan](help-fastapi.md#create-a-pull-request){.internal-link target=_blank} ve onu kaynak koduna *birleştirenler*. + +Kaynak koduna, belgelere, çevirilere vb. katkıda bulundular. 📦 + +{% if people %} +
+{% for user in people.top_contributors %} + +
@{{ user.login }}
Pull Requests: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +Çok fazla katkıda bulunan var (binden fazla), hepsini şurda görebilirsin: FastAPI GitHub Katkıda Bulunanlar. 👷 + +## En fazla inceleme yapanlar + +İşte **En fazla inceleme yapanlar**. 🕵️ + +### Çeviri için İncelemeler + +Yalnızca birkaç dil konuşabiliyorum (ve çok da iyi değilim 😅). Bu yüzden döküman çevirilerini [**onaylama yetkisi**](contributing.md#translations){.internal-link target=_blank} siz inceleyenlere aittir. Sizler olmadan diğer birkaç dilde dokümantasyon olmazdı. + +--- + +**En fazla inceleme yapanlar** 🕵️ kodun, belgelerin ve özellikle **çevirilerin** kalitesini sağlamak için diğerlerinden daha fazla pull requests incelemiştir. + +{% if people %} +
+{% for user in people.top_reviewers %} + +
@{{ user.login }}
Reviews: {{ user.count }}
+{% endfor %} + +
+{% endif %} + +## Sponsorlar + +işte **Sponsorlarımız**. 😎 + +**FastAPI** ve diğer projelerde çalışmamı destekliyorlar, özellikle de GitHub Sponsorları. + +### Altın Sponsorlar + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor %} +{% endif %} + +### Gümüş Sponsorlar + +{% if sponsors %} +{% for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + +### Bronz Sponsorlar + +{% if sponsors %} +{% for sponsor in sponsors.bronze -%} + +{% endfor %} +{% endif %} + +### Bireysel Sponsorlar + +{% if people %} +{% if people.sponsors_50 %} + +
+{% for user in people.sponsors_50 %} + + +{% endfor %} + +
+ +{% endif %} +{% endif %} + +{% if people %} +
+{% for user in people.sponsors %} + + +{% endfor %} + +
+{% endif %} + +## Veriler hakkında - Teknik detaylar + +Bu sayfanın temel amacı, topluluğun başkalarına yardım etme çabasını vurgulamaktır. + +Özellikle normalde daha az görünür olan ve çoğu durumda daha zahmetli olan, diğerlerine sorunlar konusunda yardımcı olmak ve pull requests'leri gözden geçirmek gibi çabalar dahil. + +Veriler ayda bir hesaplanır, işte kaynak kodu okuyabilirsin :source code here. + +Burada sponsorların katkılarını da tekrardan vurgulamak isterim. + +Ayrıca algoritmayı, bölümleri, eşikleri vb. güncelleme hakkımı da saklı tutarım (her ihtimale karşı 🤷). diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index d4ff63d0c..f29366679 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -55,6 +55,7 @@ nav: - uk: /uk/ - zh: /zh/ - features.md +- fastapi-people.md markdown_extensions: - toc: permalink: true From 67d5ba1efd0e4f588c6c411cac6299fc4b364ce2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 15:53:54 +0000 Subject: [PATCH 242/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 56bb42bdc..030b04b7e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Turkish translation for `docs/fastapi-people.md`. PR [#3848](https://github.com/tiangolo/fastapi/pull/3848) by [@BilalAlpaslan](https://github.com/BilalAlpaslan). ## 0.68.2 This release has **no breaking changes**. 🎉 From cc0d0f3899d94d3e964fd8a1bc8aced83c79e8ef Mon Sep 17 00:00:00 2001 From: Madat Bay <46858323+madatbay@users.noreply.github.com> Date: Tue, 5 Oct 2021 20:07:25 +0400 Subject: [PATCH 243/814] =?UTF-8?q?=F0=9F=8C=90=20Initialize=20Azerbaijani?= =?UTF-8?q?=20translations=20(#3941)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/az/mkdocs.yml | 128 +++++++++++++++++++++++++++++++++++ docs/az/overrides/.gitignore | 0 docs/de/mkdocs.yml | 3 + docs/en/mkdocs.yml | 6 +- docs/es/mkdocs.yml | 3 + docs/fr/mkdocs.yml | 3 + docs/id/mkdocs.yml | 3 + docs/it/mkdocs.yml | 3 + docs/ja/mkdocs.yml | 3 + docs/ko/mkdocs.yml | 3 + docs/pl/mkdocs.yml | 3 + docs/pt/mkdocs.yml | 3 + docs/ru/mkdocs.yml | 3 + docs/sq/mkdocs.yml | 3 + docs/tr/mkdocs.yml | 3 + docs/uk/mkdocs.yml | 3 + docs/zh/mkdocs.yml | 3 + 17 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 docs/az/mkdocs.yml create mode 100644 docs/az/overrides/.gitignore diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml new file mode 100644 index 000000000..edeb6c2e3 --- /dev/null +++ b/docs/az/mkdocs.yml @@ -0,0 +1,128 @@ +site_name: FastAPI +site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production +site_url: https://fastapi.tiangolo.com/az/ +theme: + name: material + custom_dir: overrides + palette: + - scheme: default + primary: teal + accent: amber + toggle: + icon: material/lightbulb-outline + name: Switch to light mode + - scheme: slate + primary: teal + accent: amber + toggle: + icon: material/lightbulb + name: Switch to dark mode + features: + - search.suggest + - search.highlight + - content.tabs.link + icon: + repo: fontawesome/brands/github-alt + logo: https://fastapi.tiangolo.com/img/icon-white.svg + favicon: https://fastapi.tiangolo.com/img/favicon.png + language: en +repo_name: tiangolo/fastapi +repo_url: https://github.com/tiangolo/fastapi +edit_uri: '' +google_analytics: +- UA-133183413-1 +- auto +plugins: +- search +- markdownextradata: + data: data +nav: +- FastAPI: index.md +- Languages: + - en: / + - az: /az/ + - de: /de/ + - es: /es/ + - fr: /fr/ + - id: /id/ + - it: /it/ + - ja: /ja/ + - ko: /ko/ + - pl: /pl/ + - pt: /pt/ + - ru: /ru/ + - sq: /sq/ + - tr: /tr/ + - uk: /uk/ + - zh: /zh/ +markdown_extensions: +- toc: + permalink: true +- markdown.extensions.codehilite: + guess_lang: false +- mdx_include: + base_path: docs +- admonition +- codehilite +- extra +- pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format '' +- pymdownx.tabbed +extra: + social: + - icon: fontawesome/brands/github-alt + link: https://github.com/tiangolo/fastapi + - icon: fontawesome/brands/discord + link: https://discord.gg/VQjSZaeJmf + - icon: fontawesome/brands/twitter + link: https://twitter.com/fastapi + - icon: fontawesome/brands/linkedin + link: https://www.linkedin.com/in/tiangolo + - icon: fontawesome/brands/dev + link: https://dev.to/tiangolo + - icon: fontawesome/brands/medium + link: https://medium.com/@tiangolo + - icon: fontawesome/solid/globe + link: https://tiangolo.com + alternate: + - link: / + name: en - English + - link: /az/ + name: az + - link: /de/ + name: de + - link: /es/ + name: es - español + - link: /fr/ + name: fr - français + - link: /id/ + name: id + - link: /it/ + name: it - italiano + - link: /ja/ + name: ja - 日本語 + - link: /ko/ + name: ko - 한국어 + - link: /pl/ + name: pl + - link: /pt/ + name: pt - português + - link: /ru/ + name: ru - русский язык + - link: /sq/ + name: sq - shqip + - link: /tr/ + name: tr - Türkçe + - link: /uk/ + name: uk - українська мова + - link: /zh/ + name: zh - 汉语 +extra_css: +- https://fastapi.tiangolo.com/css/termynal.css +- https://fastapi.tiangolo.com/css/custom.css +extra_javascript: +- https://fastapi.tiangolo.com/js/termynal.js +- https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/az/overrides/.gitignore b/docs/az/overrides/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 77882db03..bcd521c80 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -90,6 +91,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index b32468783..28a688a96 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -165,9 +166,6 @@ markdown_extensions: permalink: true - markdown.extensions.codehilite: guess_lang: false -# Uncomment these 2 lines during development to more easily add highlights -# - pymdownx.highlight: -# linenums: true - mdx_include: base_path: docs - admonition @@ -198,6 +196,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 3c0c65c87..35127ac27 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -99,6 +100,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 018c2bd30..4cd0750c9 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -101,6 +102,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index 88028533e..31488ee33 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -89,6 +90,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index 477f9c55a..10e6198f2 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -89,6 +90,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 2617fec96..37f6548d8 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -129,6 +130,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 6ee22afba..bb66c8987 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -95,6 +96,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 379957783..0775048e9 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -89,6 +90,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 567d21cc0..3e5fece58 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -108,6 +109,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 359cce8eb..eee98a9bc 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -89,6 +90,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index 53019fea5..1d2adbb7d 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -89,6 +90,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index f29366679..d78947fa7 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -91,6 +92,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index 4d8636bd6..41aec880c 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -89,6 +90,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 713919934..3f27884e4 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -40,6 +40,7 @@ nav: - FastAPI: index.md - Languages: - en: / + - az: /az/ - de: /de/ - es: /es/ - fr: /fr/ @@ -139,6 +140,8 @@ extra: alternate: - link: / name: en - English + - link: /az/ + name: az - link: /de/ name: de - link: /es/ From ac0f594305a059a30b8c0c29c48ee79df95d5e4e Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 16:08:13 +0000 Subject: [PATCH 244/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 030b04b7e..1fc165d5d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Initialize Azerbaijani translations. PR [#3941](https://github.com/tiangolo/fastapi/pull/3941) by [@madatbay](https://github.com/madatbay). * 🌐 Add Turkish translation for `docs/fastapi-people.md`. PR [#3848](https://github.com/tiangolo/fastapi/pull/3848) by [@BilalAlpaslan](https://github.com/BilalAlpaslan). ## 0.68.2 From cce8d9e32cb7efcd6fcdb361f1e407d7ec2cdb76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 5 Oct 2021 18:09:45 +0200 Subject: [PATCH 245/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20GitHub=20Action=20?= =?UTF-8?q?notify-translations=20config=20for=20Azerbaijani=20(#3995)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/notify-translations/app/translations.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/notify-translations/app/translations.yml b/.github/actions/notify-translations/app/translations.yml index 3f53adb65..decd63498 100644 --- a/.github/actions/notify-translations/app/translations.yml +++ b/.github/actions/notify-translations/app/translations.yml @@ -12,3 +12,4 @@ sq: 2041 pl: 3169 de: 3716 id: 3717 +az: 3994 From 292b8c8ce96b04dba358ae3d53a5eea2a9c04127 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 5 Oct 2021 16:10:28 +0000 Subject: [PATCH 246/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1fc165d5d..b9c9b9e90 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add GitHub Action notify-translations config for Azerbaijani. PR [#3995](https://github.com/tiangolo/fastapi/pull/3995) by [@tiangolo](https://github.com/tiangolo). * 🌐 Initialize Azerbaijani translations. PR [#3941](https://github.com/tiangolo/fastapi/pull/3941) by [@madatbay](https://github.com/madatbay). * 🌐 Add Turkish translation for `docs/fastapi-people.md`. PR [#3848](https://github.com/tiangolo/fastapi/pull/3848) by [@BilalAlpaslan](https://github.com/BilalAlpaslan). ## 0.68.2 From eb1d68c789d320dc3edcb2d8d1e462e9244df874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 6 Oct 2021 17:08:57 +0200 Subject: [PATCH 247/814] =?UTF-8?q?=F0=9F=94=A7=20Lint=20only=20in=20Pytho?= =?UTF-8?q?n=203.7=20and=20above=20(#4006)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test.yml | 3 +++ scripts/test.sh | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 02507a9d0..7ab0f1230 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,6 +32,9 @@ jobs: - name: Install Dependencies if: steps.cache.outputs.cache-hit != 'true' run: flit install --symlink + - name: Lint + if: ${{ matrix.python-version != '3.6' }} + run: bash scripts/lint.sh - name: Test run: bash scripts/test.sh - name: Upload coverage diff --git a/scripts/test.sh b/scripts/test.sh index 74ed7a1f1..d445ca174 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -3,7 +3,6 @@ set -e set -x -bash ./scripts/lint.sh # Check README.md is up to date python ./scripts/docs.py verify-readme export PYTHONPATH=./docs_src From 4d26fa5c546f68ddb67bd3e6c194c644323aadaa Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 6 Oct 2021 15:09:36 +0000 Subject: [PATCH 248/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b9c9b9e90..868059224 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Lint only in Python 3.7 and above. PR [#4006](https://github.com/tiangolo/fastapi/pull/4006) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add GitHub Action notify-translations config for Azerbaijani. PR [#3995](https://github.com/tiangolo/fastapi/pull/3995) by [@tiangolo](https://github.com/tiangolo). * 🌐 Initialize Azerbaijani translations. PR [#3941](https://github.com/tiangolo/fastapi/pull/3941) by [@madatbay](https://github.com/madatbay). * 🌐 Add Turkish translation for `docs/fastapi-people.md`. PR [#3848](https://github.com/tiangolo/fastapi/pull/3848) by [@BilalAlpaslan](https://github.com/BilalAlpaslan). From 11d0a08acda2f4bbc21ca1c5df92b34d8758c842 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Wed, 6 Oct 2021 16:32:11 +0100 Subject: [PATCH 249/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20Trio?= =?UTF-8?q?=20via=20AnyIO=20(#3372)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- README.md | 1 - docs/en/docs/advanced/async-tests.md | 20 ++------ docs/en/docs/advanced/extending-openapi.md | 15 ------ docs/en/docs/advanced/templates.md | 12 ----- docs/en/docs/index.md | 1 - .../dependencies/dependencies-with-yield.md | 9 ---- docs/en/docs/tutorial/sql-databases.md | 11 ----- docs/en/docs/tutorial/static-files.md | 14 ------ docs_src/async_tests/test_main.py | 2 +- fastapi/concurrency.py | 45 ++++++------------ fastapi/dependencies/utils.py | 46 ++++++------------- pyproject.toml | 16 +++---- tests/test_fakeasync.py | 12 ----- .../test_async_tests/test_main.py | 2 +- .../test_websockets/test_tutorial002.py | 10 +++- 15 files changed, 49 insertions(+), 167 deletions(-) delete mode 100644 tests/test_fakeasync.py diff --git a/README.md b/README.md index 3055e670d..d376fb74e 100644 --- a/README.md +++ b/README.md @@ -442,7 +442,6 @@ Used by Pydantic: Used by Starlette: * requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. diff --git a/docs/en/docs/advanced/async-tests.md b/docs/en/docs/advanced/async-tests.md index 921bdb708..d5116233f 100644 --- a/docs/en/docs/advanced/async-tests.md +++ b/docs/en/docs/advanced/async-tests.md @@ -6,21 +6,9 @@ Being able to use asynchronous functions in your tests could be useful, for exam Let's look at how we can make that work. -## pytest-asyncio +## pytest.mark.anyio -If we want to call asynchronous functions in our tests, our test functions have to be asynchronous. Pytest provides a neat library for this, called `pytest-asyncio`, that allows us to specify that some test functions are to be called asynchronously. - -You can install it via: - -
- -```console -$ pip install pytest-asyncio - ----> 100% -``` - -
+If we want to call asynchronous functions in our tests, our test functions have to be asynchronous. Anyio provides a neat plugin for this, that allows us to specify that some test functions are to be called asynchronously. ## HTTPX @@ -66,7 +54,7 @@ $ pytest ## In Detail -The marker `@pytest.mark.asyncio` tells pytest that this test function should be called asynchronously: +The marker `@pytest.mark.anyio` tells pytest that this test function should be called asynchronously: ```Python hl_lines="7" {!../../../docs_src/async_tests/test_main.py!} @@ -97,4 +85,4 @@ that we used to make our requests with the `TestClient`. As the testing function is now asynchronous, you can now also call (and `await`) other `async` functions apart from sending requests to your FastAPI application in your tests, exactly as you would call them anywhere else in your code. !!! tip - If you encounter a `RuntimeError: Task attached to a different loop` when integrating asynchronous function calls in your tests (e.g. when using MongoDB's MotorClient) check out this issue in the pytest-asyncio repository. + If you encounter a `RuntimeError: Task attached to a different loop` when integrating asynchronous function calls in your tests (e.g. when using MongoDB's MotorClient) Remember to instantiate objects that need an event loop only within async functions, e.g. an `'@app.on_event("startup")` callback. diff --git a/docs/en/docs/advanced/extending-openapi.md b/docs/en/docs/advanced/extending-openapi.md index 9179126df..d8d280ba6 100644 --- a/docs/en/docs/advanced/extending-openapi.md +++ b/docs/en/docs/advanced/extending-openapi.md @@ -152,21 +152,6 @@ After that, your file structure could look like: └── swagger-ui.css ``` -### Install `aiofiles` - -Now you need to install `aiofiles`: - - -
- -```console -$ pip install aiofiles - ----> 100% -``` - -
- ### Serve the static files * Import `StaticFiles`. diff --git a/docs/en/docs/advanced/templates.md b/docs/en/docs/advanced/templates.md index a8e2575c1..45e6a20fc 100644 --- a/docs/en/docs/advanced/templates.md +++ b/docs/en/docs/advanced/templates.md @@ -20,18 +20,6 @@ $ pip install jinja2
-If you need to also serve static files (as in this example), install `aiofiles`: - -
- -```console -$ pip install aiofiles - ----> 100% -``` - -
- ## Using `Jinja2Templates` * Import `Jinja2Templates`. diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index 998564bb3..cc6982b79 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -443,7 +443,6 @@ Used by Pydantic: Used by Starlette: * requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. diff --git a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md index 3388a0828..82553afae 100644 --- a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md @@ -7,15 +7,6 @@ To do this, use `yield` instead of `return`, and write the extra steps after. !!! tip Make sure to use `yield` one single time. -!!! info - For this to work, you need to use **Python 3.7** or above, or in **Python 3.6**, install the "backports": - - ``` - pip install async-exit-stack async-generator - ``` - - This installs async-exit-stack and async-generator. - !!! note "Technical Details" Any function that is valid to use with: diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md index c623fad29..e8ebb29c8 100644 --- a/docs/en/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -441,17 +441,6 @@ You can find an example of Alembic in a FastAPI project in the templates from [P ### Create a dependency -!!! info - For this to work, you need to use **Python 3.7** or above, or in **Python 3.6**, install the "backports": - - ```console - $ pip install async-exit-stack async-generator - ``` - - This installs async-exit-stack and async-generator. - - You can also use the alternative method with a "middleware" explained at the end. - Now use the `SessionLocal` class we created in the `sql_app/databases.py` file to create a dependency. We need to have an independent database session/connection (`SessionLocal`) per request, use the same session through all the request and then close it after the request is finished. diff --git a/docs/en/docs/tutorial/static-files.md b/docs/en/docs/tutorial/static-files.md index c103bd940..7a0c36af3 100644 --- a/docs/en/docs/tutorial/static-files.md +++ b/docs/en/docs/tutorial/static-files.md @@ -2,20 +2,6 @@ You can serve static files automatically from a directory using `StaticFiles`. -## Install `aiofiles` - -First you need to install `aiofiles`: - -
- -```console -$ pip install aiofiles - ----> 100% -``` - -
- ## Use `StaticFiles` * Import `StaticFiles`. diff --git a/docs_src/async_tests/test_main.py b/docs_src/async_tests/test_main.py index c141d86ca..9f1527d5f 100644 --- a/docs_src/async_tests/test_main.py +++ b/docs_src/async_tests/test_main.py @@ -4,7 +4,7 @@ from httpx import AsyncClient from .main import app -@pytest.mark.asyncio +@pytest.mark.anyio async def test_root(): async with AsyncClient(app=app, base_url="http://test") as ac: response = await ac.get("/") diff --git a/fastapi/concurrency.py b/fastapi/concurrency.py index d1fdfe5f6..04382c69e 100644 --- a/fastapi/concurrency.py +++ b/fastapi/concurrency.py @@ -1,4 +1,5 @@ -from typing import Any, Callable +import sys +from typing import AsyncGenerator, ContextManager, TypeVar from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa @@ -6,41 +7,21 @@ from starlette.concurrency import ( # noqa run_until_first_complete as run_until_first_complete, ) -asynccontextmanager_error_message = """ -FastAPI's contextmanager_in_threadpool require Python 3.7 or above, -or the backport for Python 3.6, installed with: - pip install async-generator -""" +if sys.version_info >= (3, 7): + from contextlib import AsyncExitStack as AsyncExitStack + from contextlib import asynccontextmanager as asynccontextmanager +else: + from contextlib2 import AsyncExitStack as AsyncExitStack # noqa + from contextlib2 import asynccontextmanager as asynccontextmanager # noqa -def _fake_asynccontextmanager(func: Callable[..., Any]) -> Callable[..., Any]: - def raiser(*args: Any, **kwargs: Any) -> Any: - raise RuntimeError(asynccontextmanager_error_message) - - return raiser +_T = TypeVar("_T") -try: - from contextlib import asynccontextmanager as asynccontextmanager # type: ignore -except ImportError: - try: - from async_generator import ( # type: ignore # isort: skip - asynccontextmanager as asynccontextmanager, - ) - except ImportError: # pragma: no cover - asynccontextmanager = _fake_asynccontextmanager - -try: - from contextlib import AsyncExitStack as AsyncExitStack # type: ignore -except ImportError: - try: - from async_exit_stack import AsyncExitStack as AsyncExitStack # type: ignore - except ImportError: # pragma: no cover - AsyncExitStack = None # type: ignore - - -@asynccontextmanager # type: ignore -async def contextmanager_in_threadpool(cm: Any) -> Any: +@asynccontextmanager +async def contextmanager_in_threadpool( + cm: ContextManager[_T], +) -> AsyncGenerator[_T, None]: try: yield await run_in_threadpool(cm.__enter__) except Exception as e: diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 95049d40e..35ba44aab 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -1,4 +1,3 @@ -import asyncio import dataclasses import inspect from contextlib import contextmanager @@ -6,6 +5,7 @@ from copy import deepcopy from typing import ( Any, Callable, + Coroutine, Dict, List, Mapping, @@ -17,10 +17,10 @@ from typing import ( cast, ) +import anyio from fastapi import params from fastapi.concurrency import ( AsyncExitStack, - _fake_asynccontextmanager, asynccontextmanager, contextmanager_in_threadpool, ) @@ -266,18 +266,6 @@ def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> return annotation -async_contextmanager_dependencies_error = """ -FastAPI dependencies with yield require Python 3.7 or above, -or the backports for Python 3.6, installed with: - pip install async-exit-stack async-generator -""" - - -def check_dependency_contextmanagers() -> None: - if AsyncExitStack is None or asynccontextmanager == _fake_asynccontextmanager: - raise RuntimeError(async_contextmanager_dependencies_error) # pragma: no cover - - def get_dependant( *, path: str, @@ -289,8 +277,6 @@ def get_dependant( path_param_names = get_path_param_names(path) endpoint_signature = get_typed_signature(call) signature_params = endpoint_signature.parameters - if is_gen_callable(call) or is_async_gen_callable(call): - check_dependency_contextmanagers() dependant = Dependant(call=call, name=name, path=path, use_cache=use_cache) for param_name, param in signature_params.items(): if isinstance(param.default, params.Depends): @@ -452,14 +438,6 @@ async def solve_generator( if is_gen_callable(call): cm = contextmanager_in_threadpool(contextmanager(call)(**sub_values)) elif is_async_gen_callable(call): - if not inspect.isasyncgenfunction(call): - # asynccontextmanager from the async_generator backfill pre python3.7 - # does not support callables that are not functions or methods. - # See https://github.com/python-trio/async_generator/issues/32 - # - # Expand the callable class into its __call__ method before decorating it. - # This approach will work on newer python versions as well. - call = getattr(call, "__call__", None) cm = asynccontextmanager(call)(**sub_values) return await stack.enter_async_context(cm) @@ -539,10 +517,7 @@ async def solve_dependencies( solved = dependency_cache[sub_dependant.cache_key] elif is_gen_callable(call) or is_async_gen_callable(call): stack = request.scope.get("fastapi_astack") - if stack is None: - raise RuntimeError( - async_contextmanager_dependencies_error - ) # pragma: no cover + assert isinstance(stack, AsyncExitStack) solved = await solve_generator( call=call, stack=stack, sub_values=sub_values ) @@ -697,9 +672,18 @@ async def request_body_to_args( and lenient_issubclass(field.type_, bytes) and isinstance(value, sequence_types) ): - awaitables = [sub_value.read() for sub_value in value] - contents = await asyncio.gather(*awaitables) - value = sequence_shape_to_type[field.shape](contents) + results: List[Union[bytes, str]] = [] + + async def process_fn( + fn: Callable[[], Coroutine[Any, Any, Any]] + ) -> None: + result = await fn() + results.append(result) + + async with anyio.create_task_group() as tg: + for sub_value in value: + tg.start_soon(process_fn, sub_value.read) + value = sequence_shape_to_type[field.shape](results) v_, errors_ = field.validate(value, values, loc=loc) diff --git a/pyproject.toml b/pyproject.toml index 5b6b272a7..ddce5a39c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,8 +33,10 @@ classifiers = [ "Topic :: Internet :: WWW/HTTP", ] requires = [ - "starlette ==0.14.2", - "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0" + "starlette ==0.15.0", + "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0", + # TODO: remove contextlib2 as a direct dependency after upgrading Starlette + "contextlib2 >= 21.6.0; python_version < '3.7'", ] description-file = "README.md" requires-python = ">=3.6.1" @@ -46,7 +48,6 @@ Documentation = "https://fastapi.tiangolo.com/" test = [ "pytest >=6.2.4,<7.0.0", "pytest-cov >=2.12.0,<4.0.0", - "pytest-asyncio >=0.14.0,<0.16.0", "mypy ==0.910", "flake8 >=3.8.3,<4.0.0", "black ==21.9b0", @@ -60,11 +61,9 @@ test = [ "orjson >=3.2.1,<4.0.0", "ujson >=4.0.1,<5.0.0", "python-multipart >=0.0.5,<0.0.6", - "aiofiles >=0.5.0,<0.8.0", # TODO: try to upgrade after upgrading Starlette "flask >=1.1.2,<2.0.0", - "async_exit_stack >=1.0.1,<2.0.0; python_version < '3.7'", - "async_generator >=1.10,<2.0.0; python_version < '3.7'", + "anyio[trio] >=3.2.1,<4.0.0", # types "types-ujson ==0.1.1", @@ -90,7 +89,6 @@ dev = [ ] all = [ "requests >=2.24.0,<3.0.0", - "aiofiles >=0.5.0,<0.8.0", # TODO: try to upgrade after upgrading Starlette "jinja2 >=2.11.2,<3.0.0", "python-multipart >=0.0.5,<0.0.6", @@ -103,8 +101,6 @@ all = [ "orjson >=3.2.1,<4.0.0", "email_validator >=1.1.1,<2.0.0", "uvicorn[standard] >=0.12.0,<0.16.0", - "async_exit_stack >=1.0.1,<2.0.0; python_version < '3.7'", - "async_generator >=1.10,<2.0.0; python_version < '3.7'", ] [tool.isort] @@ -148,6 +144,8 @@ junit_family = "xunit2" filterwarnings = [ "error", 'ignore:"@coroutine" decorator is deprecated since Python 3\.8, use "async def" instead:DeprecationWarning', + # TODO: needed by AnyIO in Python 3.9, try to remove after an AnyIO upgrade + 'ignore:The loop argument is deprecated since Python 3\.8, and scheduled for removal in Python 3\.10:DeprecationWarning', # TODO: if these ignores are needed, enable them, otherwise remove them # 'ignore:The explicit passing of coroutine objects to asyncio\.wait\(\) is deprecated since Python 3\.8:DeprecationWarning', # 'ignore:Exception ignored in. Date: Wed, 6 Oct 2021 15:32:53 +0000 Subject: [PATCH 250/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 868059224..c6fc827ad 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for Trio via AnyIO. PR [#3372](https://github.com/tiangolo/fastapi/pull/3372) by [@graingert](https://github.com/graingert). * 🔧 Lint only in Python 3.7 and above. PR [#4006](https://github.com/tiangolo/fastapi/pull/4006) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add GitHub Action notify-translations config for Azerbaijani. PR [#3995](https://github.com/tiangolo/fastapi/pull/3995) by [@tiangolo](https://github.com/tiangolo). * 🌐 Initialize Azerbaijani translations. PR [#3941](https://github.com/tiangolo/fastapi/pull/3941) by [@madatbay](https://github.com/madatbay). From a8bde38f7c4498edafce088bb9b525b07db889ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 6 Oct 2021 17:42:55 +0200 Subject: [PATCH 251/814] =?UTF-8?q?=E2=9E=96=20Remove=20`graphene`=20as=20?= =?UTF-8?q?an=20optional=20dependency=20(#4007)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ddce5a39c..73a020109 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,8 +84,6 @@ dev = [ "autoflake >=1.4.0,<2.0.0", "flake8 >=3.8.3,<4.0.0", "uvicorn[standard] >=0.12.0,<0.16.0", - # TODO: remove in the next major version - "graphene >=2.1.8,<3.0.0" ] all = [ "requests >=2.24.0,<3.0.0", @@ -95,8 +93,6 @@ all = [ # TODO: try to upgrade after upgrading Starlette "itsdangerous >=1.1.0,<2.0.0", "pyyaml >=5.3.1,<6.0.0", - # TODO: remove in the next major version - "graphene >=2.1.8,<3.0.0", "ujson >=4.0.1,<5.0.0", "orjson >=3.2.1,<4.0.0", "email_validator >=1.1.1,<2.0.0", From c15f0423188c4768a60dc934f86e233732c000e4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 6 Oct 2021 15:43:37 +0000 Subject: [PATCH 252/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c6fc827ad..0849a07d5 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ➖ Remove `graphene` as an optional dependency. PR [#4007](https://github.com/tiangolo/fastapi/pull/4007) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for Trio via AnyIO. PR [#3372](https://github.com/tiangolo/fastapi/pull/3372) by [@graingert](https://github.com/graingert). * 🔧 Lint only in Python 3.7 and above. PR [#4006](https://github.com/tiangolo/fastapi/pull/4006) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add GitHub Action notify-translations config for Azerbaijani. PR [#3995](https://github.com/tiangolo/fastapi/pull/3995) by [@tiangolo](https://github.com/tiangolo). From d9fa2311b358cdbc545f5c60f98d0119ec8f0c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 7 Oct 2021 12:36:09 +0200 Subject: [PATCH 253/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20docs=20for=20using?= =?UTF-8?q?=20Trio=20with=20Hypercorn=20(#4014)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/async.md | 10 +++++++- docs/en/docs/deployment/manually.md | 37 +++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index 7fadee87f..8194650fd 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -324,7 +324,15 @@ So, about the egg and the chicken, how do you call the first `async` function? If you are working with **FastAPI** you don't have to worry about that, because that "first" function will be your *path operation function*, and FastAPI will know how to do the right thing. -But if you want to use `async` / `await` without FastAPI, check the official Python docs. +But if you want to use `async` / `await` without FastAPI, you can do it as well. + +### Write your own async code + +Starlette (and **FastAPI**) are based on AnyIO, which makes it compatible with both Python's standard library asyncio and Trio. + +In particular, you can directly use AnyIO for your advanced concurrency use cases that require more advanced patterns in your own code. + +And even if you were not using FastAPI, you could also write your own async applications with AnyIO to be highly compatible and get its benefits (e.g. *structured concurrency*). ### Other forms of asynchronous code diff --git a/docs/en/docs/deployment/manually.md b/docs/en/docs/deployment/manually.md index 80a7df7e6..6a3619b65 100644 --- a/docs/en/docs/deployment/manually.md +++ b/docs/en/docs/deployment/manually.md @@ -92,6 +92,43 @@ You can then your application the same way you have done in the tutorials, but w It helps a lot during **development**, but you **shouldn't** use it in **production**. +## Hypercorn with Trio + +Starlette and **FastAPI** are based on AnyIO, which makes them compatible with both Python's standard library asyncio and Trio. + +Nevertheless, Uvicorn is currently only compatible with asyncio, and it normally uses `uvloop`, the high-performance drop-in replacement for `asyncio`. + +But if you want to directly use **Trio**, then you can use **Hypercorn** as it supports it. ✨ + +### Install Hypercorn with Trio + +First you need to install Hypercorn with Trio support: + +
+ +```console +$ pip install "hypercorn[trio]" +---> 100% +``` + +
+ +### Run with Trio + +Then you can pass the command line option `--worker-class` with the value `trio`: + +
+ +```console +$ hypercorn main:app --worker-class trio +``` + +
+ +And that will start Hypercorn with your app using Trio as the backend. + +Now you can use Trio internally in your app. Or even better, you can use AnyIO, to keep your code compatible with both Trio and asyncio. 🎉 + ## Deployment Concepts These examples run the server program (e.g Uvicorn), starting **a single process**, listening on all the IPs (`0.0.0.0`) on a predefined port (e.g. `80`). From a6ef62ce7b6d4ff4b988e3305df5fb83b5edb732 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 10:36:53 +0000 Subject: [PATCH 254/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0849a07d5..7ce38adc3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add docs for using Trio with Hypercorn. PR [#4014](https://github.com/tiangolo/fastapi/pull/4014) by [@tiangolo](https://github.com/tiangolo). * ➖ Remove `graphene` as an optional dependency. PR [#4007](https://github.com/tiangolo/fastapi/pull/4007) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for Trio via AnyIO. PR [#3372](https://github.com/tiangolo/fastapi/pull/3372) by [@graingert](https://github.com/graingert). * 🔧 Lint only in Python 3.7 and above. PR [#4006](https://github.com/tiangolo/fastapi/pull/4006) by [@tiangolo](https://github.com/tiangolo). From 17f0ec8927a7a464bd4a0165b2d9d0ad157be12e Mon Sep 17 00:00:00 2001 From: graue70 <23035329+graue70@users.noreply.github.com> Date: Thu, 7 Oct 2021 14:21:34 +0200 Subject: [PATCH 255/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20re-word=20in?= =?UTF-8?q?=20`docs/tutorial/handling-errors.md`=20(#2700)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/handling-errors.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/en/docs/tutorial/handling-errors.md b/docs/en/docs/tutorial/handling-errors.md index 4fa82d5d7..89f96176d 100644 --- a/docs/en/docs/tutorial/handling-errors.md +++ b/docs/en/docs/tutorial/handling-errors.md @@ -260,6 +260,4 @@ You can import and re-use the default exception handlers from `fastapi.exception {!../../../docs_src/handling_errors/tutorial006.py!} ``` -In this example, you are just `print`ing the error with a very expressive message. - -But you get the idea, you can use the exception and then just re-use the default exception handlers. +In this example you are just `print`ing the error with a very expressive message, but you get the idea. You can use the exception and then just re-use the default exception handlers. From 3b686c37746d1134124751b7bb27e7e2368e5213 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 12:22:16 +0000 Subject: [PATCH 256/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7ce38adc3..5b2c67b37 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo re-word in `docs/tutorial/handling-errors.md`. PR [#2700](https://github.com/tiangolo/fastapi/pull/2700) by [@graue70](https://github.com/graue70). * 📝 Add docs for using Trio with Hypercorn. PR [#4014](https://github.com/tiangolo/fastapi/pull/4014) by [@tiangolo](https://github.com/tiangolo). * ➖ Remove `graphene` as an optional dependency. PR [#4007](https://github.com/tiangolo/fastapi/pull/4007) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for Trio via AnyIO. PR [#3372](https://github.com/tiangolo/fastapi/pull/3372) by [@graingert](https://github.com/graingert). From 8f4e3a4377293e73b93a1703e8a468d623028b97 Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Thu, 7 Oct 2021 15:56:57 +0330 Subject: [PATCH 257/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20supported=20Python?= =?UTF-8?q?=20versions=20badge=20(#2794)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- README.md | 3 +++ docs/en/docs/index.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index d376fb74e..b1c815dc7 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ Package version + + Supported Python versions +

--- diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index cc6982b79..aa2c16a2e 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -14,6 +14,9 @@ Package version + + Supported Python versions +

--- From fee3126d3a6f3045a94274caf33f8498f3dd414d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 12:27:41 +0000 Subject: [PATCH 258/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5b2c67b37..bff7847ae 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add supported Python versions badge. PR [#2794](https://github.com/tiangolo/fastapi/pull/2794) by [@hramezani](https://github.com/hramezani). * ✏ Fix typo re-word in `docs/tutorial/handling-errors.md`. PR [#2700](https://github.com/tiangolo/fastapi/pull/2700) by [@graue70](https://github.com/graue70). * 📝 Add docs for using Trio with Hypercorn. PR [#4014](https://github.com/tiangolo/fastapi/pull/4014) by [@tiangolo](https://github.com/tiangolo). * ➖ Remove `graphene` as an optional dependency. PR [#4007](https://github.com/tiangolo/fastapi/pull/4007) by [@tiangolo](https://github.com/tiangolo). From 426bd096ad5e4f3f7f3deeaa67106228a3831f00 Mon Sep 17 00:00:00 2001 From: raphaelauv Date: Thu, 7 Oct 2021 14:44:39 +0200 Subject: [PATCH 260/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20note=20about=20?= =?UTF-8?q?Falcon=20and=20ASGI,=20as=20now=20Falcon=20is=20also=20ASGI=20?= =?UTF-8?q?=F0=9F=8E=89=20(#3073)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/alternatives.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/en/docs/alternatives.md b/docs/en/docs/alternatives.md index d2792eb0c..28d0be8cc 100644 --- a/docs/en/docs/alternatives.md +++ b/docs/en/docs/alternatives.md @@ -242,8 +242,6 @@ It was one of the first extremely fast Python frameworks based on `asyncio`. It Falcon is another high performance Python framework, it is designed to be minimal, and work as the foundation of other frameworks like Hug. -It uses the previous standard for Python web frameworks (WSGI) which is synchronous, so it can't handle WebSockets and other use cases. Nevertheless, it also has a very good performance. - It is designed to have functions that receive two parameters, one "request" and one "response". Then you "read" parts from the request, and "write" parts to the response. Because of this design, it is not possible to declare request parameters and bodies with standard Python type hints as function parameters. So, data validation, serialization, and documentation, have to be done in code, not automatically. Or they have to be implemented as a framework on top of Falcon, like Hug. This same distinction happens in other frameworks that are inspired by Falcon's design, of having one request object and one response object as parameters. From afe1f69e792a537b689f7b4733e7149ca123da71 Mon Sep 17 00:00:00 2001 From: Greg Gandenberger Date: Thu, 7 Oct 2021 07:55:51 -0500 Subject: [PATCH 261/814] =?UTF-8?q?=F0=9F=93=9D=20Remove=20note=20about=20?= =?UTF-8?q?(now=20supported)=20feature=20from=20Swagger=20UI=20in=20`docs/?= =?UTF-8?q?en/docs/tutorial/request-files.md`=20(#2803)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/request-files.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md index 1619d6d2a..68ea654c2 100644 --- a/docs/en/docs/tutorial/request-files.md +++ b/docs/en/docs/tutorial/request-files.md @@ -127,13 +127,6 @@ To use that, declare a `List` of `bytes` or `UploadFile`: You will receive, as declared, a `list` of `bytes` or `UploadFile`s. -!!! note - Notice that, as of 2019-04-14, Swagger UI doesn't support multiple file uploads in the same form field. For more information, check #4276 and #3641. - - Nevertheless, **FastAPI** is already compatible with it, using the standard OpenAPI. - - So, whenever Swagger UI supports multi-file uploads, or any other tools that supports OpenAPI, they will be compatible with **FastAPI**. - !!! note "Technical Details" You could also use `from starlette.responses import HTMLResponse`. From 12db3926b55ce5698b1b837161706ac86db47a03 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 12:57:15 +0000 Subject: [PATCH 262/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bff7847ae..2baee0288 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Remove note about (now supported) feature from Swagger UI in `docs/en/docs/tutorial/request-files.md`. PR [#2803](https://github.com/tiangolo/fastapi/pull/2803) by [@gsganden](https://github.com/gsganden). * 📝 Add supported Python versions badge. PR [#2794](https://github.com/tiangolo/fastapi/pull/2794) by [@hramezani](https://github.com/hramezani). * ✏ Fix typo re-word in `docs/tutorial/handling-errors.md`. PR [#2700](https://github.com/tiangolo/fastapi/pull/2700) by [@graue70](https://github.com/graue70). * 📝 Add docs for using Trio with Hypercorn. PR [#4014](https://github.com/tiangolo/fastapi/pull/4014) by [@tiangolo](https://github.com/tiangolo). From b69781b161509d51095faa98ddd3bc6c78613eb7 Mon Sep 17 00:00:00 2001 From: Abraham Hinteregger Date: Thu, 7 Oct 2021 15:00:33 +0200 Subject: [PATCH 263/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20(mistranslatio?= =?UTF-8?q?n)=20in=20`docs/en/docs/advanced/templates.md`=20(#3211)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/advanced/templates.md b/docs/en/docs/advanced/templates.md index 45e6a20fc..38618aeeb 100644 --- a/docs/en/docs/advanced/templates.md +++ b/docs/en/docs/advanced/templates.md @@ -2,7 +2,7 @@ You can use any template engine you want with **FastAPI**. -A common election is Jinja2, the same one used by Flask and other tools. +A common choice is Jinja2, the same one used by Flask and other tools. There are utilities to configure it easily that you can use directly in your **FastAPI** application (provided by Starlette). From 3581034eff447366bcffb896c0fc161e2bd23e75 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 13:01:11 +0000 Subject: [PATCH 264/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2baee0288..8ca74f1cd 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo (mistranslation) in `docs/en/docs/advanced/templates.md`. PR [#3211](https://github.com/tiangolo/fastapi/pull/3211) by [@oerpli](https://github.com/oerpli). * 📝 Remove note about (now supported) feature from Swagger UI in `docs/en/docs/tutorial/request-files.md`. PR [#2803](https://github.com/tiangolo/fastapi/pull/2803) by [@gsganden](https://github.com/gsganden). * 📝 Add supported Python versions badge. PR [#2794](https://github.com/tiangolo/fastapi/pull/2794) by [@hramezani](https://github.com/hramezani). * ✏ Fix typo re-word in `docs/tutorial/handling-errors.md`. PR [#2700](https://github.com/tiangolo/fastapi/pull/2700) by [@graue70](https://github.com/graue70). From e423c8241af70f6fedd5074c161c3befa5af12cf Mon Sep 17 00:00:00 2001 From: mori yuta <59682979+utamori@users.noreply.github.com> Date: Thu, 7 Oct 2021 22:06:17 +0900 Subject: [PATCH 265/814] =?UTF-8?q?=E2=9C=8F=20Fix=20link=20in=20Japanese?= =?UTF-8?q?=20docs=20for=20`docs/ja/docs/deployment/docker.md`=20(#3245)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/ja/docs/deployment/docker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/docs/deployment/docker.md b/docs/ja/docs/deployment/docker.md index 03a95ac6f..f10312b51 100644 --- a/docs/ja/docs/deployment/docker.md +++ b/docs/ja/docs/deployment/docker.md @@ -170,7 +170,7 @@ TraefikおよびHTTPS処理を備えたDocker Swarm Modeクラスターをセッ ### FastAPIアプリケーションのデプロイ -すべてを設定するための最も簡単な方法は、[**FastAPI** Project Generators](project-generation.md){.internal-link target=_blank}を使用することでしょう。 +すべてを設定するための最も簡単な方法は、[**FastAPI** Project Generators](../project-generation.md){.internal-link target=_blank}を使用することでしょう。 上述したTraefikとHTTPSを備えたDocker Swarm クラスタが統合されるように設計されています。 From 46882b9ae15ba0a3c312e556d1e8c8982f00c780 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 13:07:24 +0000 Subject: [PATCH 266/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8ca74f1cd..5fa77c93d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix link in Japanese docs for `docs/ja/docs/deployment/docker.md`. PR [#3245](https://github.com/tiangolo/fastapi/pull/3245) by [@utamori](https://github.com/utamori). * ✏ Fix typo (mistranslation) in `docs/en/docs/advanced/templates.md`. PR [#3211](https://github.com/tiangolo/fastapi/pull/3211) by [@oerpli](https://github.com/oerpli). * 📝 Remove note about (now supported) feature from Swagger UI in `docs/en/docs/tutorial/request-files.md`. PR [#2803](https://github.com/tiangolo/fastapi/pull/2803) by [@gsganden](https://github.com/gsganden). * 📝 Add supported Python versions badge. PR [#2794](https://github.com/tiangolo/fastapi/pull/2794) by [@hramezani](https://github.com/hramezani). From 8e68ddbddfa2c1897e6a9a3f7eeab2ae141f6f4d Mon Sep 17 00:00:00 2001 From: Somraj Saha Date: Thu, 7 Oct 2021 18:43:10 +0530 Subject: [PATCH 267/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link=20?= =?UTF-8?q?to=20article:=20How-to=20deploy=20FastAPI=20app=20to=20Heroku?= =?UTF-8?q?=20(#3241)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index 40bf5ef04..bb3e00932 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - link: https://jarmos.netlify.app/posts/using-github-actions-to-deploy-a-fastapi-project-to-heroku/ + title: Using GitHub Actions to Deploy a FastAPI Project to Heroku + author_link: https://jarmos.netlify.app/ + author: Somraj Saha - author: "@pystar" author_link: https://pystar.substack.com/ link: https://pystar.substack.com/p/how-to-create-a-fake-certificate From 5551e7282ce2b16b88a724082763fa22aeb116de Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 13:14:08 +0000 Subject: [PATCH 268/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5fa77c93d..7891c8a4f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link to article: How-to deploy FastAPI app to Heroku. PR [#3241](https://github.com/tiangolo/fastapi/pull/3241) by [@Jarmos-san](https://github.com/Jarmos-san). * ✏ Fix link in Japanese docs for `docs/ja/docs/deployment/docker.md`. PR [#3245](https://github.com/tiangolo/fastapi/pull/3245) by [@utamori](https://github.com/utamori). * ✏ Fix typo (mistranslation) in `docs/en/docs/advanced/templates.md`. PR [#3211](https://github.com/tiangolo/fastapi/pull/3211) by [@oerpli](https://github.com/oerpli). * 📝 Remove note about (now supported) feature from Swagger UI in `docs/en/docs/tutorial/request-files.md`. PR [#2803](https://github.com/tiangolo/fastapi/pull/2803) by [@gsganden](https://github.com/gsganden). From c29aa0bc8726e2c4e91ada08e4321062782a3455 Mon Sep 17 00:00:00 2001 From: Edd Salkield Date: Thu, 7 Oct 2021 13:26:36 +0000 Subject: [PATCH 269/814] =?UTF-8?q?=F0=9F=94=A7=20Swap=20light/dark=20them?= =?UTF-8?q?e=20button=20icon=20(#3246)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/az/mkdocs.yml | 4 ++-- docs/de/mkdocs.yml | 4 ++-- docs/en/mkdocs.yml | 4 ++-- docs/es/mkdocs.yml | 4 ++-- docs/fr/mkdocs.yml | 4 ++-- docs/id/mkdocs.yml | 4 ++-- docs/it/mkdocs.yml | 4 ++-- docs/ja/mkdocs.yml | 4 ++-- docs/ko/mkdocs.yml | 4 ++-- docs/pl/mkdocs.yml | 4 ++-- docs/pt/mkdocs.yml | 4 ++-- docs/ru/mkdocs.yml | 4 ++-- docs/sq/mkdocs.yml | 4 ++-- docs/tr/mkdocs.yml | 4 ++-- docs/uk/mkdocs.yml | 4 ++-- docs/zh/mkdocs.yml | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index edeb6c2e3..72ca92a96 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index bcd521c80..621305d20 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 28a688a96..aa2d0451d 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 35127ac27..ef722715b 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 4cd0750c9..940e4ff69 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index 31488ee33..f9cae22cc 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index 10e6198f2..f16210608 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 37f6548d8..237bc9654 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index bb66c8987..0bf1a9713 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 0775048e9..220008607 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 3e5fece58..219f41b81 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index eee98a9bc..e15a36bf2 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index 1d2adbb7d..a4879521e 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index d78947fa7..6fe2b0b62 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index 41aec880c..7f5785e3e 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 3f27884e4..07ffa367f 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -9,13 +9,13 @@ theme: primary: teal accent: amber toggle: - icon: material/lightbulb-outline + icon: material/lightbulb name: Switch to light mode - scheme: slate primary: teal accent: amber toggle: - icon: material/lightbulb + icon: material/lightbulb-outline name: Switch to dark mode features: - search.suggest From b67532ee5ca6af6d1ae048b60e59d8cf36b5783d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 13:27:16 +0000 Subject: [PATCH 270/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7891c8a4f..0a54f5356 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Swap light/dark theme button icon. PR [#3246](https://github.com/tiangolo/fastapi/pull/3246) by [@eddsalkield](https://github.com/eddsalkield). * 📝 Add external link to article: How-to deploy FastAPI app to Heroku. PR [#3241](https://github.com/tiangolo/fastapi/pull/3241) by [@Jarmos-san](https://github.com/Jarmos-san). * ✏ Fix link in Japanese docs for `docs/ja/docs/deployment/docker.md`. PR [#3245](https://github.com/tiangolo/fastapi/pull/3245) by [@utamori](https://github.com/utamori). * ✏ Fix typo (mistranslation) in `docs/en/docs/advanced/templates.md`. PR [#3211](https://github.com/tiangolo/fastapi/pull/3211) by [@oerpli](https://github.com/oerpli). From 4f168c5ada33c2b02344f0a4c7d8d9983fa981a1 Mon Sep 17 00:00:00 2001 From: Pax <13646646+paxcodes@users.noreply.github.com> Date: Thu, 7 Oct 2021 06:32:14 -0700 Subject: [PATCH 271/814] =?UTF-8?q?=F0=9F=93=9D=20=20Fix=20incorrect=20hig?= =?UTF-8?q?hlighted=20code=20(#3325)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/body-multiple-params.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/body-multiple-params.md b/docs/en/docs/tutorial/body-multiple-params.md index 1bc8f1436..a4484147f 100644 --- a/docs/en/docs/tutorial/body-multiple-params.md +++ b/docs/en/docs/tutorial/body-multiple-params.md @@ -109,7 +109,7 @@ q: Optional[str] = None as in: -```Python hl_lines="27" +```Python hl_lines="28" {!../../../docs_src/body_multiple_params/tutorial004.py!} ``` From 1a8284725aa8c62d347aeb0c37c09aa889a7336b Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 13:32:54 +0000 Subject: [PATCH 272/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0a54f5356..74fc37673 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Fix incorrect highlighted code. PR [#3325](https://github.com/tiangolo/fastapi/pull/3325) by [@paxcodes](https://github.com/paxcodes). * 🔧 Swap light/dark theme button icon. PR [#3246](https://github.com/tiangolo/fastapi/pull/3246) by [@eddsalkield](https://github.com/eddsalkield). * 📝 Add external link to article: How-to deploy FastAPI app to Heroku. PR [#3241](https://github.com/tiangolo/fastapi/pull/3241) by [@Jarmos-san](https://github.com/Jarmos-san). * ✏ Fix link in Japanese docs for `docs/ja/docs/deployment/docker.md`. PR [#3245](https://github.com/tiangolo/fastapi/pull/3245) by [@utamori](https://github.com/utamori). From d06b4d7bb88156bf101f4106b3ddecbd9867ef82 Mon Sep 17 00:00:00 2001 From: Bharat Raghunathan Date: Thu, 7 Oct 2021 19:27:51 +0530 Subject: [PATCH 273/814] =?UTF-8?q?=E2=9C=8F=20Re-word=20to=20clarify=20te?= =?UTF-8?q?st=20client=20in=20`docs/en/docs/tutorial/testing.md`=20(#3382)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md index b225dcb66..9c9a8270c 100644 --- a/docs/en/docs/tutorial/testing.md +++ b/docs/en/docs/tutorial/testing.md @@ -10,7 +10,7 @@ With it, you can use Date: Thu, 7 Oct 2021 13:59:14 +0000 Subject: [PATCH 274/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 74fc37673..e75d8dce7 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Re-word to clarify test client in `docs/en/docs/tutorial/testing.md`. PR [#3382](https://github.com/tiangolo/fastapi/pull/3382) by [@Bharat123rox](https://github.com/Bharat123rox). * 📝 Fix incorrect highlighted code. PR [#3325](https://github.com/tiangolo/fastapi/pull/3325) by [@paxcodes](https://github.com/paxcodes). * 🔧 Swap light/dark theme button icon. PR [#3246](https://github.com/tiangolo/fastapi/pull/3246) by [@eddsalkield](https://github.com/eddsalkield). * 📝 Add external link to article: How-to deploy FastAPI app to Heroku. PR [#3241](https://github.com/tiangolo/fastapi/pull/3241) by [@Jarmos-san](https://github.com/Jarmos-san). From 7efdc110759a318775599d22c34c9a1de2e4e13e Mon Sep 17 00:00:00 2001 From: Denys Marichev Date: Thu, 7 Oct 2021 17:07:46 +0300 Subject: [PATCH 275/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20about=20file?= =?UTF-8?q?=20path=20in=20`docs/en/docs/tutorial/bigger-applications.md`?= =?UTF-8?q?=20(#3285)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/bigger-applications.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/tutorial/bigger-applications.md b/docs/en/docs/tutorial/bigger-applications.md index 2796d7fb1..2a2e764b5 100644 --- a/docs/en/docs/tutorial/bigger-applications.md +++ b/docs/en/docs/tutorial/bigger-applications.md @@ -234,7 +234,7 @@ mean: * Starting in the same package that this module (the file `app/routers/items.py`) lives in (the directory `app/routers/`)... * go to the parent package (the directory `app/`)... -* and in there, find the module `dependencies` (the file at `app/routers/dependencies.py`)... +* and in there, find the module `dependencies` (the file at `app/dependencies.py`)... * and from it, import the function `get_token_header`. That works correctly! 🎉 @@ -252,7 +252,7 @@ that would mean: * Starting in the same package that this module (the file `app/routers/items.py`) lives in (the directory `app/routers/`)... * go to the parent package (the directory `app/`)... * then go to the parent of that package (there's no parent package, `app` is the top level 😱)... -* and in there, find the module `dependencies` (the file at `app/routers/dependencies.py`)... +* and in there, find the module `dependencies` (the file at `app/dependencies.py`)... * and from it, import the function `get_token_header`. That would refer to some package above `app/`, with its own file `__init__.py`, etc. But we don't have that. So, that would throw an error in our example. 🚨 From 4093c350587c899760399f48434b313e4005f2b9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 14:09:05 +0000 Subject: [PATCH 276/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e75d8dce7..b38431ca0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo about file path in `docs/en/docs/tutorial/bigger-applications.md`. PR [#3285](https://github.com/tiangolo/fastapi/pull/3285) by [@HolyDorus](https://github.com/HolyDorus). * ✏ Re-word to clarify test client in `docs/en/docs/tutorial/testing.md`. PR [#3382](https://github.com/tiangolo/fastapi/pull/3382) by [@Bharat123rox](https://github.com/Bharat123rox). * 📝 Fix incorrect highlighted code. PR [#3325](https://github.com/tiangolo/fastapi/pull/3325) by [@paxcodes](https://github.com/paxcodes). * 🔧 Swap light/dark theme button icon. PR [#3246](https://github.com/tiangolo/fastapi/pull/3246) by [@eddsalkield](https://github.com/eddsalkield). From 5a28f95a93802161967b7ad56fb557b434853134 Mon Sep 17 00:00:00 2001 From: jaystone776 Date: Thu, 7 Oct 2021 22:22:16 +0800 Subject: [PATCH 277/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20in=20`docs/en/?= =?UTF-8?q?docs/help-fastapi.md`=20(#3760)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/help-fastapi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/help-fastapi.md b/docs/en/docs/help-fastapi.md index 394bccab7..8d8d708ed 100644 --- a/docs/en/docs/help-fastapi.md +++ b/docs/en/docs/help-fastapi.md @@ -121,7 +121,7 @@ Have in mind that as chats allow more "free conversation", it's easy to ask ques In GitHub issues the template will guide you to write the right question so that you can more easily get a good answer, or even solve the problem yourself even before asking. And in GitHub I can make sure I always answer everything, even if it takes some time. I can't personally do that with the chat systems. 😅 -Conversations in the chat systems are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation. And only the ones in GitHub issues count to become a [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}, so you will most probably receive more attention in GitHub isssues. +Conversations in the chat systems are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation. And only the ones in GitHub issues count to become a [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}, so you will most probably receive more attention in GitHub issues. On the other side, there are thousands of users in the chat systems, so there's a high chance you'll find someone to talk to there, almost all the time. 😄 From eb453a50b81f4fe5132b737d5fe07ba78c995beb Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 14:23:26 +0000 Subject: [PATCH 278/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b38431ca0..8a5cbcec7 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo in `docs/en/docs/help-fastapi.md`. PR [#3760](https://github.com/tiangolo/fastapi/pull/3760) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo about file path in `docs/en/docs/tutorial/bigger-applications.md`. PR [#3285](https://github.com/tiangolo/fastapi/pull/3285) by [@HolyDorus](https://github.com/HolyDorus). * ✏ Re-word to clarify test client in `docs/en/docs/tutorial/testing.md`. PR [#3382](https://github.com/tiangolo/fastapi/pull/3382) by [@Bharat123rox](https://github.com/Bharat123rox). * 📝 Fix incorrect highlighted code. PR [#3325](https://github.com/tiangolo/fastapi/pull/3325) by [@paxcodes](https://github.com/paxcodes). From e43f43444829ad8e469f2178e473f4b95085c891 Mon Sep 17 00:00:00 2001 From: Jorge Alvarado <65737950+jalvaradosegura@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:36:43 -0300 Subject: [PATCH 279/814] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Add=20a=20missing?= =?UTF-8?q?=20comma=20in=20the=20security=20tutorial=20(#3564)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/security/get-current-user.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/security/get-current-user.md b/docs/en/docs/tutorial/security/get-current-user.md index f50b69acf..a41db2b67 100644 --- a/docs/en/docs/tutorial/security/get-current-user.md +++ b/docs/en/docs/tutorial/security/get-current-user.md @@ -84,7 +84,7 @@ Just use any kind of model, any kind of class, any kind of database that you nee ## Code size -This example might seem verbose. Have in mind that we are mixing security, data models utility functions and *path operations* in the same file. +This example might seem verbose. Have in mind that we are mixing security, data models, utility functions and *path operations* in the same file. But here's the key point. From ffaecddbf6b88badce1f08066a1a25b0200e02eb Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 14:37:59 +0000 Subject: [PATCH 280/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8a5cbcec7..ffaf4009e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Add a missing comma in the security tutorial. PR [#3564](https://github.com/tiangolo/fastapi/pull/3564) by [@jalvaradosegura](https://github.com/jalvaradosegura). * ✏ Fix typo in `docs/en/docs/help-fastapi.md`. PR [#3760](https://github.com/tiangolo/fastapi/pull/3760) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo about file path in `docs/en/docs/tutorial/bigger-applications.md`. PR [#3285](https://github.com/tiangolo/fastapi/pull/3285) by [@HolyDorus](https://github.com/HolyDorus). * ✏ Re-word to clarify test client in `docs/en/docs/tutorial/testing.md`. PR [#3382](https://github.com/tiangolo/fastapi/pull/3382) by [@Bharat123rox](https://github.com/Bharat123rox). From 7e4887ea55f932e7373a27354d5a6b7cc3fa9017 Mon Sep 17 00:00:00 2001 From: SaintMalik <37118134+saintmalik@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:29:50 +0100 Subject: [PATCH 281/814] =?UTF-8?q?=E2=9C=8F=20Fix=20a=20typo=20in=20`docs?= =?UTF-8?q?/en/docs/advanced/path-operation-advanced-configuration.md`=20a?= =?UTF-8?q?nd=20`docs/en/docs/release-notes.md`=20(#3750)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/path-operation-advanced-configuration.md | 2 +- docs/en/docs/release-notes.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/advanced/path-operation-advanced-configuration.md b/docs/en/docs/advanced/path-operation-advanced-configuration.md index 352fe0764..a1c902ef2 100644 --- a/docs/en/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/en/docs/advanced/path-operation-advanced-configuration.md @@ -77,7 +77,7 @@ This *path operation*-specific OpenAPI schema is normally generated automaticall !!! tip This is a low level extension point. - If you only need to declare additonal responses, a more convenient way to do it is with [Additional Responses in OpenAPI](./additional-responses.md){.internal-link target=_blank}. + If you only need to declare additional responses, a more convenient way to do it is with [Additional Responses in OpenAPI](./additional-responses.md){.internal-link target=_blank}. You can extend the OpenAPI schema for a *path operation* using the parameter `openapi_extra`. diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ffaf4009e..03234188f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -94,7 +94,7 @@ Soon there will be a new FastAPI release upgrading Starlette to take advantage o ### Features * ✨ Add support for extensions and updates to the OpenAPI schema in each *path operation*. New docs: [FastAPI Path Operation Advanced Configuration - OpenAPI Extra](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#openapi-extra). Initial PR [#1922](https://github.com/tiangolo/fastapi/pull/1922) by [@edouardlp](https://github.com/edouardlp). -* ✨ Add additonal OpenAPI metadata parameters to `FastAPI` class, shown on the automatic API docs UI. New docs: [Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/). Initial PR [#1812](https://github.com/tiangolo/fastapi/pull/1812) by [@dkreeft](https://github.com/dkreeft). +* ✨ Add additional OpenAPI metadata parameters to `FastAPI` class, shown on the automatic API docs UI. New docs: [Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/). Initial PR [#1812](https://github.com/tiangolo/fastapi/pull/1812) by [@dkreeft](https://github.com/dkreeft). * ✨ Add `description` parameter to all the security scheme classes, e.g. `APIKeyQuery(name="key", description="A very cool API key")`. PR [#1757](https://github.com/tiangolo/fastapi/pull/1757) by [@hylkepostma](https://github.com/hylkepostma). * ✨ Update OpenAPI models, supporting recursive models and extensions. PR [#3628](https://github.com/tiangolo/fastapi/pull/3628) by [@tiangolo](https://github.com/tiangolo). * ✨ Import and re-export data structures from Starlette, used by Request properties, on `fastapi.datastructures`. Initial PR [#1872](https://github.com/tiangolo/fastapi/pull/1872) by [@jamescurtin](https://github.com/jamescurtin). From bb20f5e60df2384663e94d5abe4f8e67bb7a16a3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 15:30:34 +0000 Subject: [PATCH 282/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 03234188f..6371d48ad 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix a typo in `docs/en/docs/advanced/path-operation-advanced-configuration.md` and `docs/en/docs/release-notes.md`. PR [#3750](https://github.com/tiangolo/fastapi/pull/3750) by [@saintmalik](https://github.com/saintmalik). * ✏️ Add a missing comma in the security tutorial. PR [#3564](https://github.com/tiangolo/fastapi/pull/3564) by [@jalvaradosegura](https://github.com/jalvaradosegura). * ✏ Fix typo in `docs/en/docs/help-fastapi.md`. PR [#3760](https://github.com/tiangolo/fastapi/pull/3760) by [@jaystone776](https://github.com/jaystone776). * ✏ Fix typo about file path in `docs/en/docs/tutorial/bigger-applications.md`. PR [#3285](https://github.com/tiangolo/fastapi/pull/3285) by [@HolyDorus](https://github.com/HolyDorus). From b1508dcacc3ebc0001949156b8460c5327bb2f53 Mon Sep 17 00:00:00 2001 From: Jorge Alvarado <65737950+jalvaradosegura@users.noreply.github.com> Date: Thu, 7 Oct 2021 12:39:19 -0300 Subject: [PATCH 283/814] =?UTF-8?q?=E2=9C=8F=20Re-word=20and=20combine=202?= =?UTF-8?q?=20paragraphs=20into=201=20for=20readability=20(#3346)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/es/docs/tutorial/index.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/es/docs/tutorial/index.md b/docs/es/docs/tutorial/index.md index 14ce39225..9cbdb2727 100644 --- a/docs/es/docs/tutorial/index.md +++ b/docs/es/docs/tutorial/index.md @@ -4,9 +4,7 @@ Este tutorial te muestra cómo usar **FastAPI** con la mayoría de sus caracter Cada sección se basa gradualmente en las anteriores, pero está estructurada en temas separados, así puedes ir directamente a cualquier tema en concreto para resolver tus necesidades específicas sobre la API. -También está diseñado para funcionar como una referencia futura. - -Para que puedas volver y ver exactamente lo que necesitas. +Funciona también como una referencia futura, para que puedas volver y ver exactamente lo que necesitas. ## Ejecuta el código From 4ba1e81f1671ae252b514fed31f76f2224144df4 Mon Sep 17 00:00:00 2001 From: Nina Hwang <79563565+NinaHwang@users.noreply.github.com> Date: Fri, 8 Oct 2021 00:44:46 +0900 Subject: [PATCH 284/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20in=20file=20pa?= =?UTF-8?q?ths=20in=20`docs/en/docs/contributing.md`=20(#3752)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/contributing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/contributing.md b/docs/en/docs/contributing.md index 9ef6e22c8..648c472fe 100644 --- a/docs/en/docs/contributing.md +++ b/docs/en/docs/contributing.md @@ -326,7 +326,7 @@ docs/es/docs/features.md * Now open the MkDocs config file for English at: ``` -docs/en/docs/mkdocs.yml +docs/en/mkdocs.yml ``` * Find the place where that `docs/features.md` is located in the config file. Somewhere like: @@ -345,7 +345,7 @@ nav: * Open the MkDocs config file for the language you are editing, e.g.: ``` -docs/es/docs/mkdocs.yml +docs/es/mkdocs.yml ``` * Add it there at the exact same location it was for English, e.g.: From d198f38b4546d62b7cf30c3eae0affb4a429167a Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 15:45:28 +0000 Subject: [PATCH 285/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6371d48ad..f5729765e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo in file paths in `docs/en/docs/contributing.md`. PR [#3752](https://github.com/tiangolo/fastapi/pull/3752) by [@NinaHwang](https://github.com/NinaHwang). * ✏ Fix a typo in `docs/en/docs/advanced/path-operation-advanced-configuration.md` and `docs/en/docs/release-notes.md`. PR [#3750](https://github.com/tiangolo/fastapi/pull/3750) by [@saintmalik](https://github.com/saintmalik). * ✏️ Add a missing comma in the security tutorial. PR [#3564](https://github.com/tiangolo/fastapi/pull/3564) by [@jalvaradosegura](https://github.com/jalvaradosegura). * ✏ Fix typo in `docs/en/docs/help-fastapi.md`. PR [#3760](https://github.com/tiangolo/fastapi/pull/3760) by [@jaystone776](https://github.com/jaystone776). From 9c6e0d02bb8e3de31ca26ee4118119e928eb099f Mon Sep 17 00:00:00 2001 From: Kaustubh Gupta Date: Thu, 7 Oct 2021 21:25:40 +0530 Subject: [PATCH 286/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link=20?= =?UTF-8?q?to=20article:=20Deploying=20ML=20Models=20as=20API=20Using=20Fa?= =?UTF-8?q?stAPI=20and=20Heroku=20(#3904)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index bb3e00932..0850d9788 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: Kaustubh Gupta + author_link: https://medium.com/@kaustubhgupta1828/ + link: https://www.analyticsvidhya.com/blog/2021/06/deploying-ml-models-as-api-using-fastapi-and-heroku/ + title: Deploying ML Models as API Using FastAPI and Heroku - link: https://jarmos.netlify.app/posts/using-github-actions-to-deploy-a-fastapi-project-to-heroku/ title: Using GitHub Actions to Deploy a FastAPI Project to Heroku author_link: https://jarmos.netlify.app/ From 077e5baf2c277ae49b56a5d4e913fbbc29c3cd03 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 15:56:18 +0000 Subject: [PATCH 287/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f5729765e..0654d8070 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link to article: Deploying ML Models as API Using FastAPI and Heroku. PR [#3904](https://github.com/tiangolo/fastapi/pull/3904) by [@kaustubhgupta](https://github.com/kaustubhgupta). * ✏ Fix typo in file paths in `docs/en/docs/contributing.md`. PR [#3752](https://github.com/tiangolo/fastapi/pull/3752) by [@NinaHwang](https://github.com/NinaHwang). * ✏ Fix a typo in `docs/en/docs/advanced/path-operation-advanced-configuration.md` and `docs/en/docs/release-notes.md`. PR [#3750](https://github.com/tiangolo/fastapi/pull/3750) by [@saintmalik](https://github.com/saintmalik). * ✏️ Add a missing comma in the security tutorial. PR [#3564](https://github.com/tiangolo/fastapi/pull/3564) by [@jalvaradosegura](https://github.com/jalvaradosegura). From c54fb7e20804698bf9ba9422fd92e53fa85114ad Mon Sep 17 00:00:00 2001 From: tomwei7 Date: Thu, 7 Oct 2021 23:57:38 +0800 Subject: [PATCH 288/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20docs=20with=20p?= =?UTF-8?q?ip=20install=20calls=20when=20using=20extras=20with=20brackets,?= =?UTF-8?q?=20use=20quotes=20for=20compatibility=20with=20Zsh=20(#3131)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- README.md | 4 ++-- docs/en/docs/deployment/manually.md | 2 +- docs/en/docs/deployment/server-workers.md | 2 +- docs/en/docs/index.md | 4 ++-- docs/en/docs/tutorial/index.md | 4 ++-- docs/en/docs/tutorial/security/oauth2-jwt.md | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b1c815dc7..830031581 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ You will also need an ASGI server, for production such as ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` @@ -456,7 +456,7 @@ Used by FastAPI / Starlette: * uvicorn - for the server that loads and serves your application. * orjson - Required if you want to use `ORJSONResponse`. -You can install all of these with `pip install fastapi[all]`. +You can install all of these with `pip install "fastapi[all]"`. ## License diff --git a/docs/en/docs/deployment/manually.md b/docs/en/docs/deployment/manually.md index 6a3619b65..7fd1f4d4f 100644 --- a/docs/en/docs/deployment/manually.md +++ b/docs/en/docs/deployment/manually.md @@ -29,7 +29,7 @@ You can install an ASGI compatible server with:
```console - $ pip install uvicorn[standard] + $ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/en/docs/deployment/server-workers.md b/docs/en/docs/deployment/server-workers.md index 2892d5797..84a2b0f33 100644 --- a/docs/en/docs/deployment/server-workers.md +++ b/docs/en/docs/deployment/server-workers.md @@ -39,7 +39,7 @@ And then the Gunicorn-compatible **Uvicorn worker** class would be in charge of
```console -$ pip install uvicorn[standard] gunicorn +$ pip install "uvicorn[standard]" gunicorn ---> 100% ``` diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index aa2c16a2e..7de1e50df 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -134,7 +134,7 @@ You will also need an ASGI server, for production such as ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` @@ -457,7 +457,7 @@ Used by FastAPI / Starlette: * uvicorn - for the server that loads and serves your application. * orjson - Required if you want to use `ORJSONResponse`. -You can install all of these with `pip install fastapi[all]`. +You can install all of these with `pip install "fastapi[all]"`. ## License diff --git a/docs/en/docs/tutorial/index.md b/docs/en/docs/tutorial/index.md index bd02cd539..8b4a9df9b 100644 --- a/docs/en/docs/tutorial/index.md +++ b/docs/en/docs/tutorial/index.md @@ -43,7 +43,7 @@ For the tutorial, you might want to install it with all the optional dependencie
```console -$ pip install fastapi[all] +$ pip install "fastapi[all]" ---> 100% ``` @@ -64,7 +64,7 @@ $ pip install fastapi[all] Also install `uvicorn` to work as the server: ``` - pip install uvicorn[standard] + pip install "uvicorn[standard]" ``` And the same for each of the optional dependencies that you want to use. diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index fda722cd1..f88cf23c0 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -33,7 +33,7 @@ We need to install `python-jose` to generate and verify the JWT tokens in Python
```console -$ pip install python-jose[cryptography] +$ pip install "python-jose[cryptography]" ---> 100% ``` @@ -76,7 +76,7 @@ So, install PassLib with Bcrypt:
```console -$ pip install passlib[bcrypt] +$ pip install "passlib[bcrypt]" ---> 100% ``` From eb89968b360cebcd0a9add92c5fc336aa7c44935 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 7 Oct 2021 15:58:17 +0000 Subject: [PATCH 289/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0654d8070..6efceb390 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update docs with pip install calls when using extras with brackets, use quotes for compatibility with Zsh. PR [#3131](https://github.com/tiangolo/fastapi/pull/3131) by [@tomwei7](https://github.com/tomwei7). * 📝 Add external link to article: Deploying ML Models as API Using FastAPI and Heroku. PR [#3904](https://github.com/tiangolo/fastapi/pull/3904) by [@kaustubhgupta](https://github.com/kaustubhgupta). * ✏ Fix typo in file paths in `docs/en/docs/contributing.md`. PR [#3752](https://github.com/tiangolo/fastapi/pull/3752) by [@NinaHwang](https://github.com/NinaHwang). * ✏ Fix a typo in `docs/en/docs/advanced/path-operation-advanced-configuration.md` and `docs/en/docs/release-notes.md`. PR [#3750](https://github.com/tiangolo/fastapi/pull/3750) by [@saintmalik](https://github.com/saintmalik). From 53076170c01ad9daff3060ae6c8fdf62772c1b82 Mon Sep 17 00:00:00 2001 From: Andy Challis Date: Fri, 8 Oct 2021 03:14:39 +1100 Subject: [PATCH 290/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typos=20in=20Deployme?= =?UTF-8?q?nt=20Guide=20(#3975)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Anthony Lukach Co-authored-by: Sebastián Ramírez --- docs/en/docs/deployment/concepts.md | 34 +++++++++++------------ docs/en/docs/deployment/deta.md | 8 +++--- docs/en/docs/deployment/docker.md | 18 ++++++------ docs/en/docs/deployment/https.md | 2 +- docs/en/docs/deployment/index.md | 2 +- docs/en/docs/deployment/server-workers.md | 6 ++-- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/en/docs/deployment/concepts.md b/docs/en/docs/deployment/concepts.md index d22b53fe0..22604ceeb 100644 --- a/docs/en/docs/deployment/concepts.md +++ b/docs/en/docs/deployment/concepts.md @@ -21,7 +21,7 @@ By considering these concepts, you will be able to **evaluate and design** the b In the next chapters, I'll give you more **concrete recipes** to deploy FastAPI applications. -But for now, let's check these important **conceptual ideas**. These concepts also apply for any other type of web API. 💡 +But for now, let's check these important **conceptual ideas**. These concepts also apply to any other type of web API. 💡 ## Security - HTTPS @@ -47,7 +47,7 @@ Some of the tools you could use as a TLS Termination Proxy are: * With an external component like cert-manager for certificate renewals * Handled internally by a cloud provider as part of their services (read below 👇) -Another option is that you could use a **cloud service** that does more of the work including setting up HTTPS. It could have some restrictions or charge you more, etc. But in that case you wouldn't have to set up a TLS Termination Proxy yourself. +Another option is that you could use a **cloud service** that does more of the work including setting up HTTPS. It could have some restrictions or charge you more, etc. But in that case, you wouldn't have to set up a TLS Termination Proxy yourself. I'll show you some concrete examples in the next chapters. @@ -64,7 +64,7 @@ We will talk a lot about the running "**process**", so it's useful to have clari The word **program** is commonly used to describe many things: * The **code** that you write, the **Python files**. -* The **file** that can be **executed** by the operating system, for example `python`, `python.exe` or `uvicorn`. +* The **file** that can be **executed** by the operating system, for example: `python`, `python.exe` or `uvicorn`. * A particular program while it is **running** on the operating system, using the CPU, and storing things on memory. This is also called a **process**. ### What is a Process @@ -75,7 +75,7 @@ The word **process** is normally used in a more specific way, only referring to * This doesn't refer to the file, nor to the code, it refers **specifically** to the thing that is being **executed** and managed by the operating system. * Any program, any code, **can only do things** when it is being **executed**. So, when there's a **process running**. * The process can be **terminated** (or "killed") by you, or by the operating system. At that point, it stops running/being executed, and it can **no longer do things**. -* Each application that you have running in your computer has some process behind it, each running program, each window, etc. And there are normally many processes running **at the same time** while a computer is on. +* Each application that you have running on your computer has some process behind it, each running program, each window, etc. And there are normally many processes running **at the same time** while a computer is on. * There can be **multiple processes** of the **same program** running at the same time. If you check out the "task manager" or "system monitor" (or similar tools) in your operating system, you will be able to see many of those processes running. @@ -90,13 +90,13 @@ Now that we know the difference between the terms **process** and **program**, l ## Running on Startup -In most cases, when you create a web API, you want it to be **always running**, uninterrupted, so that your clients can always access it. This is of course, unless you have a specific reason why you want it to run only on certain situations, but most of the time you want it constantly running and **available**. +In most cases, when you create a web API, you want it to be **always running**, uninterrupted, so that your clients can always access it. This is of course, unless you have a specific reason why you want it to run only in certain situations, but most of the time you want it constantly running and **available**. ### In a Remote Server When you set up a remote server (a cloud server, a virtual machine, etc.) the simplest thing you can do is to run Uvicorn (or similar) manually, the same way you do when developing locally. -And it will work, and will be useful **during development**. +And it will work and will be useful **during development**. But if your connection to the server is lost, the **running process** will probably die. @@ -108,7 +108,7 @@ In general, you will probably want the server program (e.g. Uvicorn) to be start ### Separate Program -To achieve this, you will normally have a **separate program** that would make sure your application is run on startup. And in many cases it would also make sure other components or applications are also run, for example a database. +To achieve this, you will normally have a **separate program** that would make sure your application is run on startup. And in many cases, it would also make sure other components or applications are also run, for example, a database. ### Example Tools to Run at Startup @@ -177,7 +177,7 @@ For example, this could be handled by: With a FastAPI application, using a server program like Uvicorn, running it once in **one process** can serve multiple clients concurrently. -But in many cases you will want to run several worker processes at the same time. +But in many cases, you will want to run several worker processes at the same time. ### Multiple Processes - Workers @@ -197,11 +197,11 @@ So, to be able to have **multiple processes** at the same time, there has to be Now, when the program loads things in memory, for example, a machine learning model in a variable, or the contents of a large file in a variable, all that **consumes a bit of the memory (RAM)** of the server. -And multiple processes normally **don't share any memory**. This means that each running process has its own things, its own variables, its own memory. And if you are consuming a large amount of memory in your code, **each process** will consume an equivalent amount of memory. +And multiple processes normally **don't share any memory**. This means that each running process has its own things, variables, and memory. And if you are consuming a large amount of memory in your code, **each process** will consume an equivalent amount of memory. ### Server Memory -For example, if your code loads a Machine Learning model with **1 GB in size**, when you run one process with your API, it will consume at least 1 GB or RAM. And if you start **4 processes** (4 workers), each will consume 1 GB of RAM. So, in total your API will consume **4 GB of RAM**. +For example, if your code loads a Machine Learning model with **1 GB in size**, when you run one process with your API, it will consume at least 1 GB of RAM. And if you start **4 processes** (4 workers), each will consume 1 GB of RAM. So in total, your API will consume **4 GB of RAM**. And if your remote server or virtual machine only has 3 GB of RAM, trying to load more than 4 GB of RAM will cause problems. 🚨 @@ -253,12 +253,12 @@ But in most cases, you will want to perform these steps only **once**. So, you will want to have a **single process** to perform those **previous steps**, before starting the application. -And you will have to make sure that it's a single process running those previous steps *even* if afterwards you start **multiple processes** (multiple workers) for the application itself. If those steps were run by **multiple processes**, they would **duplicate** the work by running it on **parallel**, and if the steps were something delicate like a database migration, they could cause conflicts with each other. +And you will have to make sure that it's a single process running those previous steps *even* if afterwards, you start **multiple processes** (multiple workers) for the application itself. If those steps were run by **multiple processes**, they would **duplicate** the work by running it on **parallel**, and if the steps were something delicate like a database migration, they could cause conflicts with each other. -Of course, there are some cases where there's no problem in running the previous steps multiple times, in that case it's a lot easier to handle. +Of course, there are some cases where there's no problem in running the previous steps multiple times, in that case, it's a lot easier to handle. !!! tip - Also have in mind that depending on your setup, in some cases you **might not even need any previous steps** before starting your application. + Also, have in mind that depending on your setup, in some cases you **might not even need any previous steps** before starting your application. In that case, you wouldn't have to worry about any of this. 🤷 @@ -279,7 +279,7 @@ Here are some possible ideas: Your server(s) is (are) a **resource**, you can consume or **utilize**, with your programs, the computation time on the CPUs, and the RAM memory available. -How much resources do you want to be consuming/utilizing? It might be easy to think "not much", but in reality, you will probably want to consume **as much as possible without crashing**. +How much of the system resources do you want to be consuming/utilizing? It might be easy to think "not much", but in reality, you will probably want to consume **as much as possible without crashing**. If you are paying for 3 servers but you are using only a little bit of their RAM and CPU, you are probably **wasting money** 💸, and probably **wasting server electric power** 🌎, etc. @@ -291,9 +291,9 @@ In this case, it would be better to get **one extra server** and run some proces There's also the chance that for some reason you have a **spike** of usage of your API. Maybe it went viral, or maybe some other services or bots start using it. And you might want to have extra resources to be safe in those cases. -You could put an **arbitrary number** to target, for example something **between 50% to 90%** of resource utilization. The point is that those are probably the main things you will want to measure and use to tweak your deployments. +You could put an **arbitrary number** to target, for example, something **between 50% to 90%** of resource utilization. The point is that those are probably the main things you will want to measure and use to tweak your deployments. -You can use simple tools like `htop` to see the CPU and RAM used in your server, or the amount used by each process. Or you can use more complex monitoring tools, maybe distributed across servers, etc. +You can use simple tools like `htop` to see the CPU and RAM used in your server or the amount used by each process. Or you can use more complex monitoring tools, which may be distributed across servers, etc. ## Recap @@ -308,4 +308,4 @@ You have been reading here some of the main concepts that you would probably nee Understanding these ideas and how to apply them should give you the intuition necessary to take any decisions when configuring and tweaking your deployments. 🤓 -In the next sections I'll give you more concrete examples of possible strategies you can follow. 🚀 +In the next sections, I'll give you more concrete examples of possible strategies you can follow. 🚀 diff --git a/docs/en/docs/deployment/deta.md b/docs/en/docs/deployment/deta.md index b0d1cb928..c0dc3336a 100644 --- a/docs/en/docs/deployment/deta.md +++ b/docs/en/docs/deployment/deta.md @@ -9,7 +9,7 @@ It will take you about **10 minutes**. ## A basic **FastAPI** app -* Create a directory for your app, for example `./fastapideta/` and enter in it. +* Create a directory for your app, for example, `./fastapideta/` and enter into it. ### FastAPI code @@ -213,7 +213,7 @@ Now you can share that URL with anyone and they will be able to access your API. Congrats! You deployed your FastAPI app to Deta! 🎉 🍰 -Also notice that Deta correctly handles HTTPS for you, so you don't have to take care of that and can be sure that your clients will have a secure encrypted connection. ✅ 🔒 +Also, notice that Deta correctly handles HTTPS for you, so you don't have to take care of that and can be sure that your clients will have a secure encrypted connection. ✅ 🔒 ## Check the Visor @@ -235,7 +235,7 @@ You can also edit them and re-play them. ## Learn more -At some point you will probably want to store some data for your app in a way that persists through time. For that you can use Deta Base, it also has a generous **free tier**. +At some point, you will probably want to store some data for your app in a way that persists through time. For that you can use Deta Base, it also has a generous **free tier**. You can also read more in the Deta Docs. @@ -253,6 +253,6 @@ Coming back to the concepts we discussed in [Deployments Concepts](./concepts.md !!! note Deta is designed to make it easy (and free) to deploy simple applications quickly. - It can simplify a lot several use cases, but at the same time it doesn't support others, like using external databases (apart from Deta's own NoSQL database system), custom virtual machines, etc. + It can simplify several use cases, but at the same time, it doesn't support others, like using external databases (apart from Deta's own NoSQL database system), custom virtual machines, etc. You can read more details in the Deta docs to see if it's the right choice for you. diff --git a/docs/en/docs/deployment/docker.md b/docs/en/docs/deployment/docker.md index e25401f20..3f86efcce 100644 --- a/docs/en/docs/deployment/docker.md +++ b/docs/en/docs/deployment/docker.md @@ -1,6 +1,6 @@ # FastAPI in Containers - Docker -When deploying FastAPI applications a common approach is to build a **Linux container image**. It's normally done using **Docker**. And then you can deploy that container image in one of different possible ways. +When deploying FastAPI applications a common approach is to build a **Linux container image**. It's normally done using **Docker**. You can then deploy that container image in one of a few possible ways. Using Linux containers has several advantages including **security**, **replicability**, **simplicity**, and others. @@ -68,13 +68,13 @@ And there are many other images for different things like databases, for example * MongoDB * Redis, etc. -By using a pre-made container image it's very easy to **combine** and use different tools. For example, to try out a new database. In most cases you can use the **official images**, and just configure them with environment variables. +By using a pre-made container image it's very easy to **combine** and use different tools. For example, to try out a new database. In most cases, you can use the **official images**, and just configure them with environment variables. That way, in many cases you can learn about containers and Docker and re-use that knowledge with many different tools and components. So, you would run **multiple containers** with different things, like a database, a Python application, a web server with a React frontend application, and connect them together via their internal network. -All the container management systems (like Docker or Kubernetes) have these networking features integrated in them. +All the container management systems (like Docker or Kubernetes) have these networking features integrated into them. ## Containers and Processes @@ -84,7 +84,7 @@ When a **container** is started, it will run that command/program (although you A container is running as long as the **main process** (command or program) is running. -A container normally has a **single process**, but it's also possible to start subprocesses from the main process, and that way have **multiple processes** in the same container. +A container normally has a **single process**, but it's also possible to start subprocesses from the main process, and that way you will have **multiple processes** in the same container. But it's not possible to have a running container without **at least one running process**. If the main process stops, the container stops. @@ -137,7 +137,7 @@ Successfully installed fastapi pydantic uvicorn ### Create the **FastAPI** Code -* Create an `app` directory and enter in it. +* Create an `app` directory and enter it. * Create an empty file `__init__.py`. * Create a `main.py` file with: @@ -216,7 +216,7 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] 6. Set the **command** to run the `uvicorn` server. - `CMD` takes a list of strings, each of this strings is what you would type in the command line separated by spaces. + `CMD` takes a list of strings, each of these strings is what you would type in the command line separated by spaces. This command will be run from the **current working directory**, the same `/code` directory you set above with `WORKDIR /code`. @@ -338,7 +338,7 @@ You will see the alternative automatic documentation (provided by cluster of machines with **Kubernetes**, Docker Swarm Mode, Nomad, or other similar complex system to manage distributed containers on multiple machines, then you will probably want to **handle replication** at the **cluster level** instead of using a **process manager** (like Gunicorn with workers) in each container. +If you have a cluster of machines with **Kubernetes**, Docker Swarm Mode, Nomad, or another similar complex system to manage distributed containers on multiple machines, then you will probably want to **handle replication** at the **cluster level** instead of using a **process manager** (like Gunicorn with workers) in each container. One of those distributed container management systems like Kubernetes normally has some integrated way of handling **replication of containers** while still supporting **load balancing** for the incoming requests. All at the **cluster level**. @@ -487,7 +487,7 @@ The main point is, **none** of these are **rules written in stone** that you hav ## Memory -If you run **a single process per container** you will have a more or less well defined, stable, and limited amount of memory consumed by each of of those containers (more than one if they are replicated). +If you run **a single process per container** you will have a more or less well-defined, stable, and limited amount of memory consumed by each of those containers (more than one if they are replicated). And then you can set those same memory limits and requirements in your configurations for your container management system (for example in **Kubernetes**). That way it will be able to **replicate the containers** in the **available machines** taking into account the amount of memory needed by them, and the amount available in the machines in the cluster. diff --git a/docs/en/docs/deployment/https.md b/docs/en/docs/deployment/https.md index 1a3b1a0aa..790976a71 100644 --- a/docs/en/docs/deployment/https.md +++ b/docs/en/docs/deployment/https.md @@ -187,4 +187,4 @@ Having **HTTPS** is very important, and quite **critical** in most cases. Most o But once you know the basic information of **HTTPS for developers** you can easily combine and configure different tools to help you manage everything in a simple way. -In some of the next chapters I'll show you several concrete examples of how to set up **HTTPS** for **FastAPI** applications. 🔒 +In some of the next chapters, I'll show you several concrete examples of how to set up **HTTPS** for **FastAPI** applications. 🔒 diff --git a/docs/en/docs/deployment/index.md b/docs/en/docs/deployment/index.md index d1941ad93..f0fd001cd 100644 --- a/docs/en/docs/deployment/index.md +++ b/docs/en/docs/deployment/index.md @@ -8,7 +8,7 @@ To **deploy** an application means to perform the necessary steps to make it **a For a **web API**, it normally involves putting it in a **remote machine**, with a **server program** that provides good performance, stability, etc, so that your **users** can **access** the application efficiently and without interruptions or problems. -This is in contrast to the the **development** stages, where you are constantly changing the code, breaking it and fixing it, stopping and restarting the development server, etc. +This is in contrast to the **development** stages, where you are constantly changing the code, breaking it and fixing it, stopping and restarting the development server, etc. ## Deployment Strategies diff --git a/docs/en/docs/deployment/server-workers.md b/docs/en/docs/deployment/server-workers.md index 84a2b0f33..4ccd9d9f6 100644 --- a/docs/en/docs/deployment/server-workers.md +++ b/docs/en/docs/deployment/server-workers.md @@ -20,7 +20,7 @@ Here I'll show you how to use Pydantic veri doğrulaması yapmak için bir Python kütüphanesidir. + +Verilerin "biçimini" niteliklere sahip sınıflar olarak düzenlersiniz. + +Ve her niteliğin bir türü vardır. + +Sınıfın bazı değerlerle bir örneğini oluşturursunuz ve değerleri doğrular, bunları uygun türe dönüştürür ve size tüm verileri içeren bir nesne verir. + +Ve ortaya çıkan nesne üzerindeki bütün editör desteğini alırsınız. + +Resmi Pydantic dokümanlarından alınmıştır: + +```Python +{!../../../docs_src/python_types/tutorial011.py!} +``` + +!!! info + Daha fazla şey öğrenmek için Pydantic'i takip edin. + +**FastAPI** tamamen Pydantic'e dayanmaktadır. + +Daha fazlasini görmek için [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}. + +## **FastAPI** tip belirteçleri + +**FastAPI** birkaç şey yapmak için bu tür tip belirteçlerinden faydalanır. + +**FastAPI** ile parametre tiplerini bildirirsiniz ve şunları elde edersiniz: + +* **Editor desteği**. +* **Tip kontrolü**. + +...ve **FastAPI** aynı belirteçleri şunlar için de kullanıyor: + +* **Gereksinimleri tanımlama**: request path parameters, query parameters, headers, bodies, dependencies, ve benzeri gereksinimlerden +* **Verileri çevirme**: Gönderilen veri tipinden istenilen veri tipine çevirme. +* **Verileri doğrulama**: Her gönderilen verinin: + * doğrulanması ve geçersiz olduğunda **otomatik hata** oluşturma. +* OpenAPI kullanarak apinizi **Belgeleyin** : + * bu daha sonra otomatik etkileşimli dokümantasyon kullanıcı arayüzü tarafından kullanılır. + +Bütün bunlar kulağa soyut gelebilir. Merak etme. Tüm bunları çalışırken göreceksiniz. [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}. + +Önemli olan, standart Python türlerini tek bir yerde kullanarak (daha fazla sınıf, dekoratör vb. eklemek yerine), **FastAPI**'nin bizim için işi yapmasını sağlamak. + +!!! info + Tüm öğreticiyi zaten okuduysanız ve türler hakkında daha fazla bilgi için geri döndüyseniz, iyi bir kaynak: the "cheat sheet" from `mypy`. diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 6fe2b0b62..5ef8fd6a7 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -57,6 +57,7 @@ nav: - zh: /zh/ - features.md - fastapi-people.md +- python-types.md markdown_extensions: - toc: permalink: true From 3c93e803d55b67701f14c25a6da8d9b1f5291696 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 26 Oct 2021 18:14:17 +0000 Subject: [PATCH 302/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 31953a786..e2e00f912 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Turkish translation for `docs/python-types.md`. PR [#3926](https://github.com/tiangolo/fastapi/pull/3926) by [@BilalAlpaslan](https://github.com/BilalAlpaslan). ## 0.70.0 From a859497a72a11e9545ca84a1f87b423a0b9f1cca Mon Sep 17 00:00:00 2001 From: Sam Courtemanche Date: Tue, 26 Oct 2021 20:15:30 +0200 Subject: [PATCH 303/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20`docs/tutorial/query-params.md`=20(#3556)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ruidy --- docs/fr/docs/tutorial/query-params.md | 198 ++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 199 insertions(+) create mode 100644 docs/fr/docs/tutorial/query-params.md diff --git a/docs/fr/docs/tutorial/query-params.md b/docs/fr/docs/tutorial/query-params.md new file mode 100644 index 000000000..f1f2a605d --- /dev/null +++ b/docs/fr/docs/tutorial/query-params.md @@ -0,0 +1,198 @@ +# Paramètres de requête + +Quand vous déclarez des paramètres dans votre fonction de chemin qui ne font pas partie des paramètres indiqués dans le chemin associé, ces paramètres sont automatiquement considérés comme des paramètres de "requête". + +```Python hl_lines="9" +{!../../../docs_src/query_params/tutorial001.py!} +``` + +La partie appelée requête (ou **query**) dans une URL est l'ensemble des paires clés-valeurs placées après le `?` , séparées par des `&`. + +Par exemple, dans l'URL : + +``` +http://127.0.0.1:8000/items/?skip=0&limit=10 +``` + +...les paramètres de requête sont : + +* `skip` : avec une valeur de`0` +* `limit` : avec une valeur de `10` + +Faisant partie de l'URL, ces valeurs sont des chaînes de caractères (`str`). + +Mais quand on les déclare avec des types Python (dans l'exemple précédent, en tant qu'`int`), elles sont converties dans les types renseignés. + +Toutes les fonctionnalités qui s'appliquent aux paramètres de chemin s'appliquent aussi aux paramètres de requête : + +* Support de l'éditeur : vérification d'erreurs, auto-complétion, etc. +* "Parsing" de données. +* Validation de données. +* Annotations d'API et documentation automatique. + +## Valeurs par défaut + +Les paramètres de requête ne sont pas une partie fixe d'un chemin, ils peuvent être optionnels et avoir des valeurs par défaut. + +Dans l'exemple ci-dessus, ils ont des valeurs par défaut qui sont `skip=0` et `limit=10`. + +Donc, accéder à l'URL : + +``` +http://127.0.0.1:8000/items/ +``` + +serait équivalent à accéder à l'URL : + +``` +http://127.0.0.1:8000/items/?skip=0&limit=10 +``` + +Mais si vous accédez à, par exemple : + +``` +http://127.0.0.1:8000/items/?skip=20 +``` + +Les valeurs des paramètres de votre fonction seront : + +* `skip=20` : car c'est la valeur déclarée dans l'URL. +* `limit=10` : car `limit` n'a pas été déclaré dans l'URL, et que la valeur par défaut était `10`. + +## Paramètres optionnels + +De la même façon, vous pouvez définir des paramètres de requête comme optionnels, en leur donnant comme valeur par défaut `None` : + +```Python hl_lines="9" +{!../../../docs_src/query_params/tutorial002.py!} +``` + +Ici, le paramètre `q` sera optionnel, et aura `None` comme valeur par défaut. + +!!! check "Remarque" + On peut voir que **FastAPI** est capable de détecter que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` n'en est pas un, c'est donc un paramètre de requête. + +!!! note + **FastAPI** saura que `q` est optionnel grâce au `=None`. + + Le `Optional` dans `Optional[str]` n'est pas utilisé par **FastAPI** (**FastAPI** n'en utilisera que la partie `str`), mais il servira tout de même à votre editeur de texte pour détecter des erreurs dans votre code. + + +## Conversion des types des paramètres de requête + +Vous pouvez aussi déclarer des paramètres de requête comme booléens (`bool`), **FastAPI** les convertira : + +```Python hl_lines="9" +{!../../../docs_src/query_params/tutorial003.py!} +``` + +Avec ce code, en allant sur : + +``` +http://127.0.0.1:8000/items/foo?short=1 +``` + +ou + +``` +http://127.0.0.1:8000/items/foo?short=True +``` + +ou + +``` +http://127.0.0.1:8000/items/foo?short=true +``` + +ou + +``` +http://127.0.0.1:8000/items/foo?short=on +``` + +ou + +``` +http://127.0.0.1:8000/items/foo?short=yes +``` + +ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la première lettre en majuscule, etc.), votre fonction considérera le paramètre `short` comme ayant une valeur booléenne à `True`. Sinon la valeur sera à `False`. + +## Multiples paramètres de chemin et de requête + +Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête dans la même fonction, **FastAPI** saura comment les gérer. + +Et vous n'avez pas besoin de les déclarer dans un ordre spécifique. + +Ils seront détectés par leurs noms : + +```Python hl_lines="8 10" +{!../../../docs_src/query_params/tutorial004.py!} +``` + +## Paramètres de requête requis + +Quand vous déclarez une valeur par défaut pour un paramètre qui n'est pas un paramètre de chemin (actuellement, nous n'avons vu que les paramètres de requête), alors ce paramètre n'est pas requis. + +Si vous ne voulez pas leur donner de valeur par défaut mais juste les rendre optionnels, utilisez `None` comme valeur par défaut. + +Mais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez juste ne pas y affecter de valeur par défaut : + +```Python hl_lines="6-7" +{!../../../docs_src/query_params/tutorial005.py!} +``` + +Ici le paramètre `needy` est un paramètre requis (ou obligatoire) de type `str`. + +Si vous ouvrez une URL comme : + +``` +http://127.0.0.1:8000/items/foo-item +``` + +...sans ajouter le paramètre requis `needy`, vous aurez une erreur : + +```JSON +{ + "detail": [ + { + "loc": [ + "query", + "needy" + ], + "msg": "field required", + "type": "value_error.missing" + } + ] +} +``` + +La présence de `needy` étant nécessaire, vous auriez besoin de l'insérer dans l'URL : + +``` +http://127.0.0.1:8000/items/foo-item?needy=sooooneedy +``` + +...ce qui fonctionnerait : + +```JSON +{ + "item_id": "foo-item", + "needy": "sooooneedy" +} +``` + +Et bien sur, vous pouvez définir certains paramètres comme requis, certains avec des valeurs par défaut et certains entièrement optionnels : + +```Python hl_lines="10" +{!../../../docs_src/query_params/tutorial006.py!} +``` + +Ici, on a donc 3 paramètres de requête : + +* `needy`, requis et de type `str`. +* `skip`, un `int` avec comme valeur par défaut `0`. +* `limit`, un `int` optionnel. + +!!! tip "Astuce" + Vous pouvez utiliser les `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#valeurs-predefinies){.internal-link target=_blank}. diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 940e4ff69..4973d170e 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -59,6 +59,7 @@ nav: - fastapi-people.md - python-types.md - Tutoriel - Guide utilisateur: + - tutorial/query-params.md - tutorial/body.md - tutorial/background-tasks.md - async.md From b2c9574fc60bd5fa6606851f29d03f6b32facbe8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 26 Oct 2021 18:16:12 +0000 Subject: [PATCH 304/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e2e00f912..38791f2a1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for `docs/tutorial/query-params.md`. PR [#3556](https://github.com/tiangolo/fastapi/pull/3556) by [@Smlep](https://github.com/Smlep). * 🌐 Add Turkish translation for `docs/python-types.md`. PR [#3926](https://github.com/tiangolo/fastapi/pull/3926) by [@BilalAlpaslan](https://github.com/BilalAlpaslan). ## 0.70.0 From 0d5e0ba5d590ca8de7814ae4ad926c891033530f Mon Sep 17 00:00:00 2001 From: Sam Courtemanche Date: Tue, 26 Oct 2021 20:33:34 +0200 Subject: [PATCH 305/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20`docs/tutorial/path-params.md`=20(#3548)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/fr/docs/tutorial/path-params.md | 254 +++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 255 insertions(+) create mode 100644 docs/fr/docs/tutorial/path-params.md diff --git a/docs/fr/docs/tutorial/path-params.md b/docs/fr/docs/tutorial/path-params.md new file mode 100644 index 000000000..58f53e008 --- /dev/null +++ b/docs/fr/docs/tutorial/path-params.md @@ -0,0 +1,254 @@ +# Paramètres de chemin + +Vous pouvez déclarer des "paramètres" ou "variables" de chemin avec la même syntaxe que celle utilisée par le +formatage de chaîne Python : + + +```Python hl_lines="6-7" +{!../../../docs_src/path_params/tutorial001.py!} +``` + +La valeur du paramètre `item_id` sera transmise à la fonction dans l'argument `item_id`. + +Donc, si vous exécutez cet exemple et allez sur http://127.0.0.1:8000/items/foo, +vous verrez comme réponse : + +```JSON +{"item_id":"foo"} +``` + +## Paramètres de chemin typés + +Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type Python : + + +```Python hl_lines="7" +{!../../../docs_src/path_params/tutorial002.py!} +``` + +Ici, `item_id` est déclaré comme `int`. + +!!! hint "Astuce" + Ceci vous permettra d'obtenir des fonctionnalités de l'éditeur dans votre fonction, telles + que des vérifications d'erreur, de l'auto-complétion, etc. + +## Conversion de données + +Si vous exécutez cet exemple et allez sur http://127.0.0.1:8000/items/3, vous aurez comme réponse : + +```JSON +{"item_id":3} +``` + +!!! hint "Astuce" + Comme vous l'avez remarqué, la valeur reçue par la fonction (et renvoyée ensuite) est `3`, + en tant qu'entier (`int`) Python, pas la chaîne de caractères (`string`) `"3"`. + + Grâce aux déclarations de types, **FastAPI** fournit du + "parsing" automatique. + +## Validation de données + +Si vous allez sur http://127.0.0.1:8000/items/foo, vous aurez une belle erreur HTTP : + +```JSON +{ + "detail": [ + { + "loc": [ + "path", + "item_id" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ] +} +``` + +car le paramètre de chemin `item_id` possède comme valeur `"foo"`, qui ne peut pas être convertie en entier (`int`). + +La même erreur se produira si vous passez un nombre flottant (`float`) et non un entier, comme ici +http://127.0.0.1:8000/items/4.2. + + +!!! hint "Astuce" + Donc, avec ces mêmes déclarations de type Python, **FastAPI** vous fournit de la validation de données. + + Notez que l'erreur mentionne le point exact où la validation n'a pas réussi. + + Ce qui est incroyablement utile au moment de développer et débugger du code qui interagit avec votre API. + +## Documentation + +Et quand vous vous rendez sur http://127.0.0.1:8000/docs, vous verrez la +documentation générée automatiquement et interactive : + + + +!!! info + À nouveau, en utilisant uniquement les déclarations de type Python, **FastAPI** vous fournit automatiquement une documentation interactive (via Swagger UI). + + On voit bien dans la documentation que `item_id` est déclaré comme entier. + +## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative. + +Le schéma généré suivant la norme OpenAPI, +il existe de nombreux outils compatibles. + +Grâce à cela, **FastAPI** lui-même fournit une documentation alternative (utilisant ReDoc), qui peut être lue +sur http://127.0.0.1:8000/redoc : + + + +De la même façon, il existe bien d'autres outils compatibles, y compris des outils de génération de code +pour de nombreux langages. + +## Pydantic + +Toute la validation de données est effectué en arrière-plan avec Pydantic, +dont vous bénéficierez de tous les avantages. Vous savez donc que vous êtes entre de bonnes mains. + +## L'ordre importe + +Quand vous créez des *fonctions de chemins*, vous pouvez vous retrouver dans une situation où vous avez un chemin fixe. + +Tel que `/users/me`, disons pour récupérer les données sur l'utilisateur actuel. + +Et vous avez un second chemin : `/users/{user_id}` pour récupérer de la donnée sur un utilisateur spécifique grâce à son identifiant d'utilisateur + +Les *fonctions de chemin* étant évaluées dans l'ordre, il faut s'assurer que la fonction correspondant à `/users/me` est déclarée avant celle de `/users/{user_id}` : + +```Python hl_lines="6 11" +{!../../../docs_src/path_params/tutorial003.py!} +``` + +Sinon, le chemin `/users/{user_id}` correspondrait aussi à `/users/me`, la fonction "croyant" qu'elle a reçu un paramètre `user_id` avec pour valeur `"me"`. + +## Valeurs prédéfinies + +Si vous avez une *fonction de chemin* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs possibles des paramètres soient prédéfinies, vous pouvez utiliser les `Enum` de Python. + +### Création d'un `Enum` + +Importez `Enum` et créez une sous-classe qui hérite de `str` et `Enum`. + +En héritant de `str` la documentation sera capable de savoir que les valeurs doivent être de type `string` et pourra donc afficher cette `Enum` correctement. + +Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs autorisées pour cette énumération. + +```Python hl_lines="1 6-9" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +!!! info + Les énumérations (ou enums) sont disponibles en Python depuis la version 3.4. + +!!! tip "Astuce" + Pour ceux qui se demandent, "AlexNet", "ResNet", et "LeNet" sont juste des noms de modèles de Machine Learning. + +### Déclarer un paramètre de chemin + +Créez ensuite un *paramètre de chemin* avec une annotation de type désignant l'énumération créée précédemment (`ModelName`) : + +```Python hl_lines="16" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +### Documentation + +Les valeurs disponibles pour le *paramètre de chemin* sont bien prédéfinies, la documentation les affiche correctement : + + + +### Manipuler les *énumérations* Python + +La valeur du *paramètre de chemin* sera un des "membres" de l'énumération. + +#### Comparer les *membres d'énumération* + +Vous pouvez comparer ce paramètre avec les membres de votre énumération `ModelName` : + +```Python hl_lines="17" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +#### Récupérer la *valeur de l'énumération* + +Vous pouvez obtenir la valeur réel d'un membre (une chaîne de caractères ici), avec `model_name.value`, ou en général, `votre_membre_d'enum.value` : + +```Python hl_lines="20" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +!!! tip "Astuce" + Vous pouvez aussi accéder la valeur `"lenet"` avec `ModelName.lenet.value`. + +#### Retourner des *membres d'énumération* + +Vous pouvez retourner des *membres d'énumération* dans vos *fonctions de chemin*, même imbriquée dans un JSON (e.g. un `dict`). + +Ils seront convertis vers leurs valeurs correspondantes (chaînes de caractères ici) avant d'être transmis au client : + +```Python hl_lines="18 21 23" +{!../../../docs_src/path_params/tutorial005.py!} +``` + +Le client recevra une réponse JSON comme celle-ci : + +```JSON +{ + "model_name": "alexnet", + "message": "Deep Learning FTW!" +} +``` + +## Paramètres de chemin contenant des chemins + +Disons que vous avez une *fonction de chemin* liée au chemin `/files/{file_path}`. + +Mais que `file_path` lui-même doit contenir un *chemin*, comme `home/johndoe/myfile.txt` par exemple. + +Donc, l'URL pour ce fichier pourrait être : `/files/home/johndoe/myfile.txt`. + +### Support d'OpenAPI + +OpenAPI ne supporte pas de manière de déclarer un paramètre de chemin contenant un *chemin*, cela pouvant causer des scénarios difficiles à tester et définir. + +Néanmoins, cela reste faisable dans **FastAPI**, via les outils internes de Starlette. + +Et la documentation fonctionne quand même, bien qu'aucune section ne soit ajoutée pour dire que la paramètre devrait contenir un *chemin*. + +### Convertisseur de *chemin* + +En utilisant une option de Starlette directement, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme : + +``` +/files/{file_path:path} +``` + +Dans ce cas, le nom du paramètre est `file_path`, et la dernière partie, `:path`, indique à Starlette que le paramètre devrait correspondre à un *chemin*. + +Vous pouvez donc l'utilisez comme tel : + +```Python hl_lines="6" +{!../../../docs_src/path_params/tutorial004.py!} +``` + +!!! tip "Astuce" + Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash au début (`/`). + + Dans ce cas, l'URL serait : `/files//home/johndoe/myfile.txt`, avec un double slash (`//`) entre `files` et `home`. + +## Récapitulatif + +Avec **FastAPI**, en utilisant les déclarations de type rapides, intuitives et standards de Python, vous bénéficiez de : + +* Support de l'éditeur : vérification d'erreurs, auto-complétion, etc. +* "Parsing" de données. +* Validation de données. +* Annotations d'API et documentation automatique. + +Et vous n'avez besoin de le déclarer qu'une fois. + +C'est probablement l'avantage visible principal de **FastAPI** comparé aux autres *frameworks* (outre les performances pures). diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 4973d170e..01cf8d5e0 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -59,6 +59,7 @@ nav: - fastapi-people.md - python-types.md - Tutoriel - Guide utilisateur: + - tutorial/path-params.md - tutorial/query-params.md - tutorial/body.md - tutorial/background-tasks.md From 08410ca5688e81963d681cbeb8aeef69486942eb Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 26 Oct 2021 18:34:11 +0000 Subject: [PATCH 306/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 38791f2a1..d15ca6103 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for `docs/tutorial/path-params.md`. PR [#3548](https://github.com/tiangolo/fastapi/pull/3548) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for `docs/tutorial/query-params.md`. PR [#3556](https://github.com/tiangolo/fastapi/pull/3556) by [@Smlep](https://github.com/Smlep). * 🌐 Add Turkish translation for `docs/python-types.md`. PR [#3926](https://github.com/tiangolo/fastapi/pull/3926) by [@BilalAlpaslan](https://github.com/BilalAlpaslan). From 652cf4bb6bf82a03361838f098ccde358ca71c56 Mon Sep 17 00:00:00 2001 From: Sam Courtemanche Date: Tue, 26 Oct 2021 20:47:01 +0200 Subject: [PATCH 307/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20Tutorial=20-=20First=20steps=20(#3455)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/fr/docs/tutorial/first-steps.md | 334 +++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 335 insertions(+) create mode 100644 docs/fr/docs/tutorial/first-steps.md diff --git a/docs/fr/docs/tutorial/first-steps.md b/docs/fr/docs/tutorial/first-steps.md new file mode 100644 index 000000000..3a81362f6 --- /dev/null +++ b/docs/fr/docs/tutorial/first-steps.md @@ -0,0 +1,334 @@ +# Démarrage + +Le fichier **FastAPI** le plus simple possible pourrait ressembler à cela : + +```Python +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Copiez ce code dans un fichier nommé `main.py`. + +Démarrez le serveur : + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +!!! note + La commande `uvicorn main:app` fait référence à : + + * `main` : le fichier `main.py` (le module Python). + * `app` : l'objet créé dans `main.py` via la ligne `app = FastAPI()`. + * `--reload` : l'option disant à uvicorn de redémarrer le serveur à chaque changement du code. À ne pas utiliser en production ! + +Vous devriez voir dans la console, une ligne semblable à la suivante : + +```hl_lines="4" +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +Cette ligne montre l'URL par laquelle l'app est actuellement accessible, sur votre machine locale. + +### Allez voir le résultat + +Ouvrez votre navigateur à l'adresse http://127.0.0.1:8000. + +Vous obtiendrez cette réponse JSON : + +```JSON +{"message": "Hello World"} +``` + +### Documentation interactive de l'API + +Rendez-vous sur http://127.0.0.1:8000/docs. + +Vous verrez la documentation interactive de l'API générée automatiquement (via Swagger UI) : + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Documentation alternative + +Ensuite, rendez-vous sur http://127.0.0.1:8000/redoc. + +Vous y verrez la documentation alternative (via ReDoc) : + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +### OpenAPI + +**FastAPI** génère un "schéma" contenant toute votre API dans le standard de définition d'API **OpenAPI**. + +#### "Schéma" + +Un "schéma" est une définition ou une description de quelque chose. Pas le code qui l'implémente, uniquement une description abstraite. + +#### "Schéma" d'API + +Ici, OpenAPI est une spécification qui dicte comment définir le schéma de votre API. + +Le schéma inclut les chemins de votre API, les paramètres potentiels de chaque chemin, etc. + +#### "Schéma" de données + +Le terme "schéma" peut aussi faire référence à la forme de la donnée, comme un contenu JSON. + +Dans ce cas, cela signifierait les attributs JSON, ainsi que les types de ces attributs, etc. + +#### OpenAPI et JSON Schema + +**OpenAPI** définit un schéma d'API pour votre API. Il inclut des définitions (ou "schémas") de la donnée envoyée et reçue par votre API en utilisant **JSON Schema**, le standard des schémas de données JSON. + +#### Allez voir `openapi.json` + +Si vous êtes curieux d'à quoi ressemble le schéma brut **OpenAPI**, **FastAPI** génère automatiquement un (schéma) JSON avec les descriptions de toute votre API. + +Vous pouvez le voir directement à cette adresse : http://127.0.0.1:8000/openapi.json. + +Le schéma devrait ressembler à ceci : + + +```JSON +{ + "openapi": "3.0.2", + "info": { + "title": "FastAPI", + "version": "0.1.0" + }, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + + + +... +``` + +#### À quoi sert OpenAPI + +Le schéma **OpenAPI** est ce qui alimente les deux systèmes de documentation interactive. + +Et il existe des dizaines d'alternatives, toutes basées sur **OpenAPI**. Vous pourriez facilement ajouter n'importe laquelle de ces alternatives à votre application **FastAPI**. + +Vous pourriez aussi l'utiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Comme par exemple, des applications frontend, mobiles ou IOT. + +## Récapitulatif, étape par étape + +### Étape 1 : import `FastAPI` + +```Python hl_lines="1" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +`FastAPI` est une classe Python qui fournit toutes les fonctionnalités nécessaires au lancement de votre API. + +!!! note "Détails techniques" + `FastAPI` est une classe héritant directement de `Starlette`. + + Vous pouvez donc aussi utiliser toutes les fonctionnalités de Starlette depuis `FastAPI`. + +### Étape 2 : créer une "instance" `FastAPI` + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Ici la variable `app` sera une "instance" de la classe `FastAPI`. + +Ce sera le point principal d'interaction pour créer toute votre API. + +Cette `app` est la même que celle à laquelle fait référence `uvicorn` dans la commande : + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Si vous créez votre app avec : + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial002.py!} +``` + +Et la mettez dans un fichier `main.py`, alors vous appeleriez `uvicorn` avec : + +
+ +```console +$ uvicorn main:my_awesome_api --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +### Étape 3: créer une *opération de chemin* + +#### Chemin + +Chemin, ou "path" fait référence ici à la dernière partie de l'URL démarrant au premier `/`. + +Donc, dans un URL tel que : + +``` +https://example.com/items/foo +``` + +...le "path" serait : + +``` +/items/foo +``` + +!!! info + Un chemin, ou "path" est aussi souvent appelé route ou "endpoint". + + +#### Opération + +"Opération" fait référence à une des "méthodes" HTTP. + +Une de : + +* `POST` +* `GET` +* `PUT` +* `DELETE` + +...ou une des plus exotiques : + +* `OPTIONS` +* `HEAD` +* `PATCH` +* `TRACE` + +Dans le protocol HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plus) de ces "méthodes". + +--- + +En construisant des APIs, vous utilisez généralement ces méthodes HTTP spécifiques pour effectuer une action précise. + +Généralement vous utilisez : + +* `POST` : pour créer de la donnée. +* `GET` : pour lire de la donnée. +* `PUT` : pour mettre à jour de la donnée. +* `DELETE` : pour supprimer de la donnée. + +Donc, dans **OpenAPI**, chaque méthode HTTP est appelée une "opération". + +Nous allons donc aussi appeler ces dernières des "**opérations**". + + +#### Définir un *décorateur d'opération de chemin* + +```Python hl_lines="6" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Le `@app.get("/")` dit à **FastAPI** que la fonction en dessous est chargée de gérer les requêtes qui vont sur : + +* le chemin `/` +* en utilisant une opération get + +!!! info "`@décorateur` Info" + Cette syntaxe `@something` en Python est appelée un "décorateur". + + Vous la mettez au dessus d'une fonction. Comme un joli chapeau décoratif (j'imagine que ce terme vient de là 🤷🏻‍♂). + + Un "décorateur" prend la fonction en dessous et en fait quelque chose. + + Dans notre cas, ce décorateur dit à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec l'**opération** `get`. + + C'est le "**décorateur d'opération de chemin**". + +Vous pouvez aussi utiliser les autres opérations : + +* `@app.post()` +* `@app.put()` +* `@app.delete()` + +Tout comme celles les plus exotiques : + +* `@app.options()` +* `@app.head()` +* `@app.patch()` +* `@app.trace()` + +!!! tip "Astuce" + Vous êtes libres d'utiliser chaque opération (méthode HTTP) comme vous le désirez. + + **FastAPI** n'impose pas de sens spécifique à chacune d'elle. + + Les informations qui sont présentées ici forment une directive générale, pas des obligations. + + Par exemple, quand l'on utilise **GraphQL**, toutes les actions sont effectuées en utilisant uniquement des opérations `POST`. + +### Étape 4 : définir la **fonction de chemin**. + +Voici notre "**fonction de chemin**" (ou fonction d'opération de chemin) : + +* **chemin** : `/`. +* **opération** : `get`. +* **fonction** : la fonction sous le "décorateur" (sous `@app.get("/")`). + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +C'est une fonction Python. + +Elle sera appelée par **FastAPI** quand une requête sur l'URL `/` sera reçue via une opération `GET`. + +Ici, c'est une fonction asynchrone (définie avec `async def`). + +--- + +Vous pourriez aussi la définir comme une fonction classique plutôt qu'avec `async def` : + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial003.py!} +``` + +!!! note + Si vous ne connaissez pas la différence, allez voir la section [Concurrence : *"Vous êtes pressés ?"*](../async.md#vous-etes-presses){.internal-link target=_blank}. + +### Étape 5 : retourner le contenu + +```Python hl_lines="8" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Vous pouvez retourner un dictionnaire (`dict`), une liste (`list`), des valeurs seules comme des chaines de caractères (`str`) et des entiers (`int`), etc. + +Vous pouvez aussi retourner des models **Pydantic** (qui seront détaillés plus tard). + +Il y a de nombreux autres objets et modèles qui seront automatiquement convertis en JSON. Essayez d'utiliser vos favoris, il est fort probable qu'ils soient déjà supportés. + +## Récapitulatif + +* Importez `FastAPI`. +* Créez une instance d'`app`. +* Ajoutez une **décorateur d'opération de chemin** (tel que `@app.get("/")`). +* Ajoutez une **fonction de chemin** (telle que `def root(): ...` comme ci-dessus). +* Lancez le serveur de développement (avec `uvicorn main:app --reload`). diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 01cf8d5e0..6242a88fd 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -59,6 +59,7 @@ nav: - fastapi-people.md - python-types.md - Tutoriel - Guide utilisateur: + - tutorial/first-steps.md - tutorial/path-params.md - tutorial/query-params.md - tutorial/body.md From fb1f34123124641850d5cfbe1d247a654ab51586 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 26 Oct 2021 18:47:42 +0000 Subject: [PATCH 308/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d15ca6103..cec6c2749 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for Tutorial - First steps. PR [#3455](https://github.com/tiangolo/fastapi/pull/3455) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for `docs/tutorial/path-params.md`. PR [#3548](https://github.com/tiangolo/fastapi/pull/3548) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for `docs/tutorial/query-params.md`. PR [#3556](https://github.com/tiangolo/fastapi/pull/3556) by [@Smlep](https://github.com/Smlep). * 🌐 Add Turkish translation for `docs/python-types.md`. PR [#3926](https://github.com/tiangolo/fastapi/pull/3926) by [@BilalAlpaslan](https://github.com/BilalAlpaslan). From 0a61a6c8656da738ee6438c1fa927e3cbad64bdd Mon Sep 17 00:00:00 2001 From: "weekwith.me" <63915557+0417taehyun@users.noreply.github.com> Date: Wed, 27 Oct 2021 03:53:40 +0900 Subject: [PATCH 309/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20`docs/tutorial/?= =?UTF-8?q?dependencies/classes-as-dependencies`:=20Add=20type=20of=20quer?= =?UTF-8?q?y=20parameters=20in=20a=20description=20of=20`Classes=20as=20de?= =?UTF-8?q?pendencies`=20(#4015)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/tutorial/dependencies/classes-as-dependencies.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md index 8c00374bf..7747e3e1b 100644 --- a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md @@ -91,9 +91,9 @@ Those parameters are what **FastAPI** will use to "solve" the dependency. In both cases, it will have: -* an optional `q` query parameter. -* a `skip` query parameter, with a default of `0`. -* a `limit` query parameter, with a default of `100`. +* An optional `q` query parameter that is a `str`. +* A `skip` query parameter that is an `int`, with a default of `0`. +* A `limit` query parameter that is an `int`, with a default of `100`. In both cases the data will be converted, validated, documented on the OpenAPI schema, etc. From 58ab733f19846b4875c5b79bfb1f4d1cb7f4823f Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 26 Oct 2021 18:54:22 +0000 Subject: [PATCH 310/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index cec6c2749..72f2e9b58 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update `docs/tutorial/dependencies/classes-as-dependencies`: Add type of query parameters in a description of `Classes as dependencies`. PR [#4015](https://github.com/tiangolo/fastapi/pull/4015) by [@0417taehyun](https://github.com/0417taehyun). * 🌐 Add French translation for Tutorial - First steps. PR [#3455](https://github.com/tiangolo/fastapi/pull/3455) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for `docs/tutorial/path-params.md`. PR [#3548](https://github.com/tiangolo/fastapi/pull/3548) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for `docs/tutorial/query-params.md`. PR [#3556](https://github.com/tiangolo/fastapi/pull/3556) by [@Smlep](https://github.com/Smlep). From 146ff28d9cd226783aac1d65336ee694471455f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 8 Dec 2021 16:04:04 +0100 Subject: [PATCH 311/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20CryptAPI=20sponsor?= =?UTF-8?q?=20(#4264)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/en/data/sponsors.yml | 3 + docs/en/data/sponsors_badge.yml | 1 + docs/en/docs/img/sponsors/cryptapi-banner.svg | 1375 +++++++++++++++++ docs/en/docs/img/sponsors/cryptapi.svg | 1216 +++++++++++++++ docs/en/overrides/main.html | 6 + 6 files changed, 2602 insertions(+) create mode 100644 docs/en/docs/img/sponsors/cryptapi-banner.svg create mode 100644 docs/en/docs/img/sponsors/cryptapi.svg diff --git a/README.md b/README.md index 830031581..53de38bd9 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 4949e6c56..baa2e440d 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -2,6 +2,9 @@ gold: - url: https://bit.ly/2QSouzH title: "Jina: build neural search-as-a-service for any kind of data in just minutes." img: https://fastapi.tiangolo.com/img/sponsors/jina.svg + - url: https://cryptapi.io/ + title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway." + img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index 0496c6279..759748728 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -6,3 +6,4 @@ logins: - mikeckennedy - koaning - deepset-ai + - cryptapi diff --git a/docs/en/docs/img/sponsors/cryptapi-banner.svg b/docs/en/docs/img/sponsors/cryptapi-banner.svg new file mode 100644 index 000000000..29cd772da --- /dev/null +++ b/docs/en/docs/img/sponsors/cryptapi-banner.svg @@ -0,0 +1,1375 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/docs/img/sponsors/cryptapi.svg b/docs/en/docs/img/sponsors/cryptapi.svg new file mode 100644 index 000000000..db4e09347 --- /dev/null +++ b/docs/en/docs/img/sponsors/cryptapi.svg @@ -0,0 +1,1216 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index aa381faa3..70b0253bd 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -40,6 +40,12 @@
+
{% endblock %} From f282c0e20718e50063a4c4ea164e83f13d020872 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 8 Dec 2021 15:04:50 +0000 Subject: [PATCH 312/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 72f2e9b58..d37959dcc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add CryptAPI sponsor. PR [#4264](https://github.com/tiangolo/fastapi/pull/4264) by [@tiangolo](https://github.com/tiangolo). * 📝 Update `docs/tutorial/dependencies/classes-as-dependencies`: Add type of query parameters in a description of `Classes as dependencies`. PR [#4015](https://github.com/tiangolo/fastapi/pull/4015) by [@0417taehyun](https://github.com/0417taehyun). * 🌐 Add French translation for Tutorial - First steps. PR [#3455](https://github.com/tiangolo/fastapi/pull/3455) by [@Smlep](https://github.com/Smlep). * 🌐 Add French translation for `docs/tutorial/path-params.md`. PR [#3548](https://github.com/tiangolo/fastapi/pull/3548) by [@Smlep](https://github.com/Smlep). From dabb4898f140d98f5e5a4668fdbcd0361459fa8d Mon Sep 17 00:00:00 2001 From: kimjaeyoonn <87240205+kimjaeyoonn@users.noreply.github.com> Date: Thu, 9 Dec 2021 00:32:24 +0900 Subject: [PATCH 313/814] =?UTF-8?q?=F0=9F=8C=90=20Fix=20Korean=20translati?= =?UTF-8?q?on=20for=20`docs/ko/docs/tutorial/index.md`=20(#4193)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ko/docs/tutorial/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/ko/docs/tutorial/index.md b/docs/ko/docs/tutorial/index.md index a18a9ffc7..622aad1aa 100644 --- a/docs/ko/docs/tutorial/index.md +++ b/docs/ko/docs/tutorial/index.md @@ -2,11 +2,11 @@ 이 자습서는 **FastAPI**의 대부분의 기능을 단계별로 사용하는 방법을 보여줍니다. -각 섹션은 이전 섹션을 기반해서 점진적으로 만들어 졌지만, 주제를 구분하여 구성 되었기 때문에 특정 API 요구사항을 해결하기 위해 어떤 특정 항목이던지 직접 이동할 수 있습니다. +각 섹션은 이전 섹션을 기반해서 점진적으로 만들어 졌지만, 주제에 따라 다르게 구성되었기 때문에 특정 API 요구사항을 해결하기 위해서라면 어느 특정 항목으로던지 직접 이동할 수 있습니다. 또한 향후 참조가 될 수 있도록 만들어졌습니다. -그러므로 다시 돌아와서 정확히 필요한 것을 볼 수 있습니다. +그러므로 다시 돌아와서 정확히 필요한 것을 확인할 수 있습니다. ## 코드 실행하기 @@ -30,7 +30,7 @@ $ uvicorn main:app --reload 코드를 작성하거나 복사, 편집할 때, 로컬에서 실행하는 것을 **강력히 장려**합니다. -편집기에서 이렇게 사용하면, 모든 타입 검사, 자동완성 등 작성해야 하는 코드가 얼마나 적은지 보면서 FastAPI의 장점을 실제로 확인할 수 있습니다. +편집기에서 이렇게 사용한다면, 모든 타입 검사와 자동완성 등 작성해야 하는 코드가 얼마나 적은지 보면서 FastAPI의 장점을 실제로 확인할 수 있습니다. --- @@ -77,4 +77,4 @@ $ pip install fastapi[all] 하지만 (지금 읽고 있는) **자습서 - 사용자 안내서**를 먼저 읽는게 좋습니다. -**자습서 - 사용자 안내서**만으로 완전한 애플리케이션을 구축한 다음, **고급 사용자 안내서**의 몇 가지 추가 아이디어를 사용하여 필요에 따라 다양한 방식으로 확장할 수 있도록 설계되었습니다. +**자습서 - 사용자 안내서**만으로도 완전한 애플리케이션을 구축할 수 있으며, 필요에 따라 **고급 사용자 안내서**에서 제공하는 몇 가지 추가적인 기능을 사용하여 다양한 방식으로 확장할 수 있도록 설계되었습니다. From cace5a79f77c7518eecb92ab1909a7d14cf466ff Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 8 Dec 2021 15:33:09 +0000 Subject: [PATCH 314/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d37959dcc..efb84de47 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix Korean translation for `docs/ko/docs/tutorial/index.md`. PR [#4193](https://github.com/tiangolo/fastapi/pull/4193) by [@kimjaeyoonn](https://github.com/kimjaeyoonn). * 🔧 Add CryptAPI sponsor. PR [#4264](https://github.com/tiangolo/fastapi/pull/4264) by [@tiangolo](https://github.com/tiangolo). * 📝 Update `docs/tutorial/dependencies/classes-as-dependencies`: Add type of query parameters in a description of `Classes as dependencies`. PR [#4015](https://github.com/tiangolo/fastapi/pull/4015) by [@0417taehyun](https://github.com/0417taehyun). * 🌐 Add French translation for Tutorial - First steps. PR [#3455](https://github.com/tiangolo/fastapi/pull/3455) by [@Smlep](https://github.com/Smlep). From 446d194c4675e8b3e0f6315dce31af22a229aeca Mon Sep 17 00:00:00 2001 From: daehyeon kim <87962045+DevDae@users.noreply.github.com> Date: Thu, 9 Dec 2021 00:37:30 +0900 Subject: [PATCH 315/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Korean=20translati?= =?UTF-8?q?on=20for=20`docs/ko/docs/deployment/versions.md`=20(#4121)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: weekwith.me <63915557+0417taehyun@users.noreply.github.com> --- docs/ko/docs/deployment/versions.md | 88 +++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 docs/ko/docs/deployment/versions.md diff --git a/docs/ko/docs/deployment/versions.md b/docs/ko/docs/deployment/versions.md new file mode 100644 index 000000000..4c1bcdc2e --- /dev/null +++ b/docs/ko/docs/deployment/versions.md @@ -0,0 +1,88 @@ +# FastAPI 버전들에 대하여 + +**FastAPI** 는 이미 많은 응용 프로그램과 시스템들을 만드는데 사용되고 있습니다. 그리고 100%의 테스트 정확성을 가지고 있습니다. 하지만 이것은 아직까지도 빠르게 발전하고 있습니다. + +새로운 특징들이 빈번하게 추가되고, 오류들이 지속적으로 수정되고 있습니다. 그리고 코드가 계속적으로 향상되고 있습니다. + +이것이 아직도 최신 버전이 `0.x.x`인 이유입니다. 이것은 각각의 버전들이 잠재적으로 변할 수 있다는 것을 보여줍니다. 이는 유의적 버전 관습을 따릅니다. + +지금 바로 **FastAPI**로 응용 프로그램을 만들 수 있습니다. 이때 (아마 지금까지 그래 왔던 것처럼), 사용하는 버전이 코드와 잘 맞는지 확인해야합니다. + +## `fastapi` 버전을 표시 + +가장 먼저 해야할 것은 응용 프로그램이 잘 작동하는 가장 최신의 구체적인 **FastAPI** 버전을 표시하는 것입니다. + +예를 들어, 응용 프로그램에 `0.45.0` 버전을 사용했다고 가정합니다. + +만약에 `requirements.txt` 파일을 사용했다면, 다음과 같이 버전을 명세할 수 있습니다: + +```txt +fastapi==0.45.0 +``` + +이것은 `0.45.0` 버전을 사용했다는 것을 의미합니다. + +또는 다음과 같이 표시할 수 있습니다: + +```txt +fastapi>=0.45.0,<0.46.0 +``` + +이것은 `0.45.0` 버전과 같거나 높으면서 `0.46.0` 버전 보다는 낮은 버전을 사용했다는 것을 의미합니다. 예를 들어, `0.45.2` 버전과 같은 경우는 해당 조건을 만족합니다. + +만약에 Poetry, Pipenv, 또는 그밖의 다양한 설치 도구를 사용한다면, 패키지에 구체적인 버전을 정의할 수 있는 방법을 가지고 있을 것입니다. + +## 이용가능한 버전들 + +[Release Notes](../release-notes.md){.internal-link target=_blank}를 통해 사용할 수 있는 버전들을 확인할 수 있습니다.(예를 들어, 가장 최신의 버전을 확인할 수 있습니다.) + + +## 버전들에 대해 + +유의적 버전 관습을 따라서, `1.0.0` 이하의 모든 버전들은 잠재적으로 급변할 수 있습니다. + +FastAPI는 오류를 수정하고, 일반적인 변경사항을 위해 "패치"버전의 관습을 따릅니다. + +!!! tip "팁" + 여기서 말하는 "패치"란 버전의 마지막 숫자로, 예를 들어 `0.2.3` 버전에서 "패치"는 `3`을 의미합니다. + +따라서 다음과 같이 버전을 표시할 수 있습니다: + +```txt +fastapi>=0.45.0,<0.46.0 +``` + +수정된 사항과 새로운 요소들이 "마이너" 버전에 추가되었습니다. + +!!! tip "팁" + "마이너"란 버전 넘버의 가운데 숫자로, 예를 들어서 `0.2.3`의 "마이너" 버전은 `2`입니다. + +## FastAPI 버전의 업그레이드 + +응용 프로그램을 검사해야합니다. + +(Starlette 덕분에), **FastAPI** 를 이용하여 굉장히 쉽게 할 수 있습니다. [Testing](../tutorial/testing.md){.internal-link target=_blank}문서를 확인해 보십시오: + +검사를 해보고 난 후에, **FastAPI** 버전을 더 최신으로 업그레이드 할 수 있습니다. 그리고 코드들이 테스트에 정상적으로 작동하는지 확인을 해야합니다. + +만약에 모든 것이 정상 작동하거나 필요한 부분을 변경하고, 모든 검사를 통과한다면, 새로운 버전의 `fastapi`를 표시할 수 있습니다. + +## Starlette에 대해 + +`starlette`의 버전은 표시할 수 없습니다. + +서로다른 버전의 **FastAPI**가 구체적이고 새로운 버전의 Starlette을 사용할 것입니다. + +그러므로 **FastAPI**가 알맞은 Starlette 버전을 사용하도록 하십시오. + +## Pydantic에 대해 + +Pydantic은 **FastAPI** 를 위한 검사를 포함하고 있습니다. 따라서, 새로운 버전의 Pydantic(`1.0.0`이상)은 항상 FastAPI와 호환됩니다. + +작업을 하고 있는 `1.0.0` 이상의 모든 버전과 `2.0.0` 이하의 Pydantic 버전을 표시할 수 있습니다. + +예를 들어 다음과 같습니다: + +```txt +pydantic>=1.2.0,<2.0.0 +``` From 8e416875ce98e89b05da53cf95fccd40818c903f Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 8 Dec 2021 15:38:10 +0000 Subject: [PATCH 316/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index efb84de47..0f0edaa7b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Korean translation for `docs/ko/docs/deployment/versions.md`. PR [#4121](https://github.com/tiangolo/fastapi/pull/4121) by [@DevDae](https://github.com/DevDae). * 🌐 Fix Korean translation for `docs/ko/docs/tutorial/index.md`. PR [#4193](https://github.com/tiangolo/fastapi/pull/4193) by [@kimjaeyoonn](https://github.com/kimjaeyoonn). * 🔧 Add CryptAPI sponsor. PR [#4264](https://github.com/tiangolo/fastapi/pull/4264) by [@tiangolo](https://github.com/tiangolo). * 📝 Update `docs/tutorial/dependencies/classes-as-dependencies`: Add type of query parameters in a description of `Classes as dependencies`. PR [#4015](https://github.com/tiangolo/fastapi/pull/4015) by [@0417taehyun](https://github.com/0417taehyun). From a5d697b9b56443ac1abfc09f358e9eb56031422e Mon Sep 17 00:00:00 2001 From: Spike Date: Thu, 9 Dec 2021 00:41:26 +0900 Subject: [PATCH 317/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Korean=20translati?= =?UTF-8?q?on=20for=20Tutorial=20-=20Path=20Parameters=20and=20Numeric=20V?= =?UTF-8?q?alidations=20(#2432)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../path-params-numeric-validations.md | 122 ++++++++++++++++++ docs/ko/mkdocs.yml | 1 + 2 files changed, 123 insertions(+) create mode 100644 docs/ko/docs/tutorial/path-params-numeric-validations.md diff --git a/docs/ko/docs/tutorial/path-params-numeric-validations.md b/docs/ko/docs/tutorial/path-params-numeric-validations.md new file mode 100644 index 000000000..abb9d03db --- /dev/null +++ b/docs/ko/docs/tutorial/path-params-numeric-validations.md @@ -0,0 +1,122 @@ +# 경로 매개변수와 숫자 검증 + +`Query`를 사용하여 쿼리 매개변수에 더 많은 검증과 메타데이터를 선언하는 방법과 동일하게 `Path`를 사용하여 경로 매개변수에 검증과 메타데이터를 같은 타입으로 선언할 수 있습니다. + +## 경로 임포트 + +먼저 `fastapi`에서 `Path`를 임포트합니다: + +```Python hl_lines="3" +{!../../../docs_src/path_params_numeric_validations/tutorial001.py!} +``` + +## 메타데이터 선언 + +`Query`에 동일한 매개변수를 선언할 수 있습니다. + +예를 들어, `title` 메타데이터 값을 경로 매개변수 `item_id`에 선언하려면 다음과 같이 입력할 수 있습니다: + +```Python hl_lines="10" +{!../../../docs_src/path_params_numeric_validations/tutorial001.py!} +``` + +!!! note "참고" + 경로 매개변수는 경로의 일부여야 하므로 언제나 필수적입니다. + + 즉, `...`로 선언해서 필수임을 나타내는게 좋습니다. + + 그럼에도 `None`으로 선언하거나 기본값을 지정할지라도 아무 영향을 끼치지 않으며 언제나 필수입니다. + +## 필요한 경우 매개변수 정렬하기 + +`str` 형인 쿼리 매개변수 `q`를 필수로 선언하고 싶다고 해봅시다. + +해당 매개변수에 대해 아무런 선언을 할 필요가 없으므로 `Query`를 정말로 써야할 필요는 없습니다. + +하지만 `item_id` 경로 매개변수는 여전히 `Path`를 사용해야 합니다. + +파이썬은 "기본값"이 없는 값 앞에 "기본값"이 있는 값을 입력하면 불평합니다. + +그러나 매개변수들을 재정렬함으로써 기본값(쿼리 매개변수 `q`)이 없는 값을 처음 부분에 위치 할 수 있습니다. + +**FastAPI**에서는 중요하지 않습니다. 이름, 타입 그리고 선언구(`Query`, `Path` 등)로 매개변수를 감지하며 순서는 신경 쓰지 않습니다. + +따라서 함수를 다음과 같이 선언 할 수 있습니다: + +```Python hl_lines="8" +{!../../../docs_src/path_params_numeric_validations/tutorial002.py!} +``` + +## 필요한 경우 매개변수 정렬하기, 트릭 + +`Query`나 아무런 기본값으로도 `q` 경로 매개변수를 선언하고 싶지 않지만 `Path`를 사용하여 경로 매개변수를 `item_id` 다른 순서로 선언하고 싶다면, 파이썬은 이를 위한 작고 특별한 문법이 있습니다. + +`*`를 함수의 첫 번째 매개변수로 전달하세요. + +파이썬은 `*`으로 아무런 행동도 하지 않지만, 따르는 매개변수들은 kwargs로도 알려진 키워드 인자(키-값 쌍)여야 함을 인지합니다. 기본값을 가지고 있지 않더라도 그렇습니다. + +```Python hl_lines="8" +{!../../../docs_src/path_params_numeric_validations/tutorial003.py!} +``` + +## 숫자 검증: 크거나 같음 + +`Query`와 `Path`(나중에 볼 다른 것들도)를 사용하여 문자열 뿐만 아니라 숫자의 제약을 선언할 수 있습니다. + +여기서 `ge=1`인 경우, `item_id`는 `1`보다 "크거나(`g`reater) 같은(`e`qual)" 정수형 숫자여야 합니다. + +```Python hl_lines="8" +{!../../../docs_src/path_params_numeric_validations/tutorial004.py!} +``` + +## 숫자 검증: 크거나 같음 및 작거나 같음 + +동일하게 적용됩니다: + +* `gt`: 크거나(`g`reater `t`han) +* `le`: 작거나 같은(`l`ess than or `e`qual) + +```Python hl_lines="9" +{!../../../docs_src/path_params_numeric_validations/tutorial005.py!} +``` + +## 숫자 검증: 부동소수, 크거나 및 작거나 + +숫자 검증은 `float` 값에도 동작합니다. + +여기에서 ge뿐만 아니라 gt를 선언 할 수있는 것이 중요해집니다. 예를 들어 필요한 경우, 값이 `1`보다 작더라도 반드시 `0`보다 커야합니다. + +즉, `0.5`는 유효한 값입니다. 그러나 `0.0` 또는 `0`은 그렇지 않습니다. + +lt 역시 마찬가지입니다. + +```Python hl_lines="11" +{!../../../docs_src/path_params_numeric_validations/tutorial006.py!} +``` + +## 요약 + +`Query`, `Path`(아직 보지 못한 다른 것들도)를 사용하면 [쿼리 매개변수와 문자열 검증](query-params-str-validations.md){.internal-link target=_blank}에서와 마찬가지로 메타데이터와 문자열 검증을 선언할 수 있습니다. + +그리고 숫자 검증 또한 선언할 수 있습니다: + +* `gt`: 크거나(`g`reater `t`han) +* `ge`: 크거나 같은(`g`reater than or `e`qual) +* `lt`: 작거나(`l`ess `t`han) +* `le`: 작거나 같은(`l`ess than or `e`qual) + +!!! info "정보" + `Query`, `Path`, 그리고 나중에게 보게될 것들은 (여러분이 사용할 필요가 없는) 공통 `Param` 클래스의 서브 클래스입니다. + + 그리고 이들 모두는 여태까지 본 추가 검증과 메타데이터의 동일한 모든 매개변수를 공유합니다. + +!!! note "기술 세부사항" + `fastapi`에서 `Query`, `Path` 등을 임포트 할 때, 이것들은 실제로 함수입니다. + + 호출되면 동일한 이름의 클래스의 인스턴스를 반환합니다. + + 즉, 함수인 `Query`를 임포트한 겁니다. 그리고 호출하면 `Query`라는 이름을 가진 클래스의 인스턴스를 반환합니다. + + 편집기에서 타입에 대한 오류를 표시하지 않도록 하기 위해 (클래스를 직접 사용하는 대신) 이러한 함수들이 있습니다. + + 이렇게 하면 오류를 무시하기 위한 사용자 설정을 추가하지 않고도 일반 편집기와 코딩 도구를 사용할 수 있습니다. diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 0bf1a9713..0cd0e2f9f 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -61,6 +61,7 @@ nav: - tutorial/path-params.md - tutorial/query-params.md - tutorial/header-params.md + - tutorial/path-params-numeric-validations.md markdown_extensions: - toc: permalink: true From da69a1c4c0460ab475e3d2ad351bac3a12bf6690 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 8 Dec 2021 15:42:12 +0000 Subject: [PATCH 318/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0f0edaa7b..907df6430 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Korean translation for Tutorial - Path Parameters and Numeric Validations. PR [#2432](https://github.com/tiangolo/fastapi/pull/2432) by [@hard-coders](https://github.com/hard-coders). * 🌐 Add Korean translation for `docs/ko/docs/deployment/versions.md`. PR [#4121](https://github.com/tiangolo/fastapi/pull/4121) by [@DevDae](https://github.com/DevDae). * 🌐 Fix Korean translation for `docs/ko/docs/tutorial/index.md`. PR [#4193](https://github.com/tiangolo/fastapi/pull/4193) by [@kimjaeyoonn](https://github.com/kimjaeyoonn). * 🔧 Add CryptAPI sponsor. PR [#4264](https://github.com/tiangolo/fastapi/pull/4264) by [@tiangolo](https://github.com/tiangolo). From 461e0d4cce8542cbed53791fbc80f5731883c061 Mon Sep 17 00:00:00 2001 From: Kwang Soo Jeong Date: Thu, 9 Dec 2021 00:43:31 +0900 Subject: [PATCH 319/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Korean=20translati?= =?UTF-8?q?on=20for=20Tutorial=20-=20JSON=20Compatible=20Encoder=20(#3152)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ko/docs/tutorial/encoder.md | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 docs/ko/docs/tutorial/encoder.md diff --git a/docs/ko/docs/tutorial/encoder.md b/docs/ko/docs/tutorial/encoder.md new file mode 100644 index 000000000..8b5fdb8b7 --- /dev/null +++ b/docs/ko/docs/tutorial/encoder.md @@ -0,0 +1,34 @@ +# JSON 호환 가능 인코더 + +데이터 유형(예: Pydantic 모델)을 JSON과 호환된 형태로 반환해야 하는 경우가 있습니다. (예: `dict`, `list` 등) + +예를 들면, 데이터베이스에 저장해야하는 경우입니다. + +이를 위해, **FastAPI** 에서는 `jsonable_encoder()` 함수를 제공합니다. + +## `jsonable_encoder` 사용 + +JSON 호환 가능 데이터만 수신하는 `fake_db` 데이터베이스가 존재한다고 가정하겠습니다. + +예를 들면, `datetime` 객체는 JSON과 호환되는 데이터가 아니므로 이 데이터는 받아들여지지 않습니다. + +따라서 `datetime` 객체는 ISO format 데이터를 포함하는 `str`로 변환되어야 합니다. + +같은 방식으로 이 데이터베이스는 Pydantic 모델(속성이 있는 객체)을 받지 않고, `dict` 만을 받습니다. + +이를 위해 `jsonable_encoder` 를 사용할 수 있습니다. + +Pydantic 모델과 같은 객체를 받고 JSON 호환 가능한 버전으로 반환합니다: + +```Python hl_lines="5 22" +{!../../../docs_src/encoder/tutorial001.py!} +``` + +이 예시는 Pydantic 모델을 `dict`로, `datetime` 형식을 `str`로 변환합니다. + +이렇게 호출한 결과는 파이썬 표준인 `json.dumps()`로 인코딩 할 수 있습니다. + +길이가 긴 문자열 형태의 JSON 형식(문자열)의 데이터가 들어있는 상황에서는 `str`로 반환하지 않습니다. JSON과 모두 호환되는 값과 하위 값이 있는 Python 표준 데이터 구조 (예: `dict`)를 반환합니다. + +!!! note "참고" + 실제로 `jsonable_encoder`는 **FastAPI** 에서 내부적으로 데이터를 변환하는 데 사용하지만, 다른 많은 곳에서도 이는 유용합니다. From dd463d0dc2d48777bd9149d6938a672e8f81b203 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 8 Dec 2021 15:44:10 +0000 Subject: [PATCH 320/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 907df6430..31034c847 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Korean translation for Tutorial - JSON Compatible Encoder. PR [#3152](https://github.com/tiangolo/fastapi/pull/3152) by [@NEONKID](https://github.com/NEONKID). * 🌐 Add Korean translation for Tutorial - Path Parameters and Numeric Validations. PR [#2432](https://github.com/tiangolo/fastapi/pull/2432) by [@hard-coders](https://github.com/hard-coders). * 🌐 Add Korean translation for `docs/ko/docs/deployment/versions.md`. PR [#4121](https://github.com/tiangolo/fastapi/pull/4121) by [@DevDae](https://github.com/DevDae). * 🌐 Fix Korean translation for `docs/ko/docs/tutorial/index.md`. PR [#4193](https://github.com/tiangolo/fastapi/pull/4193) by [@kimjaeyoonn](https://github.com/kimjaeyoonn). From 39dbee9d563967aeab15637974d40a374e6df85c Mon Sep 17 00:00:00 2001 From: Nina Hwang <79563565+NinaHwang@users.noreply.github.com> Date: Thu, 9 Dec 2021 00:45:37 +0900 Subject: [PATCH 321/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Korean=20translati?= =?UTF-8?q?on=20for=20`docs/tutorial/response-status-code.md`=20(#3742)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: weekwith.me <63915557+0417taehyun@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/ko/docs/tutorial/response-status-code.md | 89 +++++++++++++++++++ docs/ko/mkdocs.yml | 1 + 2 files changed, 90 insertions(+) create mode 100644 docs/ko/docs/tutorial/response-status-code.md diff --git a/docs/ko/docs/tutorial/response-status-code.md b/docs/ko/docs/tutorial/response-status-code.md new file mode 100644 index 000000000..d201867a1 --- /dev/null +++ b/docs/ko/docs/tutorial/response-status-code.md @@ -0,0 +1,89 @@ +# 응답 상태 코드 + +응답 모델과 같은 방법으로, 어떤 *경로 작동*이든 `status_code` 매개변수를 사용하여 응답에 대한 HTTP 상태 코드를 선언할 수 있습니다. + +* `@app.get()` +* `@app.post()` +* `@app.put()` +* `@app.delete()` +* 기타 + +```Python hl_lines="6" +{!../../../docs_src/response_status_code/tutorial001.py!} +``` + +!!! note "참고" + `status_code` 는 "데코레이터" 메소드(`get`, `post` 등)의 매개변수입니다. 모든 매개변수들과 본문처럼 *경로 작동 함수*가 아닙니다. + +`status_code` 매개변수는 HTTP 상태 코드를 숫자로 입력받습니다. + +!!! info "정보" + `status_code` 는 파이썬의 `http.HTTPStatus` 와 같은 `IntEnum` 을 입력받을 수도 있습니다. + +`status_code` 매개변수는: + +* 응답에서 해당 상태 코드를 반환합니다. +* 상태 코드를 OpenAPI 스키마(및 사용자 인터페이스)에 문서화 합니다. + + + +!!! note "참고" + 어떤 응답 코드들은 해당 응답에 본문이 없다는 것을 의미하기도 합니다 (다음 항목 참고). + + 이에 따라 FastAPI는 응답 본문이 없음을 명시하는 OpenAPI를 생성합니다. + +## HTTP 상태 코드에 대하여 + +!!! note "참고" + 만약 HTTP 상태 코드에 대하여 이미 알고있다면, 다음 항목으로 넘어가십시오. + +HTTP는 세자리의 숫자 상태 코드를 응답의 일부로 전송합니다. + +이 상태 코드들은 각자를 식별할 수 있도록 지정된 이름이 있으나, 중요한 것은 숫자 코드입니다. + +요약하자면: + +* `**1xx**` 상태 코드는 "정보"용입니다. 이들은 직접적으로는 잘 사용되지는 않습니다. 이 상태 코드를 갖는 응답들은 본문을 가질 수 없습니다. +* `**2xx**` 상태 코드는 "성공적인" 응답을 위해 사용됩니다. 가장 많이 사용되는 유형입니다. + * `200` 은 디폴트 상태 코드로, 모든 것이 "성공적임"을 의미합니다. + * 다른 예로는 `201` "생성됨"이 있습니다. 일반적으로 데이터베이스에 새로운 레코드를 생성한 후 사용합니다. + * 단, `204` "내용 없음"은 특별한 경우입니다. 이것은 클라이언트에게 반환할 내용이 없는 경우 사용합니다. 따라서 응답은 본문을 가질 수 없습니다. +* `**3xx**` 상태 코드는 "리다이렉션"용입니다. 본문을 가질 수 없는 `304` "수정되지 않음"을 제외하고, 이 상태 코드를 갖는 응답에는 본문이 있을 수도, 없을 수도 있습니다. +* `**4xx**` 상태 코드는 "클라이언트 오류" 응답을 위해 사용됩니다. 이것은 아마 가장 많이 사용하게 될 두번째 유형입니다. + * 일례로 `404` 는 "찾을 수 없음" 응답을 위해 사용합니다. + * 일반적인 클라이언트 오류의 경우 `400` 을 사용할 수 있습니다. +* `**5xx**` 상태 코드는 서버 오류에 사용됩니다. 이것들을 직접 사용할 일은 거의 없습니다. 응용 프로그램 코드나 서버의 일부에서 문제가 발생하면 자동으로 이들 상태 코드 중 하나를 반환합니다. + +!!! tip "팁" + 각각의 상태 코드와 이들이 의미하는 내용에 대해 더 알고싶다면 MDN HTTP 상태 코드에 관한 문서 를 확인하십시오. + +## 이름을 기억하는 쉬운 방법 + +상기 예시 참고: + +```Python hl_lines="6" +{!../../../docs_src/response_status_code/tutorial001.py!} +``` + +`201` 은 "생성됨"를 의미하는 상태 코드입니다. + +하지만 모든 상태 코드들이 무엇을 의미하는지 외울 필요는 없습니다. + +`fastapi.status` 의 편의 변수를 사용할 수 있습니다. + +```Python hl_lines="1 6" +{!../../../docs_src/response_status_code/tutorial002.py!} +``` + +이것은 단순히 작업을 편리하게 하기 위한 것으로, HTTP 상태 코드와 동일한 번호를 갖고있지만, 이를 사용하면 편집기의 자동완성 기능을 사용할 수 있습니다: + + + +!!! note "기술적 세부사항" + `from starlette import status` 역시 사용할 수 있습니다. + + **FastAPI**는 개발자인 당신의 편의를 위해 `fastapi.status` 와 동일한 `starlette.status` 도 제공합니다. 하지만 이것은 Starlette로부터 직접 제공됩니다. + +## 기본값 변경 + +추후 여기서 선언하는 기본 상태 코드가 아닌 다른 상태 코드를 반환하는 방법을 [숙련된 사용자 지침서](https://fastapi.tiangolo.com/ko/advanced/response-change-status-code/){.internal-link target=_blank}에서 확인할 수 있습니다. diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 0cd0e2f9f..dd2d6a7ac 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -62,6 +62,7 @@ nav: - tutorial/query-params.md - tutorial/header-params.md - tutorial/path-params-numeric-validations.md + - tutorial/response-status-code.md markdown_extensions: - toc: permalink: true From fb9c4b31b91fe9f9601302046997e007fe35ef95 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 8 Dec 2021 15:46:19 +0000 Subject: [PATCH 322/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 31034c847..ca7553855 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Korean translation for `docs/tutorial/response-status-code.md`. PR [#3742](https://github.com/tiangolo/fastapi/pull/3742) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add Korean translation for Tutorial - JSON Compatible Encoder. PR [#3152](https://github.com/tiangolo/fastapi/pull/3152) by [@NEONKID](https://github.com/NEONKID). * 🌐 Add Korean translation for Tutorial - Path Parameters and Numeric Validations. PR [#2432](https://github.com/tiangolo/fastapi/pull/2432) by [@hard-coders](https://github.com/hard-coders). * 🌐 Add Korean translation for `docs/ko/docs/deployment/versions.md`. PR [#4121](https://github.com/tiangolo/fastapi/pull/4121) by [@DevDae](https://github.com/DevDae). From 10e3a02582cfbf58b9c93dd782b4c2cb7a615da5 Mon Sep 17 00:00:00 2001 From: Leandro de Souza <85115541+leandrodesouzadev@users.noreply.github.com> Date: Wed, 8 Dec 2021 12:50:35 -0300 Subject: [PATCH 323/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/tutorial/query-params-str-validations.md`?= =?UTF-8?q?=20(#3965)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mário Victor Ribeiro Silva Co-authored-by: Leandro de Souza Co-authored-by: Sebastián Ramírez --- .../tutorial/query-params-str-validations.md | 303 ++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 304 insertions(+) create mode 100644 docs/pt/docs/tutorial/query-params-str-validations.md diff --git a/docs/pt/docs/tutorial/query-params-str-validations.md b/docs/pt/docs/tutorial/query-params-str-validations.md new file mode 100644 index 000000000..baac5f493 --- /dev/null +++ b/docs/pt/docs/tutorial/query-params-str-validations.md @@ -0,0 +1,303 @@ +# Parâmetros de consulta e validações de texto + +O **FastAPI** permite que você declare informações adicionais e validações aos seus parâmetros. + +Vamos utilizar essa aplicação como exemplo: + +```Python hl_lines="9" +{!../../../docs_src/query_params_str_validations/tutorial001.py!} +``` + +O parâmetro de consulta `q` é do tipo `Optional[str]`, o que significa que é do tipo `str` mas que também pode ser `None`, e de fato, o valor padrão é `None`, então o FastAPI saberá que não é obrigatório. + +!!! note "Observação" + O FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`. + + O `Optional` em `Optional[str]` não é usado pelo FastAPI, mas permitirá que seu editor lhe dê um melhor suporte e detecte erros. + +## Validação adicional + +Nós iremos forçar que mesmo o parâmetro `q` seja opcional, sempre que informado, **seu tamanho não exceda 50 caracteres**. + +### Importe `Query` + +Para isso, primeiro importe `Query` de `fastapi`: + +```Python hl_lines="3" +{!../../../docs_src/query_params_str_validations/tutorial002.py!} +``` + +## Use `Query` como o valor padrão + +Agora utilize-o como valor padrão do seu parâmetro, definindo o parâmetro `max_length` para 50: + +```Python hl_lines="9" +{!../../../docs_src/query_params_str_validations/tutorial002.py!} +``` + +Note que substituímos o valor padrão de `None` para `Query(None)`, o primeiro parâmetro de `Query` serve para o mesmo propósito: definir o valor padrão do parâmetro. + +Então: + +```Python +q: Optional[str] = Query(None) +``` + +...Torna o parâmetro opcional, da mesma maneira que: + +```Python +q: Optional[str] = None +``` + +Mas o declara explicitamente como um parâmetro de consulta. + +!!! info "Informação" + Tenha em mente que o FastAPI se preocupa com a parte: + + ```Python + = None + ``` + + Ou com: + + ```Python + = Query(None) + ``` + + E irá utilizar o `None` para detectar que o parâmetro de consulta não é obrigatório. + + O `Optional` é apenas para permitir que seu editor de texto lhe dê um melhor suporte. + +Então, podemos passar mais parâmetros para `Query`. Neste caso, o parâmetro `max_length` que se aplica a textos: + +```Python +q: str = Query(None, max_length=50) +``` + +Isso irá validar os dados, mostrar um erro claro quando os dados forem inválidos, e documentar o parâmetro na *operação de rota* do esquema OpenAPI.. + +## Adicionando mais validações + +Você também pode incluir um parâmetro `min_length`: + +```Python hl_lines="9" +{!../../../docs_src/query_params_str_validations/tutorial003.py!} +``` + +## Adicionando expressões regulares + +Você pode definir uma expressão regular que combine com um padrão esperado pelo parâmetro: + +```Python hl_lines="10" +{!../../../docs_src/query_params_str_validations/tutorial004.py!} +``` + +Essa expressão regular específica verifica se o valor recebido no parâmetro: + +* `^`: Inicia com os seguintes caracteres, ou seja, não contém caracteres anteriores. +* `fixedquery`: contém o valor exato `fixedquery`. +* `$`: termina aqui, não contém nenhum caractere após `fixedquery`. + +Se você se sente perdido com todo esse assunto de **"expressão regular"**, não se preocupe. Esse é um assunto complicado para a maioria das pessoas. Você ainda pode fazer muitas coisas sem utilizar expressões regulares. + +Mas assim que você precisar e já tiver aprendido sobre, saiba que você poderá usá-las diretamente no **FastAPI**. + +## Valores padrão + +Da mesma maneira que você utiliza `None` como o primeiro argumento para ser utilizado como um valor padrão, você pode usar outros valores. + +Vamos dizer que você queira que o parâmetro de consulta `q` tenha um `min_length` de `3`, e um valor padrão de `"fixedquery"`, então declararíamos assim: + +```Python hl_lines="7" +{!../../../docs_src/query_params_str_validations/tutorial005.py!} +``` + +!!! note "Observação" + O parâmetro torna-se opcional quando possui um valor padrão. + +## Torne-o obrigatório + +Quando você não necessita de validações ou de metadados adicionais, podemos fazer com que o parâmetro de consulta `q` seja obrigatório por não declarar um valor padrão, dessa forma: + +```Python +q: str +``` + +em vez desta: + +```Python +q: Optional[str] = None +``` + +Mas agora nós o estamos declarando como `Query`, conforme abaixo: + +```Python +q: Optional[str] = Query(None, min_length=3) +``` + +Então, quando você precisa declarar um parâmetro obrigatório utilizando o `Query`, você pode utilizar `...` como o primeiro argumento: + +```Python hl_lines="7" +{!../../../docs_src/query_params_str_validations/tutorial006.py!} +``` + +!!! info "Informação" + Se você nunca viu os `...` antes: é um valor único especial, faz parte do Python e é chamado "Ellipsis". + +Dessa forma o **FastAPI** saberá que o parâmetro é obrigatório. + +## Lista de parâmetros de consulta / múltiplos valores + +Quando você declara explicitamente um parâmetro com `Query` você pode declará-lo para receber uma lista de valores, ou podemos dizer, que irá receber mais de um valor. + +Por exemplo, para declarar que o parâmetro `q` pode aparecer diversas vezes na URL, você escreveria: + +```Python hl_lines="9" +{!../../../docs_src/query_params_str_validations/tutorial011.py!} +``` + +Então, com uma URL assim: + +``` +http://localhost:8000/items/?q=foo&q=bar +``` + +você receberá os múltiplos *parâmetros de consulta* `q` com os valores (`foo` e `bar`) em uma lista (`list`) Python dentro da *função de operação de rota*, no *parâmetro da função* `q`. + +Assim, a resposta para essa URL seria: + +```JSON +{ + "q": [ + "foo", + "bar" + ] +} +``` + +!!! tip "Dica" + Para declarar um parâmetro de consulta com o tipo `list`, como no exemplo acima, você precisa usar explicitamente o `Query`, caso contrário será interpretado como um corpo da requisição. + +A documentação interativa da API irá atualizar de acordo, permitindo múltiplos valores: + + + +### Lista de parâmetros de consulta / múltiplos valores por padrão + +E você também pode definir uma lista (`list`) de valores padrão caso nenhum seja informado: + +```Python hl_lines="9" +{!../../../docs_src/query_params_str_validations/tutorial012.py!} +``` + +Se você for até: + +``` +http://localhost:8000/items/ +``` + +O valor padrão de `q` será: `["foo", "bar"]` e sua resposta será: + +```JSON +{ + "q": [ + "foo", + "bar" + ] +} +``` + +#### Usando `list` + +Você também pode utilizar o tipo `list` diretamente em vez de `List[str]`: + +```Python hl_lines="7" +{!../../../docs_src/query_params_str_validations/tutorial013.py!} +``` + +!!! note "Observação" + Tenha em mente que neste caso, o FastAPI não irá validar os conteúdos da lista. + + Por exemplo, um `List[int]` iria validar (e documentar) que os contéudos da lista são números inteiros. Mas apenas `list` não. + +## Declarando mais metadados + +Você pode adicionar mais informações sobre o parâmetro. + +Essa informações serão inclusas no esquema do OpenAPI e utilizado pela documentação interativa e ferramentas externas. + +!!! note "Observação" + Tenha em mente que cada ferramenta oferece diferentes níveis de suporte ao OpenAPI. + + Algumas delas não exibem todas as informações extras que declaramos, ainda que na maioria dos casos, esses recursos estão planejados para desenvolvimento. + +Você pode adicionar um `title`: + +```Python hl_lines="10" +{!../../../docs_src/query_params_str_validations/tutorial007.py!} +``` + +E uma `description`: + +```Python hl_lines="13" +{!../../../docs_src/query_params_str_validations/tutorial008.py!} +``` + +## Apelidos (alias) de parâmetros + +Imagine que você queira que um parâmetro tenha o nome `item-query`. + +Desta maneira: + +``` +http://127.0.0.1:8000/items/?item-query=foobaritems +``` + +Mas o nome `item-query` não é um nome de váriavel válido no Python. + +O que mais se aproxima é `item_query`. + +Mas ainda você precisa que o nome seja exatamente `item-query`... + +Então você pode declarar um `alias`, e esse apelido (alias) que será utilizado para encontrar o valor do parâmetro: + +```Python hl_lines="9" +{!../../../docs_src/query_params_str_validations/tutorial009.py!} +``` + +## Parâmetros descontinuados + +Agora vamos dizer que você não queria mais utilizar um parâmetro. + +Você tem que deixá-lo ativo por um tempo, já que existem clientes o utilizando. Mas você quer que a documentação deixe claro que este parâmetro será descontinuado. + +Então você passa o parâmetro `deprecated=True` para `Query`: + +```Python hl_lines="18" +{!../../../docs_src/query_params_str_validations/tutorial010.py!} +``` + +Na documentação aparecerá assim: + + + +## Recapitulando + +Você pode adicionar validações e metadados adicionais aos seus parâmetros. + +Validações genéricas e metadados: + +* `alias` +* `title` +* `description` +* `deprecated` + +Validações específicas para textos: + +* `min_length` +* `max_length` +* `regex` + +Nesses exemplos você viu como declarar validações em valores do tipo `str`. + +Leia os próximos capítulos para ver como declarar validação de outros tipos, como números. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 219f41b81..ea4af852e 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -62,6 +62,7 @@ nav: - tutorial/first-steps.md - tutorial/path-params.md - tutorial/body-fields.md + - tutorial/query-params-str-validations.md - Segurança: - tutorial/security/index.md - Guia de Usuário Avançado: From fa5639cb3564a475335f468b1d2d80ae5d8845d0 Mon Sep 17 00:00:00 2001 From: Nina Hwang <79563565+NinaHwang@users.noreply.github.com> Date: Thu, 9 Dec 2021 00:52:01 +0900 Subject: [PATCH 324/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Korean=20translati?= =?UTF-8?q?on=20for=20`docs/tutorial/request-files.md`=20(#3743)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Spike Co-authored-by: weekwith.me <63915557+0417taehyun@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/ko/docs/tutorial/request-files.md | 144 +++++++++++++++++++++++++ docs/ko/mkdocs.yml | 1 + 2 files changed, 145 insertions(+) create mode 100644 docs/ko/docs/tutorial/request-files.md diff --git a/docs/ko/docs/tutorial/request-files.md b/docs/ko/docs/tutorial/request-files.md new file mode 100644 index 000000000..769a676cd --- /dev/null +++ b/docs/ko/docs/tutorial/request-files.md @@ -0,0 +1,144 @@ +# 파일 요청 + +`File`을 사용하여 클라이언트가 업로드할 파일들을 정의할 수 있습니다. + +!!! info "정보" + 업로드된 파일을 전달받기 위해 먼저 `python-multipart`를 설치해야합니다. + + 예시) `pip install python-multipart`. + + 업로드된 파일들은 "폼 데이터"의 형태로 전송되기 때문에 이 작업이 필요합니다. + +## `File` 임포트 + +`fastapi` 에서 `File` 과 `UploadFile` 을 임포트 합니다: + +```Python hl_lines="1" +{!../../../docs_src/request_files/tutorial001.py!} +``` + +## `File` 매개변수 정의 + +`Body` 및 `Form` 과 동일한 방식으로 파일의 매개변수를 생성합니다: + +```Python hl_lines="7" +{!../../../docs_src/request_files/tutorial001.py!} +``` + +!!! info "정보" + `File` 은 `Form` 으로부터 직접 상속된 클래스입니다. + + 하지만 `fastapi`로부터 `Query`, `Path`, `File` 등을 임포트 할 때, 이것들은 특별한 클래스들을 반환하는 함수라는 것을 기억하기 바랍니다. + +!!! tip "팁" + File의 본문을 선언할 때, 매개변수가 쿼리 매개변수 또는 본문(JSON) 매개변수로 해석되는 것을 방지하기 위해 `File` 을 사용해야합니다. + +파일들은 "폼 데이터"의 형태로 업로드 됩니다. + +*경로 작동 함수*의 매개변수를 `bytes` 로 선언하는 경우 **FastAPI**는 파일을 읽고 `bytes` 형태의 내용을 전달합니다. + +이것은 전체 내용이 메모리에 저장된다는 것을 의미한다는 걸 염두하기 바랍니다. 이는 작은 크기의 파일들에 적합합니다. + +어떤 경우에는 `UploadFile` 을 사용하는 것이 더 유리합니다. + +## `File` 매개변수와 `UploadFile` + +`File` 매개변수를 `UploadFile` 타입으로 정의합니다: + +```Python hl_lines="12" +{!../../../docs_src/request_files/tutorial001.py!} +``` + +`UploadFile` 을 사용하는 것은 `bytes` 과 비교해 다음과 같은 장점이 있습니다: + +* "스풀 파일"을 사용합니다. + * 최대 크기 제한까지만 메모리에 저장되며, 이를 초과하는 경우 디스크에 저장됩니다. +* 따라서 이미지, 동영상, 큰 이진코드와 같은 대용량 파일들을 많은 메모리를 소모하지 않고 처리하기에 적합합니다. +* 업로드 된 파일의 메타데이터를 얻을 수 있습니다. +* file-like `async` 인터페이스를 갖고 있습니다. +* file-like object를 필요로하는 다른 라이브러리에 직접적으로 전달할 수 있는 파이썬 `SpooledTemporaryFile` 객체를 반환합니다. + +### `UploadFile` + +`UploadFile` 은 다음과 같은 어트리뷰트가 있습니다: + +* `filename` : 문자열(`str`)로 된 업로드된 파일의 파일명입니다 (예: `myimage.jpg`). +* `content_type` : 문자열(`str`)로 된 파일 형식(MIME type / media type)입니다 (예: `image/jpeg`). +* `file` : `SpooledTemporaryFile` (파일류 객체)입니다. 이것은 "파일류" 객체를 필요로하는 다른 라이브러리에 직접적으로 전달할 수 있는 실질적인 파이썬 파일입니다. + +`UploadFile` 에는 다음의 `async` 메소드들이 있습니다. 이들은 내부적인 `SpooledTemporaryFile` 을 사용하여 해당하는 파일 메소드를 호출합니다. + +* `write(data)`: `data`(`str` 또는 `bytes`)를 파일에 작성합니다. +* `read(size)`: 파일의 바이트 및 글자의 `size`(`int`)를 읽습니다. +* `seek(offset)`: 파일 내 `offset`(`int`) 위치의 바이트로 이동합니다. + * 예) `await myfile.seek(0)` 를 사용하면 파일의 시작부분으로 이동합니다. + * `await myfile.read()` 를 사용한 후 내용을 다시 읽을 때 유용합니다. +* `close()`: 파일을 닫습니다. + +상기 모든 메소드들이 `async` 메소드이기 때문에 “await”을 사용하여야 합니다. + +예를들어, `async` *경로 작동 함수*의 내부에서 다음과 같은 방식으로 내용을 가져올 수 있습니다: + +```Python +contents = await myfile.read() +``` + +만약 일반적인 `def` *경로 작동 함수*의 내부라면, 다음과 같이 `UploadFile.file` 에 직접 접근할 수 있습니다: + +```Python +contents = myfile.file.read() +``` + +!!! note "`async` 기술적 세부사항" + `async` 메소드들을 사용할 때 **FastAPI**는 스레드풀에서 파일 메소드들을 실행하고 그들을 기다립니다. + +!!! note "Starlette 기술적 세부사항" + **FastAPI**의 `UploadFile` 은 **Starlette**의 `UploadFile` 을 직접적으로 상속받지만, **Pydantic** 및 FastAPI의 다른 부분들과의 호환성을 위해 필요한 부분들이 추가되었습니다. + +## "폼 데이터"란 + +HTML의 폼들(`
`)이 서버에 데이터를 전송하는 방식은 대개 데이터에 JSON과는 다른 "특별한" 인코딩을 사용합니다. + +**FastAPI**는 JSON 대신 올바른 위치에서 데이터를 읽을 수 있도록 합니다. + +!!! note "기술적 세부사항" + 폼의 데이터는 파일이 포함되지 않은 경우 일반적으로 "미디어 유형" `application/x-www-form-urlencoded` 을 사용해 인코딩 됩니다. + + 하지만 파일이 포함된 경우, `multipart/form-data`로 인코딩됩니다. `File`을 사용하였다면, **FastAPI**는 본문의 적합한 부분에서 파일을 가져와야 한다는 것을 인지합니다. + + 인코딩과 폼 필드에 대해 더 알고싶다면, POST에 관한MDN웹 문서 를 참고하기 바랍니다,. + +!!! warning "주의" + 다수의 `File` 과 `Form` 매개변수를 한 *경로 작동*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json` 가 아닌 `multipart/form-data` 로 인코딩 되기 때문에 JSON으로 받아야하는 `Body` 필드를 함께 선언할 수는 없습니다. + + 이는 **FastAPI**의 한계가 아니라, HTTP 프로토콜에 의한 것입니다. + +## 다중 파일 업로드 + +여러 파일을 동시에 업로드 할 수 있습니다. + +그들은 "폼 데이터"를 사용하여 전송된 동일한 "폼 필드"에 연결됩니다. + +이 기능을 사용하기 위해 , `bytes` 의 `List` 또는 `UploadFile` 를 선언하기 바랍니다: + +```Python hl_lines="10 15" +{!../../../docs_src/request_files/tutorial002.py!} +``` + +선언한대로, `bytes` 의 `list` 또는 `UploadFile` 들을 전송받을 것입니다. + +!!! note "참고" + 2019년 4월 14일부터 Swagger UI가 하나의 폼 필드로 다수의 파일을 업로드하는 것을 지원하지 않습니다. 더 많은 정보를 원하면, #4276#3641을 참고하세요. + + 그럼에도, **FastAPI**는 표준 Open API를 사용해 이미 호환이 가능합니다. + + 따라서 Swagger UI 또는 기타 그 외의 OpenAPI를 지원하는 툴이 다중 파일 업로드를 지원하는 경우, 이들은 **FastAPI**와 호환됩니다. + +!!! note "기술적 세부사항" + `from starlette.responses import HTMLResponse` 역시 사용할 수 있습니다. + + **FastAPI**는 개발자의 편의를 위해 `fastapi.responses` 와 동일한 `starlette.responses` 도 제공합니다. 하지만 대부분의 응답들은 Starlette로부터 직접 제공됩니다. + +## 요약 + +폼 데이터로써 입력 매개변수로 업로드할 파일을 선언할 경우 `File` 을 사용하기 바랍니다. diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index dd2d6a7ac..124e7b1d3 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -63,6 +63,7 @@ nav: - tutorial/header-params.md - tutorial/path-params-numeric-validations.md - tutorial/response-status-code.md + - tutorial/request-files.md markdown_extensions: - toc: permalink: true From eb79441a7f23c0df42f13547af67159d037f43c5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 9 Dec 2021 10:40:14 +0000 Subject: [PATCH 325/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ca7553855..053244434 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add portuguese translation for `docs/tutorial/query-params-str-validations.md`. PR [#3965](https://github.com/tiangolo/fastapi/pull/3965) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). * 🌐 Add Korean translation for `docs/tutorial/response-status-code.md`. PR [#3742](https://github.com/tiangolo/fastapi/pull/3742) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add Korean translation for Tutorial - JSON Compatible Encoder. PR [#3152](https://github.com/tiangolo/fastapi/pull/3152) by [@NEONKID](https://github.com/NEONKID). * 🌐 Add Korean translation for Tutorial - Path Parameters and Numeric Validations. PR [#2432](https://github.com/tiangolo/fastapi/pull/2432) by [@hard-coders](https://github.com/hard-coders). From aa4a69f790fb9a78ba7ed7767273f8734a5d028d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 9 Dec 2021 10:45:00 +0000 Subject: [PATCH 326/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 053244434..b96e81c76 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Korean translation for `docs/tutorial/request-files.md`. PR [#3743](https://github.com/tiangolo/fastapi/pull/3743) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add portuguese translation for `docs/tutorial/query-params-str-validations.md`. PR [#3965](https://github.com/tiangolo/fastapi/pull/3965) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). * 🌐 Add Korean translation for `docs/tutorial/response-status-code.md`. PR [#3742](https://github.com/tiangolo/fastapi/pull/3742) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add Korean translation for Tutorial - JSON Compatible Encoder. PR [#3152](https://github.com/tiangolo/fastapi/pull/3152) by [@NEONKID](https://github.com/NEONKID). From 062efcbb5d19efb075ed1b50cb3f01d813c04460 Mon Sep 17 00:00:00 2001 From: Nina Hwang <79563565+NinaHwang@users.noreply.github.com> Date: Thu, 9 Dec 2021 19:47:26 +0900 Subject: [PATCH 327/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Korean=20translati?= =?UTF-8?q?on=20for=20`docs/tutorial/request-forms-and-files.md`=20(#3744)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: weekwith.me <63915557+0417taehyun@users.noreply.github.com> --- .../docs/tutorial/request-forms-and-files.md | 35 +++++++++++++++++++ docs/ko/mkdocs.yml | 1 + 2 files changed, 36 insertions(+) create mode 100644 docs/ko/docs/tutorial/request-forms-and-files.md diff --git a/docs/ko/docs/tutorial/request-forms-and-files.md b/docs/ko/docs/tutorial/request-forms-and-files.md new file mode 100644 index 000000000..6750c7b23 --- /dev/null +++ b/docs/ko/docs/tutorial/request-forms-and-files.md @@ -0,0 +1,35 @@ +# 폼 및 파일 요청 + +`File` 과 `Form` 을 사용하여 파일과 폼을 함께 정의할 수 있습니다. + +!!! info "정보" + 파일과 폼 데이터를 함께, 또는 각각 업로드하기 위해 먼저 `python-multipart`를 설치해야합니다. + + 예 ) `pip install python-multipart`. + +## `File` 및 `Form` 업로드 + +```Python hl_lines="1" +{!../../../docs_src/request_forms_and_files/tutorial001.py!} +``` + +## `File` 및 `Form` 매개변수 정의 + +`Body` 및 `Query`와 동일한 방식으로 파일과 폼의 매개변수를 생성합니다: + +```Python hl_lines="8" +{!../../../docs_src/request_forms_and_files/tutorial001.py!} +``` + +파일과 폼 필드는 폼 데이터 형식으로 업로드되어 파일과 폼 필드로 전달됩니다. + +어떤 파일들은 `bytes`로, 또 어떤 파일들은 `UploadFile`로 선언할 수 있습니다. + +!!! warning "주의" + 다수의 `File`과 `Form` 매개변수를 한 *경로 작동*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json`가 아닌 `multipart/form-data`로 인코딩 되기 때문에 JSON으로 받아야하는 `Body` 필드를 함께 선언할 수는 없습니다. + + 이는 **FastAPI**의 한계가 아니라, HTTP 프로토콜에 의한 것입니다. + +## 요약 + +하나의 요청으로 데이터와 파일들을 받아야 할 경우 `File`과 `Form`을 함께 사용하기 바랍니다. diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 124e7b1d3..7a75940a3 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -64,6 +64,7 @@ nav: - tutorial/path-params-numeric-validations.md - tutorial/response-status-code.md - tutorial/request-files.md + - tutorial/request-forms-and-files.md markdown_extensions: - toc: permalink: true From 0a87bc88b85445018d3ced9d07ac6a37f9e6d8f1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 9 Dec 2021 10:48:10 +0000 Subject: [PATCH 328/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b96e81c76..271aab5d1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Korean translation for `docs/tutorial/request-forms-and-files.md`. PR [#3744](https://github.com/tiangolo/fastapi/pull/3744) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add Korean translation for `docs/tutorial/request-files.md`. PR [#3743](https://github.com/tiangolo/fastapi/pull/3743) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add portuguese translation for `docs/tutorial/query-params-str-validations.md`. PR [#3965](https://github.com/tiangolo/fastapi/pull/3965) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). * 🌐 Add Korean translation for `docs/tutorial/response-status-code.md`. PR [#3742](https://github.com/tiangolo/fastapi/pull/3742) by [@NinaHwang](https://github.com/NinaHwang). From b0cd4d7e7ebdbab130d663d73d5474361116ce63 Mon Sep 17 00:00:00 2001 From: Eric Jolibois Date: Sun, 12 Dec 2021 12:28:35 +0100 Subject: [PATCH 329/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20JSON=20Schema=20fo?= =?UTF-8?q?r=20dataclasses,=20supporting=20the=20fixes=20in=20Pydantic=201?= =?UTF-8?q?.9=20(#4272)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../test_dataclasses/test_tutorial002.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial002.py b/tests/test_tutorial/test_dataclasses/test_tutorial002.py index 10d8d227d..34aeb0be5 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial002.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial002.py @@ -1,3 +1,5 @@ +from copy import deepcopy + from fastapi.testclient import TestClient from docs_src.dataclasses.tutorial002 import app @@ -29,7 +31,7 @@ openapi_schema = { "schemas": { "Item": { "title": "Item", - "required": ["name", "price", "tags"], + "required": ["name", "price"], "type": "object", "properties": { "name": {"title": "Name", "type": "string"}, @@ -51,7 +53,18 @@ openapi_schema = { def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 - assert response.json() == openapi_schema + # TODO: remove this once Pydantic 1.9 is released + # Ref: https://github.com/samuelcolvin/pydantic/pull/2557 + data = response.json() + alternative_data1 = deepcopy(data) + alternative_data2 = deepcopy(data) + alternative_data1["components"]["schemas"]["Item"]["required"] = ["name", "price"] + alternative_data2["components"]["schemas"]["Item"]["required"] = [ + "name", + "price", + "tags", + ] + assert alternative_data1 == openapi_schema or alternative_data2 == openapi_schema def test_get_item(): From 6d642ef5fb60eb48d178de2846657cf4d90e882a Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 12 Dec 2021 11:29:36 +0000 Subject: [PATCH 330/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 271aab5d1..2a0d27360 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix JSON Schema for dataclasses, supporting the fixes in Pydantic 1.9. PR [#4272](https://github.com/tiangolo/fastapi/pull/4272) by [@PrettyWood](https://github.com/PrettyWood). * 🌐 Add Korean translation for `docs/tutorial/request-forms-and-files.md`. PR [#3744](https://github.com/tiangolo/fastapi/pull/3744) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add Korean translation for `docs/tutorial/request-files.md`. PR [#3743](https://github.com/tiangolo/fastapi/pull/3743) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add portuguese translation for `docs/tutorial/query-params-str-validations.md`. PR [#3965](https://github.com/tiangolo/fastapi/pull/3965) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). From e7158bc59212ddc5ecd6a45a83e6d99f8c6bb3d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 12 Dec 2021 12:34:18 +0100 Subject: [PATCH 331/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#4274)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/people.yml | 258 ++++++++++++++++++++-------------------- 1 file changed, 127 insertions(+), 131 deletions(-) diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 8f1710d33..89c6f8dc3 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,12 +1,12 @@ maintainers: - login: tiangolo answers: 1230 - prs: 260 + prs: 269 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=5cad72c846b7aba2e960546af490edc7375dafc4&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 299 + count: 315 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: dmontagu @@ -30,41 +30,45 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 - login: ArcLightSlavik - count: 68 + count: 71 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik +- login: raphaelauv + count: 63 + avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 + url: https://github.com/raphaelauv - login: falkben - count: 57 + count: 58 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 url: https://github.com/falkben - login: sm-Fifteen count: 48 avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 url: https://github.com/sm-Fifteen -- login: raphaelauv - count: 48 - avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 - url: https://github.com/raphaelauv +- login: Dustyposa + count: 42 + avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 + url: https://github.com/Dustyposa - login: includeamin count: 38 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 url: https://github.com/includeamin -- login: Dustyposa - count: 38 - avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 - url: https://github.com/Dustyposa +- login: insomnes + count: 37 + avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 + url: https://github.com/insomnes - login: prostomarkeloff count: 33 avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4 url: https://github.com/prostomarkeloff +- login: STeveShary + count: 32 + avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 + url: https://github.com/STeveShary - login: krishnardt count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 url: https://github.com/krishnardt -- login: insomnes - count: 30 - avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 - url: https://github.com/insomnes - login: wshayes count: 29 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 @@ -73,6 +77,14 @@ experts: count: 29 avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 url: https://github.com/frankie567 +- login: adriangb + count: 26 + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 + url: https://github.com/adriangb +- login: ghandic + count: 25 + avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 + url: https://github.com/ghandic - login: dbanty count: 25 avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4 @@ -85,13 +97,9 @@ experts: count: 24 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak -- login: STeveShary - count: 24 - avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 - url: https://github.com/STeveShary - login: acnebs count: 22 - avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=bfd127b3e6200f4d00afd714f0fc95c2512df19b&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4 url: https://github.com/acnebs - login: nsidnev count: 22 @@ -101,22 +109,18 @@ experts: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 url: https://github.com/chris-allnutt +- login: panla + count: 21 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla - login: retnikt count: 19 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 url: https://github.com/retnikt -- login: ghandic - count: 18 - avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 - url: https://github.com/ghandic - login: Hultner count: 18 avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 url: https://github.com/Hultner -- login: panla - count: 18 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 - url: https://github.com/panla - login: jorgerpo count: 17 avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4 @@ -125,26 +129,30 @@ experts: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4 url: https://github.com/nkhitrov -- login: adriangb - count: 17 - avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 - url: https://github.com/adriangb - login: waynerv count: 16 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 url: https://github.com/waynerv +- login: acidjunk + count: 15 + avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 + url: https://github.com/acidjunk - login: haizaar count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar -- login: acidjunk +- login: dstlny count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 - url: https://github.com/acidjunk + avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 + url: https://github.com/dstlny - login: David-Lor count: 12 avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4 url: https://github.com/David-Lor +- login: lowercase00 + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/21188280?v=4 + url: https://github.com/lowercase00 - login: zamiramir count: 11 avatarUrl: https://avatars.githubusercontent.com/u/40475662?u=e58ef61034e8d0d6a312cc956fb09b9c3332b449&v=4 @@ -153,10 +161,6 @@ experts: count: 11 avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4 url: https://github.com/juntatalor -- login: dstlny - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 - url: https://github.com/dstlny - login: valentin994 count: 11 avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4 @@ -173,43 +177,27 @@ experts: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/47581948?v=4 url: https://github.com/hellocoldworld +- login: oligond + count: 10 + avatarUrl: https://avatars.githubusercontent.com/u/2858306?u=1bb1182a5944e93624b7fb26585f22c8f7a9d76e&v=4 + url: https://github.com/oligond last_month_active: +- login: raphaelauv + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 + url: https://github.com/raphaelauv +- login: oligond + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/2858306?u=1bb1182a5944e93624b7fb26585f22c8f7a9d76e&v=4 + url: https://github.com/oligond - login: Kludex - count: 13 + count: 5 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex -- login: ghandic - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 - url: https://github.com/ghandic -- login: STeveShary - count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 - url: https://github.com/STeveShary -- login: Honda-a +- login: Dustyposa count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/22759187?u=f45bd5fb17b4dca331529b8e9e5eab6122b84b8b&v=4 - url: https://github.com/Honda-a -- login: frankie567 - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 - url: https://github.com/frankie567 -- login: panla - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 - url: https://github.com/panla -- login: dstlny - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 - url: https://github.com/dstlny -- login: trevorwang - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/121966?v=4 - url: https://github.com/trevorwang -- login: klaa97 - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/39653693?v=4 - url: https://github.com/klaa97 + avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 + url: https://github.com/Dustyposa top_contributors: - login: waynerv count: 25 @@ -227,14 +215,18 @@ top_contributors: count: 13 avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4 url: https://github.com/euri10 +- login: jaystone776 + count: 13 + avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 + url: https://github.com/jaystone776 - login: mariacamilagl count: 12 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 url: https://github.com/mariacamilagl -- login: jaystone776 - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 - url: https://github.com/jaystone776 +- login: Smlep + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 + url: https://github.com/Smlep - login: Serrones count: 8 avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 @@ -248,8 +240,8 @@ top_contributors: avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: hard-coders - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4 url: https://github.com/hard-coders - login: wshayes count: 5 @@ -263,10 +255,6 @@ top_contributors: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4 url: https://github.com/Attsun1031 -- login: Smlep - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 - url: https://github.com/Smlep - login: jekirl count: 4 avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4 @@ -275,13 +263,21 @@ top_contributors: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/805749?v=4 url: https://github.com/jfunez +- login: ycd + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 + url: https://github.com/ycd - login: komtaki count: 4 avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki +- login: NinaHwang + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=36ca24be1fc3daa967b0f409bab0e17132d8c80c&v=4 + url: https://github.com/NinaHwang top_reviewers: - login: Kludex - count: 90 + count: 91 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 url: https://github.com/Kludex - login: waynerv @@ -297,29 +293,37 @@ top_reviewers: avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 url: https://github.com/tokusumi - login: ycd - count: 43 + count: 44 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: AdrianDeAnda - count: 32 + count: 33 avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4 url: https://github.com/AdrianDeAnda - login: ArcLightSlavik - count: 27 + count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik - login: dmontagu count: 23 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu +- login: cassiobotaro + count: 22 + avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 + url: https://github.com/cassiobotaro - login: komtaki count: 21 avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki -- login: cassiobotaro +- login: hard-coders count: 19 - avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 - url: https://github.com/cassiobotaro + avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4 + url: https://github.com/hard-coders +- login: 0417taehyun + count: 19 + avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4 + url: https://github.com/0417taehyun - login: yanever count: 16 avatarUrl: https://avatars.githubusercontent.com/u/21978760?v=4 @@ -328,10 +332,14 @@ top_reviewers: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4 url: https://github.com/SwftAlpc -- login: hard-coders +- login: Smlep count: 16 - avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 - url: https://github.com/hard-coders + avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 + url: https://github.com/Smlep +- login: DevDae + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/87962045?u=08e10fa516e844934f4b3fc7c38b33c61697e4a1&v=4 + url: https://github.com/DevDae - login: pedabraham count: 15 avatarUrl: https://avatars.githubusercontent.com/u/16860088?u=abf922a7b920bf8fdb7867d8b43e091f1e796178&v=4 @@ -340,10 +348,6 @@ top_reviewers: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4 url: https://github.com/delhi09 -- login: Smlep - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 - url: https://github.com/Smlep - login: lsglucas count: 14 avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 @@ -372,18 +376,38 @@ top_reviewers: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4 url: https://github.com/maoyibo +- login: yezz123 + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 + url: https://github.com/yezz123 +- login: graingert + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4 + url: https://github.com/graingert - login: PandaHun count: 9 avatarUrl: https://avatars.githubusercontent.com/u/13096845?u=646eba44db720e37d0dbe8e98e77ab534ea78a20&v=4 url: https://github.com/PandaHun +- login: kty4119 + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/49435654?v=4 + url: https://github.com/kty4119 - login: bezaca count: 9 avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4 url: https://github.com/bezaca +- login: solomein-sv + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 + url: https://github.com/solomein-sv - login: blt232018 count: 8 avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4 url: https://github.com/blt232018 +- login: ComicShrimp + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 + url: https://github.com/ComicShrimp - login: Serrones count: 7 avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 @@ -396,10 +420,6 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv -- login: graingert - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4 - url: https://github.com/graingert - login: NastasiaSaby count: 7 avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4 @@ -408,14 +428,10 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause -- login: solomein-sv +- login: krocdort count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 - url: https://github.com/solomein-sv -- login: ComicShrimp - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 - url: https://github.com/ComicShrimp + avatarUrl: https://avatars.githubusercontent.com/u/34248814?v=4 + url: https://github.com/krocdort - login: jovicon count: 6 avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 @@ -424,6 +440,10 @@ top_reviewers: count: 6 avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 url: https://github.com/BilalAlpaslan +- login: diogoduartec + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/31852339?u=b50fc11c531e9b77922e19edfc9e7233d4d7b92e&v=4 + url: https://github.com/diogoduartec - login: nimctl count: 5 avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4 @@ -452,27 +472,3 @@ top_reviewers: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/23391143?u=56ab6bff50be950fa8cae5cf736f2ae66e319ff3&v=4 url: https://github.com/rkbeatss -- login: izaguerreiro - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4 - url: https://github.com/izaguerreiro -- login: aviramha - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/41201924?u=6883cc4fc13a7b2e60d4deddd4be06f9c5287880&v=4 - url: https://github.com/aviramha -- login: Cajuteq - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/26676532?u=8ee0422981810e51480855de1c0d67b6b79cd3f2&v=4 - url: https://github.com/Cajuteq -- login: Zxilly - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/31370133?v=4 - url: https://github.com/Zxilly -- login: dukkee - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/36825394?u=ccfd86e6a4f2d093dad6f7544cc875af67fa2df8&v=4 - url: https://github.com/dukkee -- login: Bluenix2 - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/38372706?u=c9d28aff15958d6ebf1971148bfb3154ff943c4f&v=4 - url: https://github.com/Bluenix2 From 9c25f9615c037cdfdeccb06b002e6ed8fd50d903 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 12 Dec 2021 11:34:58 +0000 Subject: [PATCH 332/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2a0d27360..2d3a0f4e4 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#4274](https://github.com/tiangolo/fastapi/pull/4274) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🐛 Fix JSON Schema for dataclasses, supporting the fixes in Pydantic 1.9. PR [#4272](https://github.com/tiangolo/fastapi/pull/4272) by [@PrettyWood](https://github.com/PrettyWood). * 🌐 Add Korean translation for `docs/tutorial/request-forms-and-files.md`. PR [#3744](https://github.com/tiangolo/fastapi/pull/3744) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add Korean translation for `docs/tutorial/request-files.md`. PR [#3743](https://github.com/tiangolo/fastapi/pull/3743) by [@NinaHwang](https://github.com/NinaHwang). From 3efb4f7edff99fdc12802a85ae9d140ec4772497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 12 Dec 2021 12:39:32 +0100 Subject: [PATCH 333/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.70?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 14 +++++++++++++- fastapi/__init__.py | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2d3a0f4e4..5995ecca6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,8 +2,16 @@ ## Latest Changes -* 👥 Update FastAPI People. PR [#4274](https://github.com/tiangolo/fastapi/pull/4274) by [@github-actions[bot]](https://github.com/apps/github-actions). +## 0.70.1 + +There's nothing interesting in this particular FastAPI release. It is mainly to enable/unblock the release of the next version of Pydantic that comes packed with features and improvements. 🤩 + +### Fixes + * 🐛 Fix JSON Schema for dataclasses, supporting the fixes in Pydantic 1.9. PR [#4272](https://github.com/tiangolo/fastapi/pull/4272) by [@PrettyWood](https://github.com/PrettyWood). + +### Translations + * 🌐 Add Korean translation for `docs/tutorial/request-forms-and-files.md`. PR [#3744](https://github.com/tiangolo/fastapi/pull/3744) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add Korean translation for `docs/tutorial/request-files.md`. PR [#3743](https://github.com/tiangolo/fastapi/pull/3743) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add portuguese translation for `docs/tutorial/query-params-str-validations.md`. PR [#3965](https://github.com/tiangolo/fastapi/pull/3965) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). @@ -19,6 +27,10 @@ * 🌐 Add French translation for `docs/tutorial/query-params.md`. PR [#3556](https://github.com/tiangolo/fastapi/pull/3556) by [@Smlep](https://github.com/Smlep). * 🌐 Add Turkish translation for `docs/python-types.md`. PR [#3926](https://github.com/tiangolo/fastapi/pull/3926) by [@BilalAlpaslan](https://github.com/BilalAlpaslan). +### Internal + +* 👥 Update FastAPI People. PR [#4274](https://github.com/tiangolo/fastapi/pull/4274) by [@github-actions[bot]](https://github.com/apps/github-actions). + ## 0.70.0 This release just upgrades Starlette to the latest version, `0.16.0`, which includes several bug fixes and some small breaking changes. diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 4d4d4333d..8bb6ce15b 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.70.0" +__version__ = "0.70.1" from starlette import status as status From 2b10ca1cc47146b07b6598ac9473cbe8cac50cc0 Mon Sep 17 00:00:00 2001 From: simondale00 <33907262+simondale00@users.noreply.github.com> Date: Fri, 7 Jan 2022 04:34:28 -0500 Subject: [PATCH 334/814] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20Starlett?= =?UTF-8?q?e=20to=200.17.1=20(#4145)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dima Tisnek Co-authored-by: simond Co-authored-by: Samuel Colvin Co-authored-by: Samuel Colvin --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 50e0afe87..4feae5524 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ classifiers = [ "Topic :: Internet :: WWW/HTTP", ] requires = [ - "starlette ==0.16.0", + "starlette ==0.17.1", "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0", ] description-file = "README.md" From 4e9f75912f75f09816328d5f8a28060c9d1ddd69 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 7 Jan 2022 09:35:10 +0000 Subject: [PATCH 335/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5995ecca6..add51ca59 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade Starlette to 0.17.1. PR [#4145](https://github.com/tiangolo/fastapi/pull/4145) by [@simondale00](https://github.com/simondale00). ## 0.70.1 There's nothing interesting in this particular FastAPI release. It is mainly to enable/unblock the release of the next version of Pydantic that comes packed with features and improvements. 🤩 From 764ecae2d477c48ba2e61dda44ee3d663d54b84d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 7 Jan 2022 11:24:00 +0100 Subject: [PATCH 336/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20MkDocs=20Material?= =?UTF-8?q?=20and=20configs=20(#4385)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/az/mkdocs.yml | 9 +++++---- docs/de/mkdocs.yml | 9 +++++---- docs/en/mkdocs.yml | 9 +++++---- docs/es/mkdocs.yml | 9 +++++---- docs/fr/mkdocs.yml | 9 +++++---- docs/id/mkdocs.yml | 9 +++++---- docs/it/mkdocs.yml | 9 +++++---- docs/ja/mkdocs.yml | 9 +++++---- docs/ko/mkdocs.yml | 9 +++++---- docs/pl/mkdocs.yml | 9 +++++---- docs/pt/mkdocs.yml | 9 +++++---- docs/ru/mkdocs.yml | 9 +++++---- docs/sq/mkdocs.yml | 9 +++++---- docs/tr/mkdocs.yml | 9 +++++---- docs/uk/mkdocs.yml | 9 +++++---- docs/zh/mkdocs.yml | 9 +++++---- pyproject.toml | 2 +- 17 files changed, 81 insertions(+), 65 deletions(-) diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index 72ca92a96..66220f63e 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -70,8 +67,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 621305d20..360fa8c4a 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -71,8 +68,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index aa2d0451d..5bdd2c54a 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -176,8 +173,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index ef722715b..a4bc41154 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -80,8 +77,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 6242a88fd..ff16e1d78 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -85,8 +82,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index f9cae22cc..d70d2b3c3 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -70,8 +67,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index f16210608..e6d01fbde 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -70,8 +67,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 237bc9654..39fd8a211 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -110,8 +107,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 7a75940a3..1d4d30913 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -80,8 +77,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 220008607..3c1351a12 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -70,8 +67,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index ea4af852e..f202f306d 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -90,8 +87,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index e15a36bf2..6e17c287e 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -70,8 +67,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index a4879521e..d9c3dad4c 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -70,8 +67,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 5ef8fd6a7..f6ed7f5b9 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -73,8 +70,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index 7f5785e3e..d0de8cc0e 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -70,8 +67,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 07ffa367f..a929e3388 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -120,8 +117,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi diff --git a/pyproject.toml b/pyproject.toml index 4feae5524..e6148831b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,7 @@ test = [ ] doc = [ "mkdocs >=1.1.2,<2.0.0", - "mkdocs-material >=7.1.9,<8.0.0", + "mkdocs-material >=8.1.4,<9.0.0", "mdx-include >=1.4.1,<2.0.0", "mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0", "typer-cli >=0.0.12,<0.0.13", From 83f67810371f48c22b7955de926d86e42ac30416 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 7 Jan 2022 10:24:43 +0000 Subject: [PATCH 337/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index add51ca59..ce1d3144d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade MkDocs Material and configs. PR [#4385](https://github.com/tiangolo/fastapi/pull/4385) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade Starlette to 0.17.1. PR [#4145](https://github.com/tiangolo/fastapi/pull/4145) by [@simondale00](https://github.com/simondale00). ## 0.70.1 From d08a062ee2121f446537f06c8425cdeb1209e4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 7 Jan 2022 15:11:31 +0100 Subject: [PATCH 338/814] =?UTF-8?q?=E2=9C=A8=20Add=20docs=20and=20tests=20?= =?UTF-8?q?for=20Python=203.9=20and=20Python=203.10=20(#3712)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Thomas Grainger --- .github/workflows/test.yml | 2 +- docs/az/mkdocs.yml | 1 - docs/de/mkdocs.yml | 1 - docs/en/docs/python-types.md | 208 ++++++++-- docs/en/docs/tutorial/background-tasks.md | 14 +- docs/en/docs/tutorial/body-fields.md | 28 +- docs/en/docs/tutorial/body-multiple-params.md | 76 +++- docs/en/docs/tutorial/body-nested-models.md | 208 ++++++++-- docs/en/docs/tutorial/body-updates.md | 80 +++- docs/en/docs/tutorial/body.md | 84 +++- docs/en/docs/tutorial/cookie-params.md | 28 +- .../dependencies/classes-as-dependencies.md | 98 ++++- docs/en/docs/tutorial/dependencies/index.md | 42 +- .../tutorial/dependencies/sub-dependencies.md | 48 ++- docs/en/docs/tutorial/encoder.md | 14 +- docs/en/docs/tutorial/extra-data-types.md | 28 +- docs/en/docs/tutorial/extra-models.md | 86 +++- docs/en/docs/tutorial/header-params.md | 63 ++- .../tutorial/path-operation-configuration.md | 100 ++++- .../path-params-numeric-validations.md | 30 +- .../tutorial/query-params-str-validations.md | 182 +++++++-- docs/en/docs/tutorial/query-params.md | 61 ++- docs/en/docs/tutorial/request-files.md | 16 +- docs/en/docs/tutorial/response-model.md | 158 +++++-- docs/en/docs/tutorial/schema-extra-example.md | 56 ++- .../tutorial/security/get-current-user.md | 72 +++- docs/en/docs/tutorial/security/oauth2-jwt.md | 56 ++- .../docs/tutorial/security/simple-oauth2.md | 70 +++- docs/en/docs/tutorial/sql-databases.md | 164 ++++++-- docs/en/docs/tutorial/testing.md | 20 +- docs/en/mkdocs.yml | 1 - docs/es/mkdocs.yml | 1 - docs/fr/mkdocs.yml | 1 - docs/id/mkdocs.yml | 1 - docs/it/mkdocs.yml | 1 - docs/ja/mkdocs.yml | 1 - docs/ko/mkdocs.yml | 1 - docs/pl/mkdocs.yml | 1 - docs/pt/mkdocs.yml | 1 - docs/ru/mkdocs.yml | 1 - docs/sq/mkdocs.yml | 1 - docs/tr/mkdocs.yml | 1 - docs/uk/mkdocs.yml | 1 - docs/zh/mkdocs.yml | 1 - docs_src/app_testing/app_b/__init__.py | 0 .../app_testing/{main_b.py => app_b/main.py} | 0 .../{test_main_b.py => app_b/test_main.py} | 2 +- docs_src/app_testing/app_b_py310/__init__.py | 0 docs_src/app_testing/app_b_py310/main.py | 36 ++ docs_src/app_testing/app_b_py310/test_main.py | 65 +++ .../background_tasks/tutorial002_py310.py | 24 ++ docs_src/body/tutorial001_py310.py | 17 + docs_src/body/tutorial002_py310.py | 21 + docs_src/body/tutorial003_py310.py | 17 + docs_src/body/tutorial004_py310.py | 20 + docs_src/body_fields/tutorial001_py310.py | 19 + .../body_multiple_params/tutorial001_py310.py | 26 ++ .../body_multiple_params/tutorial002_py310.py | 22 + .../body_multiple_params/tutorial003_py310.py | 24 ++ .../body_multiple_params/tutorial004_py310.py | 31 ++ .../body_multiple_params/tutorial005_py310.py | 17 + .../body_nested_models/tutorial001_py310.py | 18 + .../body_nested_models/tutorial002_py310.py | 18 + .../body_nested_models/tutorial002_py39.py | 20 + .../body_nested_models/tutorial003_py310.py | 18 + .../body_nested_models/tutorial003_py39.py | 20 + .../body_nested_models/tutorial004_py310.py | 24 ++ .../body_nested_models/tutorial004_py39.py | 26 ++ .../body_nested_models/tutorial005_py310.py | 24 ++ .../body_nested_models/tutorial005_py39.py | 26 ++ .../body_nested_models/tutorial006_py310.py | 24 ++ .../body_nested_models/tutorial006_py39.py | 26 ++ .../body_nested_models/tutorial007_py310.py | 30 ++ .../body_nested_models/tutorial007_py39.py | 32 ++ .../body_nested_models/tutorial008_py39.py | 14 + .../body_nested_models/tutorial009_py39.py | 8 + docs_src/body_updates/tutorial001_py310.py | 32 ++ docs_src/body_updates/tutorial001_py39.py | 34 ++ docs_src/body_updates/tutorial002_py310.py | 35 ++ docs_src/body_updates/tutorial002_py39.py | 37 ++ docs_src/cookie_params/tutorial001_py310.py | 8 + docs_src/dependencies/tutorial001_py310.py | 17 + docs_src/dependencies/tutorial002_py310.py | 23 ++ docs_src/dependencies/tutorial003_py310.py | 23 ++ docs_src/dependencies/tutorial004_py310.py | 23 ++ docs_src/dependencies/tutorial005_py310.py | 20 + docs_src/encoder/tutorial001_py310.py | 22 + .../extra_data_types/tutorial001_py310.py | 27 ++ docs_src/extra_models/tutorial001_py310.py | 41 ++ docs_src/extra_models/tutorial002_py310.py | 39 ++ docs_src/extra_models/tutorial003_py310.py | 35 ++ docs_src/extra_models/tutorial004_py39.py | 20 + docs_src/extra_models/tutorial005_py39.py | 8 + docs_src/header_params/tutorial001_py310.py | 8 + docs_src/header_params/tutorial002_py310.py | 10 + docs_src/header_params/tutorial003_py310.py | 8 + docs_src/header_params/tutorial003_py39.py | 10 + .../tutorial001.py | 2 +- .../tutorial001_py310.py | 17 + .../tutorial001_py39.py | 19 + .../tutorial002.py | 2 +- .../tutorial002_py310.py | 27 ++ .../tutorial002_py39.py | 29 ++ .../tutorial003.py | 2 +- .../tutorial003_py310.py | 22 + .../tutorial003_py39.py | 24 ++ .../tutorial004.py | 2 +- .../tutorial004_py310.py | 26 ++ .../tutorial004_py39.py | 28 ++ .../tutorial005.py | 2 +- .../tutorial005_py310.py | 31 ++ .../tutorial005_py39.py | 33 ++ .../tutorial001_py310.py | 14 + docs_src/python_types/tutorial006_py39.py | 3 + docs_src/python_types/tutorial007_py39.py | 2 + docs_src/python_types/tutorial008.py | 5 +- docs_src/python_types/tutorial008b.py | 5 + docs_src/python_types/tutorial008b_py310.py | 2 + docs_src/python_types/tutorial009_py310.py | 5 + docs_src/python_types/tutorial009b.py | 8 + docs_src/python_types/tutorial011_py310.py | 22 + docs_src/python_types/tutorial011_py39.py | 23 ++ docs_src/query_params/tutorial002_py310.py | 10 + docs_src/query_params/tutorial003_py310.py | 15 + docs_src/query_params/tutorial004_py310.py | 17 + docs_src/query_params/tutorial006_py310.py | 11 + docs_src/query_params/tutorial006b.py | 13 + .../tutorial001_py310.py | 11 + .../tutorial002_py310.py | 11 + .../tutorial003_py310.py | 11 + .../tutorial004_py310.py | 13 + .../tutorial007_py310.py | 11 + .../tutorial008_py310.py | 19 + .../tutorial009_py310.py | 11 + .../tutorial010_py310.py | 23 ++ .../tutorial011_py310.py | 9 + .../tutorial011_py39.py | 11 + .../tutorial012_py39.py | 9 + docs_src/request_files/tutorial002_py39.py | 31 ++ docs_src/response_model/tutorial001_py310.py | 17 + docs_src/response_model/tutorial001_py39.py | 19 + docs_src/response_model/tutorial002_py310.py | 17 + docs_src/response_model/tutorial003_py310.py | 22 + docs_src/response_model/tutorial004_py310.py | 24 ++ docs_src/response_model/tutorial004_py39.py | 26 ++ docs_src/response_model/tutorial005_py310.py | 37 ++ docs_src/response_model/tutorial006_py310.py | 37 ++ .../schema_extra_example/tutorial001_py310.py | 27 ++ .../schema_extra_example/tutorial002_py310.py | 17 + .../schema_extra_example/tutorial003_py310.py | 28 ++ .../schema_extra_example/tutorial004_py310.py | 50 +++ docs_src/security/tutorial002_py310.py | 30 ++ docs_src/security/tutorial003_py310.py | 88 ++++ docs_src/security/tutorial004_py310.py | 137 +++++++ docs_src/security/tutorial005_py310.py | 172 ++++++++ docs_src/security/tutorial005_py39.py | 173 ++++++++ .../sql_databases/sql_app_py310/__init__.py | 0 .../sql_databases/sql_app_py310/alt_main.py | 60 +++ docs_src/sql_databases/sql_app_py310/crud.py | 36 ++ .../sql_databases/sql_app_py310/database.py | 13 + docs_src/sql_databases/sql_app_py310/main.py | 53 +++ .../sql_databases/sql_app_py310/models.py | 26 ++ .../sql_databases/sql_app_py310/schemas.py | 35 ++ .../sql_app_py310/tests/__init__.py | 0 .../sql_app_py310/tests/test_sql_app.py | 47 +++ .../sql_databases/sql_app_py39/__init__.py | 0 .../sql_databases/sql_app_py39/alt_main.py | 60 +++ docs_src/sql_databases/sql_app_py39/crud.py | 36 ++ .../sql_databases/sql_app_py39/database.py | 13 + docs_src/sql_databases/sql_app_py39/main.py | 53 +++ docs_src/sql_databases/sql_app_py39/models.py | 26 ++ .../sql_databases/sql_app_py39/schemas.py | 37 ++ .../sql_app_py39/tests/__init__.py | 0 .../sql_app_py39/tests/test_sql_app.py | 47 +++ pyproject.toml | 1 + .../test_tutorial002_py310.py | 21 + .../test_body/test_tutorial001_py310.py | 292 +++++++++++++ .../test_tutorial001_py310.py | 176 ++++++++ .../test_tutorial001_py310.py | 155 +++++++ .../test_tutorial003_py310.py | 206 ++++++++++ .../test_tutorial009_py39.py | 113 ++++++ .../test_tutorial001_py310.py | 172 ++++++++ .../test_tutorial001_py39.py | 172 ++++++++ .../test_tutorial001_py310.py | 100 +++++ .../test_tutorial001_py310.py | 157 +++++++ .../test_tutorial004_py310.py | 152 +++++++ .../test_tutorial001_py310.py | 146 +++++++ .../test_tutorial003_py310.py | 135 ++++++ .../test_tutorial004_py39.py | 69 ++++ .../test_tutorial005_py39.py | 53 +++ .../test_tutorial001_py310.py | 94 +++++ .../test_tutorial005_py310.py | 121 ++++++ .../test_tutorial005_py39.py | 121 ++++++ .../test_tutorial006_py310.py | 148 +++++++ .../test_tutorial001_py310.py | 132 ++++++ .../test_tutorial011_py310.py | 105 +++++ .../test_tutorial011_py39.py | 105 +++++ .../test_tutorial012_py39.py | 106 +++++ .../test_tutorial002_py39.py | 235 +++++++++++ .../test_tutorial003_py310.py | 129 ++++++ .../test_tutorial004_py310.py | 133 ++++++ .../test_tutorial004_py39.py | 133 ++++++ .../test_tutorial005_py310.py | 152 +++++++ .../test_tutorial006_py310.py | 152 +++++++ .../test_tutorial004_py310.py | 143 +++++++ .../test_security/test_tutorial003_py310.py | 192 +++++++++ .../test_security/test_tutorial005_py310.py | 375 +++++++++++++++++ .../test_security/test_tutorial005_py39.py | 375 +++++++++++++++++ .../test_sql_databases/test_sql_databases.py | 7 +- .../test_sql_databases_middleware_py310.py | 384 ++++++++++++++++++ .../test_sql_databases_middleware_py39.py | 384 ++++++++++++++++++ .../test_sql_databases_py310.py | 383 +++++++++++++++++ .../test_sql_databases_py39.py | 383 +++++++++++++++++ .../test_testing_databases.py | 9 +- .../test_testing_databases_py310.py | 26 ++ .../test_testing_databases_py39.py | 26 ++ .../test_tutorial/test_testing/test_main_b.py | 14 +- .../test_testing/test_main_b_py310.py | 13 + tests/utils.py | 3 + 219 files changed, 11562 insertions(+), 452 deletions(-) create mode 100644 docs_src/app_testing/app_b/__init__.py rename docs_src/app_testing/{main_b.py => app_b/main.py} (100%) rename docs_src/app_testing/{test_main_b.py => app_b/test_main.py} (98%) create mode 100644 docs_src/app_testing/app_b_py310/__init__.py create mode 100644 docs_src/app_testing/app_b_py310/main.py create mode 100644 docs_src/app_testing/app_b_py310/test_main.py create mode 100644 docs_src/background_tasks/tutorial002_py310.py create mode 100644 docs_src/body/tutorial001_py310.py create mode 100644 docs_src/body/tutorial002_py310.py create mode 100644 docs_src/body/tutorial003_py310.py create mode 100644 docs_src/body/tutorial004_py310.py create mode 100644 docs_src/body_fields/tutorial001_py310.py create mode 100644 docs_src/body_multiple_params/tutorial001_py310.py create mode 100644 docs_src/body_multiple_params/tutorial002_py310.py create mode 100644 docs_src/body_multiple_params/tutorial003_py310.py create mode 100644 docs_src/body_multiple_params/tutorial004_py310.py create mode 100644 docs_src/body_multiple_params/tutorial005_py310.py create mode 100644 docs_src/body_nested_models/tutorial001_py310.py create mode 100644 docs_src/body_nested_models/tutorial002_py310.py create mode 100644 docs_src/body_nested_models/tutorial002_py39.py create mode 100644 docs_src/body_nested_models/tutorial003_py310.py create mode 100644 docs_src/body_nested_models/tutorial003_py39.py create mode 100644 docs_src/body_nested_models/tutorial004_py310.py create mode 100644 docs_src/body_nested_models/tutorial004_py39.py create mode 100644 docs_src/body_nested_models/tutorial005_py310.py create mode 100644 docs_src/body_nested_models/tutorial005_py39.py create mode 100644 docs_src/body_nested_models/tutorial006_py310.py create mode 100644 docs_src/body_nested_models/tutorial006_py39.py create mode 100644 docs_src/body_nested_models/tutorial007_py310.py create mode 100644 docs_src/body_nested_models/tutorial007_py39.py create mode 100644 docs_src/body_nested_models/tutorial008_py39.py create mode 100644 docs_src/body_nested_models/tutorial009_py39.py create mode 100644 docs_src/body_updates/tutorial001_py310.py create mode 100644 docs_src/body_updates/tutorial001_py39.py create mode 100644 docs_src/body_updates/tutorial002_py310.py create mode 100644 docs_src/body_updates/tutorial002_py39.py create mode 100644 docs_src/cookie_params/tutorial001_py310.py create mode 100644 docs_src/dependencies/tutorial001_py310.py create mode 100644 docs_src/dependencies/tutorial002_py310.py create mode 100644 docs_src/dependencies/tutorial003_py310.py create mode 100644 docs_src/dependencies/tutorial004_py310.py create mode 100644 docs_src/dependencies/tutorial005_py310.py create mode 100644 docs_src/encoder/tutorial001_py310.py create mode 100644 docs_src/extra_data_types/tutorial001_py310.py create mode 100644 docs_src/extra_models/tutorial001_py310.py create mode 100644 docs_src/extra_models/tutorial002_py310.py create mode 100644 docs_src/extra_models/tutorial003_py310.py create mode 100644 docs_src/extra_models/tutorial004_py39.py create mode 100644 docs_src/extra_models/tutorial005_py39.py create mode 100644 docs_src/header_params/tutorial001_py310.py create mode 100644 docs_src/header_params/tutorial002_py310.py create mode 100644 docs_src/header_params/tutorial003_py310.py create mode 100644 docs_src/header_params/tutorial003_py39.py create mode 100644 docs_src/path_operation_configuration/tutorial001_py310.py create mode 100644 docs_src/path_operation_configuration/tutorial001_py39.py create mode 100644 docs_src/path_operation_configuration/tutorial002_py310.py create mode 100644 docs_src/path_operation_configuration/tutorial002_py39.py create mode 100644 docs_src/path_operation_configuration/tutorial003_py310.py create mode 100644 docs_src/path_operation_configuration/tutorial003_py39.py create mode 100644 docs_src/path_operation_configuration/tutorial004_py310.py create mode 100644 docs_src/path_operation_configuration/tutorial004_py39.py create mode 100644 docs_src/path_operation_configuration/tutorial005_py310.py create mode 100644 docs_src/path_operation_configuration/tutorial005_py39.py create mode 100644 docs_src/path_params_numeric_validations/tutorial001_py310.py create mode 100644 docs_src/python_types/tutorial006_py39.py create mode 100644 docs_src/python_types/tutorial007_py39.py create mode 100644 docs_src/python_types/tutorial008b.py create mode 100644 docs_src/python_types/tutorial008b_py310.py create mode 100644 docs_src/python_types/tutorial009_py310.py create mode 100644 docs_src/python_types/tutorial009b.py create mode 100644 docs_src/python_types/tutorial011_py310.py create mode 100644 docs_src/python_types/tutorial011_py39.py create mode 100644 docs_src/query_params/tutorial002_py310.py create mode 100644 docs_src/query_params/tutorial003_py310.py create mode 100644 docs_src/query_params/tutorial004_py310.py create mode 100644 docs_src/query_params/tutorial006_py310.py create mode 100644 docs_src/query_params/tutorial006b.py create mode 100644 docs_src/query_params_str_validations/tutorial001_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial002_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial003_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial004_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial007_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial008_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial009_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial010_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial011_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial011_py39.py create mode 100644 docs_src/query_params_str_validations/tutorial012_py39.py create mode 100644 docs_src/request_files/tutorial002_py39.py create mode 100644 docs_src/response_model/tutorial001_py310.py create mode 100644 docs_src/response_model/tutorial001_py39.py create mode 100644 docs_src/response_model/tutorial002_py310.py create mode 100644 docs_src/response_model/tutorial003_py310.py create mode 100644 docs_src/response_model/tutorial004_py310.py create mode 100644 docs_src/response_model/tutorial004_py39.py create mode 100644 docs_src/response_model/tutorial005_py310.py create mode 100644 docs_src/response_model/tutorial006_py310.py create mode 100644 docs_src/schema_extra_example/tutorial001_py310.py create mode 100644 docs_src/schema_extra_example/tutorial002_py310.py create mode 100644 docs_src/schema_extra_example/tutorial003_py310.py create mode 100644 docs_src/schema_extra_example/tutorial004_py310.py create mode 100644 docs_src/security/tutorial002_py310.py create mode 100644 docs_src/security/tutorial003_py310.py create mode 100644 docs_src/security/tutorial004_py310.py create mode 100644 docs_src/security/tutorial005_py310.py create mode 100644 docs_src/security/tutorial005_py39.py create mode 100644 docs_src/sql_databases/sql_app_py310/__init__.py create mode 100644 docs_src/sql_databases/sql_app_py310/alt_main.py create mode 100644 docs_src/sql_databases/sql_app_py310/crud.py create mode 100644 docs_src/sql_databases/sql_app_py310/database.py create mode 100644 docs_src/sql_databases/sql_app_py310/main.py create mode 100644 docs_src/sql_databases/sql_app_py310/models.py create mode 100644 docs_src/sql_databases/sql_app_py310/schemas.py create mode 100644 docs_src/sql_databases/sql_app_py310/tests/__init__.py create mode 100644 docs_src/sql_databases/sql_app_py310/tests/test_sql_app.py create mode 100644 docs_src/sql_databases/sql_app_py39/__init__.py create mode 100644 docs_src/sql_databases/sql_app_py39/alt_main.py create mode 100644 docs_src/sql_databases/sql_app_py39/crud.py create mode 100644 docs_src/sql_databases/sql_app_py39/database.py create mode 100644 docs_src/sql_databases/sql_app_py39/main.py create mode 100644 docs_src/sql_databases/sql_app_py39/models.py create mode 100644 docs_src/sql_databases/sql_app_py39/schemas.py create mode 100644 docs_src/sql_databases/sql_app_py39/tests/__init__.py create mode 100644 docs_src/sql_databases/sql_app_py39/tests/test_sql_app.py create mode 100644 tests/test_tutorial/test_background_tasks/test_tutorial002_py310.py create mode 100644 tests/test_tutorial/test_body/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_body_fields/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py create mode 100644 tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py create mode 100644 tests/test_tutorial/test_body_updates/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_body_updates/test_tutorial001_py39.py create mode 100644 tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_dependencies/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_dependencies/test_tutorial004_py310.py create mode 100644 tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_extra_models/test_tutorial003_py310.py create mode 100644 tests/test_tutorial/test_extra_models/test_tutorial004_py39.py create mode 100644 tests/test_tutorial/test_extra_models/test_tutorial005_py39.py create mode 100644 tests/test_tutorial/test_header_params/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py create mode 100644 tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py create mode 100644 tests/test_tutorial/test_query_params/test_tutorial006_py310.py create mode 100644 tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py create mode 100644 tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py create mode 100644 tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py create mode 100644 tests/test_tutorial/test_request_files/test_tutorial002_py39.py create mode 100644 tests/test_tutorial/test_response_model/test_tutorial003_py310.py create mode 100644 tests/test_tutorial/test_response_model/test_tutorial004_py310.py create mode 100644 tests/test_tutorial/test_response_model/test_tutorial004_py39.py create mode 100644 tests/test_tutorial/test_response_model/test_tutorial005_py310.py create mode 100644 tests/test_tutorial/test_response_model/test_tutorial006_py310.py create mode 100644 tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py create mode 100644 tests/test_tutorial/test_security/test_tutorial003_py310.py create mode 100644 tests/test_tutorial/test_security/test_tutorial005_py310.py create mode 100644 tests/test_tutorial/test_security/test_tutorial005_py39.py create mode 100644 tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py create mode 100644 tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py create mode 100644 tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py create mode 100644 tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py create mode 100644 tests/test_tutorial/test_sql_databases/test_testing_databases_py310.py create mode 100644 tests/test_tutorial/test_sql_databases/test_testing_databases_py39.py create mode 100644 tests/test_tutorial/test_testing/test_main_b_py310.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7ab0f1230..21ea7c1a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] fail-fast: false steps: diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index 66220f63e..dbff7b26a 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 360fa8c4a..8f29ef316 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index 9bbf955b9..76d442855 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -148,37 +148,62 @@ You can use, for example: There are some data structures that can contain other values, like `dict`, `list`, `set` and `tuple`. And the internal values can have their own type too. -To declare those types and the internal types, you can use the standard Python module `typing`. +These types that have internal types are called "**generic**" types. And it's possible to declare them, even with their internal types. -It exists specifically to support these type hints. +To declare those types and the internal types, you can use the standard Python module `typing`. It exists specifically to support these type hints. -#### `List` +#### Newer versions of Python + +The syntax using `typing` is **compatible** with all versions, from Python 3.6 to the latest ones, including Python 3.9, Python 3.10, etc. + +As Python advances, **newer versions** come with improved support for these type annotations and in many cases you won't even need to import and use the `typing` module to declare the type annotations. + +If you can chose a more recent version of Python for your project, you will be able to take advantage of that extra simplicity. See some examples below. + +#### List For example, let's define a variable to be a `list` of `str`. -From `typing`, import `List` (with a capital `L`): +=== "Python 3.6 and above" -```Python hl_lines="1" -{!../../../docs_src/python_types/tutorial006.py!} -``` + From `typing`, import `List` (with a capital `L`): -Declare the variable, with the same colon (`:`) syntax. + ``` Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial006.py!} + ``` -As the type, put the `List`. + Declare the variable, with the same colon (`:`) syntax. -As the list is a type that contains some internal types, you put them in square brackets: + As the type, put the `List` that you imported from `typing`. -```Python hl_lines="4" -{!../../../docs_src/python_types/tutorial006.py!} -``` + As the list is a type that contains some internal types, you put them in square brackets: -!!! tip + ```Python hl_lines="4" + {!> ../../../docs_src/python_types/tutorial006.py!} + ``` + +=== "Python 3.9 and above" + + Declare the variable, with the same colon (`:`) syntax. + + As the type, put `list`. + + As the list is a type that contains some internal types, you put them in square brackets: + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial006_py39.py!} + ``` + +!!! info Those internal types in the square brackets are called "type parameters". - In this case, `str` is the type parameter passed to `List`. + In this case, `str` is the type parameter passed to `List` (or `list` in Python 3.9 and above). That means: "the variable `items` is a `list`, and each of the items in this list is a `str`". +!!! tip + If you use Python 3.9 or above, you don't have to import `List` from `typing`, you can use the same regular `list` type instead. + By doing that, your editor can provide support even while processing items from the list: @@ -189,20 +214,28 @@ Notice that the variable `item` is one of the elements in the list `items`. And still, the editor knows it is a `str`, and provides support for that. -#### `Tuple` and `Set` +#### Tuple and Set You would do the same to declare `tuple`s and `set`s: -```Python hl_lines="1 4" -{!../../../docs_src/python_types/tutorial007.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial007.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial007_py39.py!} + ``` This means: * The variable `items_t` is a `tuple` with 3 items, an `int`, another `int`, and a `str`. * The variable `items_s` is a `set`, and each of its items is of type `bytes`. -#### `Dict` +#### Dict To define a `dict`, you pass 2 type parameters, separated by commas. @@ -210,9 +243,17 @@ The first type parameter is for the keys of the `dict`. The second type parameter is for the values of the `dict`: -```Python hl_lines="1 4" -{!../../../docs_src/python_types/tutorial008.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial008.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial008.py!} + ``` This means: @@ -220,9 +261,33 @@ This means: * The keys of this `dict` are of type `str` (let's say, the name of each item). * The values of this `dict` are of type `float` (let's say, the price of each item). -#### `Optional` +#### Union -You can also use `Optional` to declare that a variable has a type, like `str`, but that it is "optional", which means that it could also be `None`: +You can declare that a variable can be any of **several types**, for example, an `int` or a `str`. + +In Python 3.6 and above (including Python 3.10) you can use the `Union` type from `typing` and put inside the square brackets the possible types to accept. + +In Python 3.10 there's also an **alternative syntax** were you can put the possible types separated by a vertical bar (`|`). + +=== "Python 3.6 and above" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial008b.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial008b_py310.py!} + ``` + +In both cases this means that `item` could be an `int` or a `str`. + +#### Possibly `None` + +You can declare that a value could have a type, like `str`, but that it could also be `None`. + +In Python 3.6 and above (including Python 3.10) you can declare it by importing and using `Optional` from the `typing` module. ```Python hl_lines="1 4" {!../../../docs_src/python_types/tutorial009.py!} @@ -230,18 +295,73 @@ You can also use `Optional` to declare that a variable has a type, like `str`, b Using `Optional[str]` instead of just `str` will let the editor help you detecting errors where you could be assuming that a value is always a `str`, when it could actually be `None` too. +`Optional[Something]` is actually a shortcut for `Union[Something, None]`, they are equivalent. + +This also means that in Python 3.10, you can use `Something | None`: + +=== "Python 3.6 and above" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial009.py!} + ``` + +=== "Python 3.6 and above - alternative" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial009b.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial009_py310.py!} + ``` + #### Generic types -These types that take type parameters in square brackets, like: +These types that take type parameters in square brackets are called **Generic types** or **Generics**, for example: -* `List` -* `Tuple` -* `Set` -* `Dict` -* `Optional` -* ...and others. +=== "Python 3.6 and above" -are called **Generic types** or **Generics**. + * `List` + * `Tuple` + * `Set` + * `Dict` + * `Union` + * `Optional` + * ...and others. + +=== "Python 3.9 and above" + + You can use the same builtin types as generics (with square brakets and types inside): + + * `list` + * `tuple` + * `set` + * `dict` + + And the same as with Python 3.6, from the `typing` module: + + * `Union` + * `Optional` + * ...and others. + +=== "Python 3.10 and above" + + You can use the same builtin types as generics (with square brakets and types inside): + + * `list` + * `tuple` + * `set` + * `dict` + + And the same as with Python 3.6, from the `typing` module: + + * `Union` + * `Optional` (the same as with Python 3.6) + * ...and others. + + In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the vertical bar (`|`) to declare unions of types. ### Classes as types @@ -275,11 +395,25 @@ Then you create an instance of that class with some values and it will validate And you get all the editor support with that resulting object. -Taken from the official Pydantic docs: +An example from the official Pydantic docs: -```Python -{!../../../docs_src/python_types/tutorial011.py!} -``` +=== "Python 3.6 and above" + + ```Python + {!> ../../../docs_src/python_types/tutorial011.py!} + ``` + +=== "Python 3.9 and above" + + ```Python + {!> ../../../docs_src/python_types/tutorial011_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python + {!> ../../../docs_src/python_types/tutorial011_py310.py!} + ``` !!! info To learn more about Pydantic, check its docs. diff --git a/docs/en/docs/tutorial/background-tasks.md b/docs/en/docs/tutorial/background-tasks.md index 6002ce075..69aeb6712 100644 --- a/docs/en/docs/tutorial/background-tasks.md +++ b/docs/en/docs/tutorial/background-tasks.md @@ -57,9 +57,17 @@ Using `BackgroundTasks` also works with the dependency injection system, you can **FastAPI** knows what to do in each case and how to re-use the same object, so that all the background tasks are merged together and are run in the background afterwards: -```Python hl_lines="13 15 22 25" -{!../../../docs_src/background_tasks/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="13 15 22 25" + {!> ../../../docs_src/background_tasks/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="11 13 20 23" + {!> ../../../docs_src/background_tasks/tutorial002_py310.py!} + ``` In this example, the messages will be written to the `log.txt` file *after* the response is sent. diff --git a/docs/en/docs/tutorial/body-fields.md b/docs/en/docs/tutorial/body-fields.md index 6b3fd8fb5..1f38a0c5c 100644 --- a/docs/en/docs/tutorial/body-fields.md +++ b/docs/en/docs/tutorial/body-fields.md @@ -6,9 +6,17 @@ The same way you can declare additional validation and metadata in *path operati First, you have to import it: -```Python hl_lines="4" -{!../../../docs_src/body_fields/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="4" + {!> ../../../docs_src/body_fields/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="2" + {!> ../../../docs_src/body_fields/tutorial001_py310.py!} + ``` !!! warning Notice that `Field` is imported directly from `pydantic`, not from `fastapi` as are all the rest (`Query`, `Path`, `Body`, etc). @@ -17,9 +25,17 @@ First, you have to import it: You can then use `Field` with model attributes: -```Python hl_lines="11-14" -{!../../../docs_src/body_fields/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="11-14" + {!> ../../../docs_src/body_fields/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="9-12" + {!> ../../../docs_src/body_fields/tutorial001_py310.py!} + ``` `Field` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc. diff --git a/docs/en/docs/tutorial/body-multiple-params.md b/docs/en/docs/tutorial/body-multiple-params.md index a4484147f..13de4c8ea 100644 --- a/docs/en/docs/tutorial/body-multiple-params.md +++ b/docs/en/docs/tutorial/body-multiple-params.md @@ -8,9 +8,17 @@ First, of course, you can mix `Path`, `Query` and request body parameter declara And you can also declare body parameters as optional, by setting the default to `None`: -```Python hl_lines="19-21" -{!../../../docs_src/body_multiple_params/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="19-21" + {!> ../../../docs_src/body_multiple_params/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="17-19" + {!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!} + ``` !!! note Notice that, in this case, the `item` that would be taken from the body is optional. As it has a `None` default value. @@ -30,9 +38,17 @@ In the previous example, the *path operations* would expect a JSON body with the But you can also declare multiple body parameters, e.g. `item` and `user`: -```Python hl_lines="22" -{!../../../docs_src/body_multiple_params/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="22" + {!> ../../../docs_src/body_multiple_params/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="20" + {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!} + ``` In this case, **FastAPI** will notice that there are more than one body parameters in the function (two parameters that are Pydantic models). @@ -71,14 +87,20 @@ If you declare it as is, because it is a singular value, **FastAPI** will assume But you can instruct **FastAPI** to treat it as another body key using `Body`: +=== "Python 3.6 and above" -```Python hl_lines="23" -{!../../../docs_src/body_multiple_params/tutorial003.py!} -``` + ```Python hl_lines="23" + {!> ../../../docs_src/body_multiple_params/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="21" + {!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!} + ``` In this case, **FastAPI** will expect a body like: - ```JSON { "item": { @@ -107,12 +129,26 @@ As, by default, singular values are interpreted as query parameters, you don't h q: Optional[str] = None ``` -as in: +Or in Python 3.10 and above: -```Python hl_lines="28" -{!../../../docs_src/body_multiple_params/tutorial004.py!} +```Python +q: str | None = None ``` +For example: + +=== "Python 3.6 and above" + + ```Python hl_lines="28" + {!> ../../../docs_src/body_multiple_params/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="26" + {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!} + ``` + !!! info `Body` also has all the same extra validation and metadata parameters as `Query`,`Path` and others you will see later. @@ -131,9 +167,17 @@ item: Item = Body(..., embed=True) as in: -```Python hl_lines="17" -{!../../../docs_src/body_multiple_params/tutorial005.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="17" + {!> ../../../docs_src/body_multiple_params/tutorial005.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="15" + {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!} + ``` In this case **FastAPI** will expect a body like: diff --git a/docs/en/docs/tutorial/body-nested-models.md b/docs/en/docs/tutorial/body-nested-models.md index 5bacf1666..fa38cfc48 100644 --- a/docs/en/docs/tutorial/body-nested-models.md +++ b/docs/en/docs/tutorial/body-nested-models.md @@ -6,9 +6,17 @@ With **FastAPI**, you can define, validate, document, and use arbitrarily deeply You can define an attribute to be a subtype. For example, a Python `list`: -```Python hl_lines="14" -{!../../../docs_src/body_nested_models/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="14" + {!> ../../../docs_src/body_nested_models/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="12" + {!> ../../../docs_src/body_nested_models/tutorial001_py310.py!} + ``` This will make `tags` be a list of items. Although it doesn't declare the type of each of the items. @@ -18,19 +26,29 @@ But Python has a specific way to declare lists with internal types, or "type par ### Import typing's `List` -First, import `List` from standard Python's `typing` module: +In Python 3.9 and above you can use the standard `list` to declare these type annotations as we'll see below. 💡 + +But in Python versions before 3.9 (3.6 and above), you first need to import `List` from standard Python's `typing` module: ```Python hl_lines="1" -{!../../../docs_src/body_nested_models/tutorial002.py!} +{!> ../../../docs_src/body_nested_models/tutorial002.py!} ``` -### Declare a `List` with a type parameter +### Declare a `list` with a type parameter To declare types that have type parameters (internal types), like `list`, `dict`, `tuple`: -* Import them from the `typing` module +* If you are in a Python version lower than 3.9, import their equivalent version from the `typing` module * Pass the internal type(s) as "type parameters" using square brackets: `[` and `]` +In Python 3.9 it would be: + +```Python +my_list: list[str] +``` + +In versions of Python before 3.9, it would be: + ```Python from typing import List @@ -43,9 +61,23 @@ Use that same standard syntax for model attributes with internal types. So, in our example, we can make `tags` be specifically a "list of strings": -```Python hl_lines="14" -{!../../../docs_src/body_nested_models/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="14" + {!> ../../../docs_src/body_nested_models/tutorial002.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="14" + {!> ../../../docs_src/body_nested_models/tutorial002_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="12" + {!> ../../../docs_src/body_nested_models/tutorial002_py310.py!} + ``` ## Set types @@ -53,11 +85,25 @@ But then we think about it, and realize that tags shouldn't repeat, they would p And Python has a special data type for sets of unique items, the `set`. -Then we can import `Set` and declare `tags` as a `set` of `str`: +Then we can declare `tags` as a set of strings: -```Python hl_lines="1 14" -{!../../../docs_src/body_nested_models/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="1 14" + {!> ../../../docs_src/body_nested_models/tutorial003.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="14" + {!> ../../../docs_src/body_nested_models/tutorial003_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="12" + {!> ../../../docs_src/body_nested_models/tutorial003_py310.py!} + ``` With this, even if you receive a request with duplicate data, it will be converted to a set of unique items. @@ -79,17 +125,45 @@ All that, arbitrarily nested. For example, we can define an `Image` model: -```Python hl_lines="9-11" -{!../../../docs_src/body_nested_models/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9-11" + {!> ../../../docs_src/body_nested_models/tutorial004.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="9-11" + {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7-9" + {!> ../../../docs_src/body_nested_models/tutorial004_py310.py!} + ``` ### Use the submodel as a type And then we can use it as the type of an attribute: -```Python hl_lines="20" -{!../../../docs_src/body_nested_models/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="20" + {!> ../../../docs_src/body_nested_models/tutorial004.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="20" + {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="18" + {!> ../../../docs_src/body_nested_models/tutorial004_py310.py!} + ``` This would mean that **FastAPI** would expect a body similar to: @@ -122,9 +196,23 @@ To see all the options you have, checkout the docs for ../../../docs_src/body_nested_models/tutorial005.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="4 10" + {!> ../../../docs_src/body_nested_models/tutorial005_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="2 8" + {!> ../../../docs_src/body_nested_models/tutorial005_py310.py!} + ``` The string will be checked to be a valid URL, and documented in JSON Schema / OpenAPI as such. @@ -132,9 +220,23 @@ The string will be checked to be a valid URL, and documented in JSON Schema / Op You can also use Pydantic models as subtypes of `list`, `set`, etc: -```Python hl_lines="20" -{!../../../docs_src/body_nested_models/tutorial006.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="20" + {!> ../../../docs_src/body_nested_models/tutorial006.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="20" + {!> ../../../docs_src/body_nested_models/tutorial006_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="18" + {!> ../../../docs_src/body_nested_models/tutorial006_py310.py!} + ``` This will expect (convert, validate, document, etc) a JSON body like: @@ -169,9 +271,23 @@ This will expect (convert, validate, document, etc) a JSON body like: You can define arbitrarily deeply nested models: -```Python hl_lines="9 14 20 23 27" -{!../../../docs_src/body_nested_models/tutorial007.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9 14 20 23 27" + {!> ../../../docs_src/body_nested_models/tutorial007.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="9 14 20 23 27" + {!> ../../../docs_src/body_nested_models/tutorial007_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7 12 18 21 25" + {!> ../../../docs_src/body_nested_models/tutorial007_py310.py!} + ``` !!! info Notice how `Offer` has a list of `Item`s, which in turn have an optional list of `Image`s @@ -184,11 +300,25 @@ If the top level value of the JSON body you expect is a JSON `array` (a Python ` images: List[Image] ``` +or in Python 3.9 and above: + +```Python +images: list[Image] +``` + as in: -```Python hl_lines="15" -{!../../../docs_src/body_nested_models/tutorial008.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="15" + {!> ../../../docs_src/body_nested_models/tutorial008.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="13" + {!> ../../../docs_src/body_nested_models/tutorial008_py39.py!} + ``` ## Editor support everywhere @@ -218,9 +348,17 @@ That's what we are going to see here. In this case, you would accept any `dict` as long as it has `int` keys with `float` values: -```Python hl_lines="9" -{!../../../docs_src/body_nested_models/tutorial009.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/body_nested_models/tutorial009.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/body_nested_models/tutorial009_py39.py!} + ``` !!! tip Have in mind that JSON only supports `str` as keys. diff --git a/docs/en/docs/tutorial/body-updates.md b/docs/en/docs/tutorial/body-updates.md index 757d7bdbc..7d8675060 100644 --- a/docs/en/docs/tutorial/body-updates.md +++ b/docs/en/docs/tutorial/body-updates.md @@ -6,9 +6,23 @@ To update an item you can use the ../../../docs_src/body_updates/tutorial001.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="30-35" + {!> ../../../docs_src/body_updates/tutorial001_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="28-33" + {!> ../../../docs_src/body_updates/tutorial001_py310.py!} + ``` `PUT` is used to receive data that should replace the existing data. @@ -53,9 +67,23 @@ That would generate a `dict` with only the data that was set when creating the ` Then you can use this to generate a `dict` with only the data that was set (sent in the request), omitting default values: -```Python hl_lines="34" -{!../../../docs_src/body_updates/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="34" + {!> ../../../docs_src/body_updates/tutorial002.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="34" + {!> ../../../docs_src/body_updates/tutorial002_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="32" + {!> ../../../docs_src/body_updates/tutorial002_py310.py!} + ``` ### Using Pydantic's `update` parameter @@ -63,9 +91,23 @@ Now, you can create a copy of the existing model using `.copy()`, and pass the ` Like `stored_item_model.copy(update=update_data)`: -```Python hl_lines="35" -{!../../../docs_src/body_updates/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="35" + {!> ../../../docs_src/body_updates/tutorial002.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="35" + {!> ../../../docs_src/body_updates/tutorial002_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="33" + {!> ../../../docs_src/body_updates/tutorial002_py310.py!} + ``` ### Partial updates recap @@ -82,9 +124,23 @@ In summary, to apply partial updates you would: * Save the data to your DB. * Return the updated model. -```Python hl_lines="30-37" -{!../../../docs_src/body_updates/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="30-37" + {!> ../../../docs_src/body_updates/tutorial002.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="30-37" + {!> ../../../docs_src/body_updates/tutorial002_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="28-35" + {!> ../../../docs_src/body_updates/tutorial002_py310.py!} + ``` !!! tip You can actually use this same technique with an HTTP `PUT` operation. diff --git a/docs/en/docs/tutorial/body.md b/docs/en/docs/tutorial/body.md index f18afaea6..81441b41e 100644 --- a/docs/en/docs/tutorial/body.md +++ b/docs/en/docs/tutorial/body.md @@ -19,9 +19,17 @@ To declare a **request** body, you use ../../../docs_src/body/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="2" + {!> ../../../docs_src/body/tutorial001_py310.py!} + ``` ## Create your data model @@ -29,9 +37,17 @@ Then you declare your data model as a class that inherits from `BaseModel`. Use standard Python types for all the attributes: -```Python hl_lines="7-11" -{!../../../docs_src/body/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="7-11" + {!> ../../../docs_src/body/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="5-9" + {!> ../../../docs_src/body/tutorial001_py310.py!} + ``` The same as when declaring query parameters, when a model attribute has a default value, it is not required. Otherwise, it is required. Use `None` to make it just optional. @@ -59,9 +75,17 @@ For example, this model above declares a JSON "`object`" (or Python `dict`) like To add it to your *path operation*, declare it the same way you declared path and query parameters: -```Python hl_lines="18" -{!../../../docs_src/body/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="18" + {!> ../../../docs_src/body/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="16" + {!> ../../../docs_src/body/tutorial001_py310.py!} + ``` ...and declare its type as the model you created, `Item`. @@ -125,9 +149,17 @@ But you would get the same editor support with ../../../docs_src/body/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="19" + {!> ../../../docs_src/body/tutorial002_py310.py!} + ``` ## Request body + path parameters @@ -135,9 +167,17 @@ You can declare path parameters and request body at the same time. **FastAPI** will recognize that the function parameters that match path parameters should be **taken from the path**, and that function parameters that are declared to be Pydantic models should be **taken from the request body**. -```Python hl_lines="17-18" -{!../../../docs_src/body/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="17-18" + {!> ../../../docs_src/body/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="15-16" + {!> ../../../docs_src/body/tutorial003_py310.py!} + ``` ## Request body + path + query parameters @@ -145,9 +185,17 @@ You can also declare **body**, **path** and **query** parameters, all at the sam **FastAPI** will recognize each of them and take the data from the correct place. -```Python hl_lines="18" -{!../../../docs_src/body/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="18" + {!> ../../../docs_src/body/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="16" + {!> ../../../docs_src/body/tutorial004_py310.py!} + ``` The function parameters will be recognized as follows: diff --git a/docs/en/docs/tutorial/cookie-params.md b/docs/en/docs/tutorial/cookie-params.md index 9aa2300c4..221cdfffb 100644 --- a/docs/en/docs/tutorial/cookie-params.md +++ b/docs/en/docs/tutorial/cookie-params.md @@ -6,9 +6,17 @@ You can define Cookie parameters the same way you define `Query` and `Path` para First import `Cookie`: -```Python hl_lines="3" -{!../../../docs_src/cookie_params/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="3" + {!> ../../../docs_src/cookie_params/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1" + {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} + ``` ## Declare `Cookie` parameters @@ -16,9 +24,17 @@ Then declare the cookie parameters using the same structure as with `Path` and ` The first value is the default value, you can pass all the extra validation or annotation parameters: -```Python hl_lines="9" -{!../../../docs_src/cookie_params/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/cookie_params/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} + ``` !!! note "Technical Details" `Cookie` is a "sister" class of `Path` and `Query`. It also inherits from the same common `Param` class. diff --git a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md index 7747e3e1b..663fff15b 100644 --- a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md @@ -6,9 +6,17 @@ Before diving deeper into the **Dependency Injection** system, let's upgrade the In the previous example, we were returning a `dict` from our dependency ("dependable"): -```Python hl_lines="9" -{!../../../docs_src/dependencies/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/dependencies/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/dependencies/tutorial001_py310.py!} + ``` But then we get a `dict` in the parameter `commons` of the *path operation function*. @@ -71,21 +79,45 @@ That also applies to callables with no parameters at all. The same as it would b Then, we can change the dependency "dependable" `common_parameters` from above to the class `CommonQueryParams`: -```Python hl_lines="11-15" -{!../../../docs_src/dependencies/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="11-15" + {!> ../../../docs_src/dependencies/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="9-13" + {!> ../../../docs_src/dependencies/tutorial002_py310.py!} + ``` Pay attention to the `__init__` method used to create the instance of the class: -```Python hl_lines="12" -{!../../../docs_src/dependencies/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="12" + {!> ../../../docs_src/dependencies/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="10" + {!> ../../../docs_src/dependencies/tutorial002_py310.py!} + ``` ...it has the same parameters as our previous `common_parameters`: -```Python hl_lines="8" -{!../../../docs_src/dependencies/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="8" + {!> ../../../docs_src/dependencies/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="6" + {!> ../../../docs_src/dependencies/tutorial001_py310.py!} + ``` Those parameters are what **FastAPI** will use to "solve" the dependency. @@ -101,9 +133,17 @@ In both cases the data will be converted, validated, documented on the OpenAPI s Now you can declare your dependency using this class. -```Python hl_lines="19" -{!../../../docs_src/dependencies/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="19" + {!> ../../../docs_src/dependencies/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="17" + {!> ../../../docs_src/dependencies/tutorial002_py310.py!} + ``` **FastAPI** calls the `CommonQueryParams` class. This creates an "instance" of that class and the instance will be passed as the parameter `commons` to your function. @@ -143,9 +183,17 @@ commons = Depends(CommonQueryParams) ..as in: -```Python hl_lines="19" -{!../../../docs_src/dependencies/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="19" + {!> ../../../docs_src/dependencies/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="17" + {!> ../../../docs_src/dependencies/tutorial003_py310.py!} + ``` But declaring the type is encouraged as that way your editor will know what will be passed as the parameter `commons`, and then it can help you with code completion, type checks, etc: @@ -179,9 +227,17 @@ You declare the dependency as the type of the parameter, and you use `Depends()` The same example would then look like: -```Python hl_lines="19" -{!../../../docs_src/dependencies/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="19" + {!> ../../../docs_src/dependencies/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="17" + {!> ../../../docs_src/dependencies/tutorial004_py310.py!} + ``` ...and **FastAPI** will know what to do. diff --git a/docs/en/docs/tutorial/dependencies/index.md b/docs/en/docs/tutorial/dependencies/index.md index cf0b5a92f..fe10facfb 100644 --- a/docs/en/docs/tutorial/dependencies/index.md +++ b/docs/en/docs/tutorial/dependencies/index.md @@ -31,9 +31,17 @@ Let's first focus on the dependency. It is just a function that can take all the same parameters that a *path operation function* can take: -```Python hl_lines="8-9" -{!../../../docs_src/dependencies/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="8-9" + {!> ../../../docs_src/dependencies/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="6-7" + {!> ../../../docs_src/dependencies/tutorial001_py310.py!} + ``` That's it. @@ -55,17 +63,33 @@ And then it just returns a `dict` containing those values. ### Import `Depends` -```Python hl_lines="3" -{!../../../docs_src/dependencies/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="3" + {!> ../../../docs_src/dependencies/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1" + {!> ../../../docs_src/dependencies/tutorial001_py310.py!} + ``` ### Declare the dependency, in the "dependant" The same way you use `Body`, `Query`, etc. with your *path operation function* parameters, use `Depends` with a new parameter: -```Python hl_lines="13 18" -{!../../../docs_src/dependencies/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="13 18" + {!> ../../../docs_src/dependencies/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="11 16" + {!> ../../../docs_src/dependencies/tutorial001_py310.py!} + ``` Although you use `Depends` in the parameters of your function the same way you use `Body`, `Query`, etc, `Depends` works a bit differently. diff --git a/docs/en/docs/tutorial/dependencies/sub-dependencies.md b/docs/en/docs/tutorial/dependencies/sub-dependencies.md index 097edb68b..51531228d 100644 --- a/docs/en/docs/tutorial/dependencies/sub-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/sub-dependencies.md @@ -6,25 +6,41 @@ They can be as **deep** as you need them to be. **FastAPI** will take care of solving them. -### First dependency "dependable" +## First dependency "dependable" You could create a first dependency ("dependable") like: -```Python hl_lines="8-9" -{!../../../docs_src/dependencies/tutorial005.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="8-9" + {!> ../../../docs_src/dependencies/tutorial005.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="6-7" + {!> ../../../docs_src/dependencies/tutorial005_py310.py!} + ``` It declares an optional query parameter `q` as a `str`, and then it just returns it. This is quite simple (not very useful), but will help us focus on how the sub-dependencies work. -### Second dependency, "dependable" and "dependant" +## Second dependency, "dependable" and "dependant" Then you can create another dependency function (a "dependable") that at the same time declares a dependency of its own (so it is a "dependant" too): -```Python hl_lines="13" -{!../../../docs_src/dependencies/tutorial005.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="13" + {!> ../../../docs_src/dependencies/tutorial005.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="11" + {!> ../../../docs_src/dependencies/tutorial005_py310.py!} + ``` Let's focus on the parameters declared: @@ -33,13 +49,21 @@ Let's focus on the parameters declared: * It also declares an optional `last_query` cookie, as a `str`. * If the user didn't provide any query `q`, we use the last query used, which we saved to a cookie before. -### Use the dependency +## Use the dependency Then we can use the dependency with: -```Python hl_lines="21" -{!../../../docs_src/dependencies/tutorial005.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="21" + {!> ../../../docs_src/dependencies/tutorial005.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="19" + {!> ../../../docs_src/dependencies/tutorial005_py310.py!} + ``` !!! info Notice that we are only declaring one dependency in the *path operation function*, the `query_or_cookie_extractor`. diff --git a/docs/en/docs/tutorial/encoder.md b/docs/en/docs/tutorial/encoder.md index a2cbe45d5..7a69c5474 100644 --- a/docs/en/docs/tutorial/encoder.md +++ b/docs/en/docs/tutorial/encoder.md @@ -20,9 +20,17 @@ You can use `jsonable_encoder` for that. It receives an object, like a Pydantic model, and returns a JSON compatible version: -```Python hl_lines="5 22" -{!../../../docs_src/encoder/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="5 22" + {!> ../../../docs_src/encoder/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="4 21" + {!> ../../../docs_src/encoder/tutorial001_py310.py!} + ``` In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`. diff --git a/docs/en/docs/tutorial/extra-data-types.md b/docs/en/docs/tutorial/extra-data-types.md index 995f0b972..a00bd3212 100644 --- a/docs/en/docs/tutorial/extra-data-types.md +++ b/docs/en/docs/tutorial/extra-data-types.md @@ -55,12 +55,28 @@ Here are some of the additional data types you can use: Here's an example *path operation* with parameters using some of the above types. -```Python hl_lines="1 3 12-16" -{!../../../docs_src/extra_data_types/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="1 3 12-16" + {!> ../../../docs_src/extra_data_types/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1 2 11-15" + {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!} + ``` Note that the parameters inside the function have their natural data type, and you can, for example, perform normal date manipulations, like: -```Python hl_lines="18-19" -{!../../../docs_src/extra_data_types/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="18-19" + {!> ../../../docs_src/extra_data_types/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="17-18" + {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!} + ``` diff --git a/docs/en/docs/tutorial/extra-models.md b/docs/en/docs/tutorial/extra-models.md index 4eced04ca..72fc74894 100644 --- a/docs/en/docs/tutorial/extra-models.md +++ b/docs/en/docs/tutorial/extra-models.md @@ -17,9 +17,17 @@ This is especially the case for user models, because: Here's a general idea of how the models could look like with their password fields and the places where they are used: -```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41" -{!../../../docs_src/extra_models/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41" + {!> ../../../docs_src/extra_models/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7 9 14 20 22 27-28 31-33 38-39" + {!> ../../../docs_src/extra_models/tutorial001_py310.py!} + ``` ### About `**user_in.dict()` @@ -150,9 +158,17 @@ All the data conversion, validation, documentation, etc. will still work as norm That way, we can declare just the differences between the models (with plaintext `password`, with `hashed_password` and without password): -```Python hl_lines="9 15-16 19-20 23-24" -{!../../../docs_src/extra_models/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9 15-16 19-20 23-24" + {!> ../../../docs_src/extra_models/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7 13-14 17-18 21-22" + {!> ../../../docs_src/extra_models/tutorial002_py310.py!} + ``` ## `Union` or `anyOf` @@ -165,19 +181,49 @@ To do that, use the standard Python type hint `Union`, include the most specific type first, followed by the less specific type. In the example below, the more specific `PlaneItem` comes before `CarItem` in `Union[PlaneItem, CarItem]`. -```Python hl_lines="1 14-15 18-20 33" -{!../../../docs_src/extra_models/tutorial003.py!} +=== "Python 3.6 and above" + + ```Python hl_lines="1 14-15 18-20 33" + {!> ../../../docs_src/extra_models/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1 14-15 18-20 33" + {!> ../../../docs_src/extra_models/tutorial003_py310.py!} + ``` + +### `Union` in Python 3.10 + +In this example we pass `Union[PlaneItem, CarItem]` as the value of the argument `response_model`. + +Because we are passing it as a **value to an argument** instead of putting it in a **type annotation**, we have to use `Union` even in Python 3.10. + +If it was in a type annotation we could have used the vertical bar, as: + +```Python +some_variable: PlaneItem | CarItem ``` +But if we put that in `response_model=PlaneItem | CarItem` we would get an error, because Python would try to perform an **invalid operation** between `PlaneItem` and `CarItem` instead of interpreting that as a type annotation. + ## List of models The same way, you can declare responses of lists of objects. -For that, use the standard Python `typing.List`: +For that, use the standard Python `typing.List` (or just `list` in Python 3.9 and above): -```Python hl_lines="1 20" -{!../../../docs_src/extra_models/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="1 20" + {!> ../../../docs_src/extra_models/tutorial004.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="18" + {!> ../../../docs_src/extra_models/tutorial004_py39.py!} + ``` ## Response with arbitrary `dict` @@ -185,11 +231,19 @@ You can also declare a response using a plain arbitrary `dict`, declaring just t This is useful if you don't know the valid field/attribute names (that would be needed for a Pydantic model) beforehand. -In this case, you can use `typing.Dict`: +In this case, you can use `typing.Dict` (or just `dict` in Python 3.9 and above): -```Python hl_lines="1 8" -{!../../../docs_src/extra_models/tutorial005.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="1 8" + {!> ../../../docs_src/extra_models/tutorial005.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="6" + {!> ../../../docs_src/extra_models/tutorial005_py39.py!} + ``` ## Recap diff --git a/docs/en/docs/tutorial/header-params.md b/docs/en/docs/tutorial/header-params.md index 57570153f..8e294416c 100644 --- a/docs/en/docs/tutorial/header-params.md +++ b/docs/en/docs/tutorial/header-params.md @@ -6,9 +6,17 @@ You can define Header parameters the same way you define `Query`, `Path` and `Co First import `Header`: -```Python hl_lines="3" -{!../../../docs_src/header_params/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="3" + {!> ../../../docs_src/header_params/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1" + {!> ../../../docs_src/header_params/tutorial001_py310.py!} + ``` ## Declare `Header` parameters @@ -16,9 +24,17 @@ Then declare the header parameters using the same structure as with `Path`, `Que The first value is the default value, you can pass all the extra validation or annotation parameters: -```Python hl_lines="9" -{!../../../docs_src/header_params/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/header_params/tutorial001_py310.py!} + ``` !!! note "Technical Details" `Header` is a "sister" class of `Path`, `Query` and `Cookie`. It also inherits from the same common `Param` class. @@ -44,14 +60,21 @@ So, you can use `user_agent` as you normally would in Python code, instead of ne If for some reason you need to disable automatic conversion of underscores to hyphens, set the parameter `convert_underscores` of `Header` to `False`: -```Python hl_lines="10" -{!../../../docs_src/header_params/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="10" + {!> ../../../docs_src/header_params/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="8" + {!> ../../../docs_src/header_params/tutorial002_py310.py!} + ``` !!! warning Before setting `convert_underscores` to `False`, bear in mind that some HTTP proxies and servers disallow the usage of headers with underscores. - ## Duplicate headers It is possible to receive duplicate headers. That means, the same header with multiple values. @@ -62,9 +85,23 @@ You will receive all the values from the duplicate header as a Python `list`. For example, to declare a header of `X-Token` that can appear more than once, you can write: -```Python hl_lines="9" -{!../../../docs_src/header_params/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial003.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial003_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/header_params/tutorial003_py310.py!} + ``` If you communicate with that *path operation* sending two HTTP headers like: diff --git a/docs/en/docs/tutorial/path-operation-configuration.md b/docs/en/docs/tutorial/path-operation-configuration.md index 0d606331d..1ff448e76 100644 --- a/docs/en/docs/tutorial/path-operation-configuration.md +++ b/docs/en/docs/tutorial/path-operation-configuration.md @@ -13,9 +13,23 @@ You can pass directly the `int` code, like `404`. But if you don't remember what each number code is for, you can use the shortcut constants in `status`: -```Python hl_lines="3 17" -{!../../../docs_src/path_operation_configuration/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="3 17" + {!> ../../../docs_src/path_operation_configuration/tutorial001.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="3 17" + {!> ../../../docs_src/path_operation_configuration/tutorial001_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1 15" + {!> ../../../docs_src/path_operation_configuration/tutorial001_py310.py!} + ``` That status code will be used in the response and will be added to the OpenAPI schema. @@ -28,9 +42,23 @@ That status code will be used in the response and will be added to the OpenAPI s You can add tags to your *path operation*, pass the parameter `tags` with a `list` of `str` (commonly just one `str`): -```Python hl_lines="17 22 27" -{!../../../docs_src/path_operation_configuration/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="17 22 27" + {!> ../../../docs_src/path_operation_configuration/tutorial002.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="17 22 27" + {!> ../../../docs_src/path_operation_configuration/tutorial002_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="15 20 25" + {!> ../../../docs_src/path_operation_configuration/tutorial002_py310.py!} + ``` They will be added to the OpenAPI schema and used by the automatic documentation interfaces: @@ -40,9 +68,23 @@ They will be added to the OpenAPI schema and used by the automatic documentation You can add a `summary` and `description`: -```Python hl_lines="20-21" -{!../../../docs_src/path_operation_configuration/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="20-21" + {!> ../../../docs_src/path_operation_configuration/tutorial003.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="20-21" + {!> ../../../docs_src/path_operation_configuration/tutorial003_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="18-19" + {!> ../../../docs_src/path_operation_configuration/tutorial003_py310.py!} + ``` ## Description from docstring @@ -50,9 +92,23 @@ As descriptions tend to be long and cover multiple lines, you can declare the *p You can write Markdown in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation). -```Python hl_lines="19-27" -{!../../../docs_src/path_operation_configuration/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="19-27" + {!> ../../../docs_src/path_operation_configuration/tutorial004.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="19-27" + {!> ../../../docs_src/path_operation_configuration/tutorial004_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="17-25" + {!> ../../../docs_src/path_operation_configuration/tutorial004_py310.py!} + ``` It will be used in the interactive docs: @@ -62,9 +118,23 @@ It will be used in the interactive docs: You can specify the response description with the parameter `response_description`: -```Python hl_lines="21" -{!../../../docs_src/path_operation_configuration/tutorial005.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="21" + {!> ../../../docs_src/path_operation_configuration/tutorial005.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="21" + {!> ../../../docs_src/path_operation_configuration/tutorial005_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="19" + {!> ../../../docs_src/path_operation_configuration/tutorial005_py310.py!} + ``` !!! info Notice that `response_description` refers specifically to the response, the `description` refers to the *path operation* in general. diff --git a/docs/en/docs/tutorial/path-params-numeric-validations.md b/docs/en/docs/tutorial/path-params-numeric-validations.md index 5da69a21b..31bf91a0e 100644 --- a/docs/en/docs/tutorial/path-params-numeric-validations.md +++ b/docs/en/docs/tutorial/path-params-numeric-validations.md @@ -6,9 +6,17 @@ The same way you can declare more validations and metadata for query parameters First, import `Path` from `fastapi`: -```Python hl_lines="3" -{!../../../docs_src/path_params_numeric_validations/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="3" + {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1" + {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} + ``` ## Declare metadata @@ -16,13 +24,21 @@ You can declare all the same parameters as for `Query`. For example, to declare a `title` metadata value for the path parameter `item_id` you can type: -```Python hl_lines="10" -{!../../../docs_src/path_params_numeric_validations/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="10" + {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="8" + {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} + ``` !!! note A path parameter is always required as it has to be part of the path. - + So, you should declare it with `...` to mark it as required. Nevertheless, even if you declared it with `None` or set a default value, it would not affect anything, it would still be always required. diff --git a/docs/en/docs/tutorial/query-params-str-validations.md b/docs/en/docs/tutorial/query-params-str-validations.md index 8deccda0b..fcac1a4e0 100644 --- a/docs/en/docs/tutorial/query-params-str-validations.md +++ b/docs/en/docs/tutorial/query-params-str-validations.md @@ -4,11 +4,19 @@ Let's take this application as example: -```Python hl_lines="9" -{!../../../docs_src/query_params_str_validations/tutorial001.py!} -``` +=== "Python 3.6 and above" -The query parameter `q` is of type `Optional[str]`, that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required. + ```Python hl_lines="9" + {!> ../../../docs_src/query_params_str_validations/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!} + ``` + +The query parameter `q` is of type `Optional[str]` (or `str | None` in Python 3.10), that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required. !!! note FastAPI will know that the value of `q` is not required because of the default value `= None`. @@ -23,17 +31,33 @@ We are going to enforce that even though `q` is optional, whenever it is provide To achieve that, first import `Query` from `fastapi`: -```Python hl_lines="3" -{!../../../docs_src/query_params_str_validations/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="3" + {!> ../../../docs_src/query_params_str_validations/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1" + {!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!} + ``` ## Use `Query` as the default value And now use it as the default value of your parameter, setting the parameter `max_length` to 50: -```Python hl_lines="9" -{!../../../docs_src/query_params_str_validations/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params_str_validations/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!} + ``` As we have to replace the default value `None` with `Query(None)`, the first parameter to `Query` serves the same purpose of defining that default value. @@ -49,10 +73,22 @@ q: Optional[str] = Query(None) q: Optional[str] = None ``` +And in Python 3.10 and above: + +```Python +q: str | None = Query(None) +``` + +...makes the parameter optional, the same as: + +```Python +q: str | None = None +``` + But it declares it explicitly as being a query parameter. !!! info - Have in mind that FastAPI cares about the part: + Have in mind that the most important part to make a parameter optional is the part: ```Python = None @@ -64,9 +100,9 @@ But it declares it explicitly as being a query parameter. = Query(None) ``` - and will use that `None` to detect that the query parameter is not required. + as it will use that `None` as the default value, and that way make the parameter **not required**. - The `Optional` part is only to allow your editor to provide better support. + The `Optional` part allows your editor to provide better support, but it is not what tells FastAPI that this parameter is not required. Then, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings: @@ -80,17 +116,33 @@ This will validate the data, show a clear error when the data is not valid, and You can also add a parameter `min_length`: -```Python hl_lines="9" -{!../../../docs_src/query_params_str_validations/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params_str_validations/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params_str_validations/tutorial003_py310.py!} + ``` ## Add regular expressions You can define a regular expression that the parameter should match: -```Python hl_lines="10" -{!../../../docs_src/query_params_str_validations/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="10" + {!> ../../../docs_src/query_params_str_validations/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="8" + {!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!} + ``` This specific regular expression checks that the received parameter value: @@ -152,9 +204,23 @@ When you define a query parameter explicitly with `Query` you can also declare i For example, to declare a query parameter `q` that can appear multiple times in the URL, you can write: -```Python hl_lines="9" -{!../../../docs_src/query_params_str_validations/tutorial011.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params_str_validations/tutorial011.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params_str_validations/tutorial011_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params_str_validations/tutorial011_py310.py!} + ``` Then, with a URL like: @@ -186,9 +252,17 @@ The interactive API docs will update accordingly, to allow multiple values: And you can also define a default `list` of values if none are provided: -```Python hl_lines="9" -{!../../../docs_src/query_params_str_validations/tutorial012.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params_str_validations/tutorial012.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params_str_validations/tutorial012_py39.py!} + ``` If you go to: @@ -209,7 +283,7 @@ the default of `q` will be: `["foo", "bar"]` and your response will be: #### Using `list` -You can also use `list` directly instead of `List[str]`: +You can also use `list` directly instead of `List[str]` (or `list[str]` in Python 3.9+): ```Python hl_lines="7" {!../../../docs_src/query_params_str_validations/tutorial013.py!} @@ -233,15 +307,31 @@ That information will be included in the generated OpenAPI and used by the docum You can add a `title`: -```Python hl_lines="10" -{!../../../docs_src/query_params_str_validations/tutorial007.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="10" + {!> ../../../docs_src/query_params_str_validations/tutorial007.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!} + ``` And a `description`: -```Python hl_lines="13" -{!../../../docs_src/query_params_str_validations/tutorial008.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="13" + {!> ../../../docs_src/query_params_str_validations/tutorial008.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="12" + {!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!} + ``` ## Alias parameters @@ -261,9 +351,17 @@ But you still need it to be exactly `item-query`... Then you can declare an `alias`, and that alias is what will be used to find the parameter value: -```Python hl_lines="9" -{!../../../docs_src/query_params_str_validations/tutorial009.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params_str_validations/tutorial009.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params_str_validations/tutorial009_py310.py!} + ``` ## Deprecating parameters @@ -273,9 +371,17 @@ You have to leave it there a while because there are clients using it, but you w Then pass the parameter `deprecated=True` to `Query`: -```Python hl_lines="18" -{!../../../docs_src/query_params_str_validations/tutorial010.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="18" + {!> ../../../docs_src/query_params_str_validations/tutorial010.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="17" + {!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!} + ``` The docs will show it like this: diff --git a/docs/en/docs/tutorial/query-params.md b/docs/en/docs/tutorial/query-params.md index 4401745ac..eec55502a 100644 --- a/docs/en/docs/tutorial/query-params.md +++ b/docs/en/docs/tutorial/query-params.md @@ -63,27 +63,38 @@ The parameter values in your function will be: The same way, you can declare optional query parameters, by setting their default to `None`: -```Python hl_lines="9" -{!../../../docs_src/query_params/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params/tutorial002_py310.py!} + ``` In this case, the function parameter `q` will be optional, and will be `None` by default. !!! check Also notice that **FastAPI** is smart enough to notice that the path parameter `item_id` is a path parameter and `q` is not, so, it's a query parameter. -!!! note - FastAPI will know that `q` is optional because of the `= None`. - - The `Optional` in `Optional[str]` is not used by FastAPI (FastAPI will only use the `str` part), but the `Optional[str]` will let your editor help you finding errors in your code. - ## Query parameter type conversion You can also declare `bool` types, and they will be converted: -```Python hl_lines="9" -{!../../../docs_src/query_params/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params/tutorial003_py310.py!} + ``` In this case, if you go to: @@ -126,9 +137,17 @@ And you don't have to declare them in any specific order. They will be detected by name: -```Python hl_lines="8 10" -{!../../../docs_src/query_params/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="8 10" + {!> ../../../docs_src/query_params/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="6 8" + {!> ../../../docs_src/query_params/tutorial004_py310.py!} + ``` ## Required query parameters @@ -184,9 +203,17 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy And of course, you can define some parameters as required, some as having a default value, and some entirely optional: -```Python hl_lines="10" -{!../../../docs_src/query_params/tutorial006.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="10" + {!> ../../../docs_src/query_params/tutorial006.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="8" + {!> ../../../docs_src/query_params/tutorial006_py310.py!} + ``` In this case, there are 3 query parameters: diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md index 68ea654c2..b7257c7eb 100644 --- a/docs/en/docs/tutorial/request-files.md +++ b/docs/en/docs/tutorial/request-files.md @@ -119,11 +119,19 @@ It's possible to upload several files at the same time. They would be associated to the same "form field" sent using "form data". -To use that, declare a `List` of `bytes` or `UploadFile`: +To use that, declare a list of `bytes` or `UploadFile`: -```Python hl_lines="10 15" -{!../../../docs_src/request_files/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="10 15" + {!> ../../../docs_src/request_files/tutorial002.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="8 13" + {!> ../../../docs_src/request_files/tutorial002_py39.py!} + ``` You will receive, as declared, a `list` of `bytes` or `UploadFile`s. diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md index e2b89ca9e..c751a9256 100644 --- a/docs/en/docs/tutorial/response-model.md +++ b/docs/en/docs/tutorial/response-model.md @@ -8,9 +8,23 @@ You can declare the model used for the response with the parameter `response_mod * `@app.delete()` * etc. -```Python hl_lines="17" -{!../../../docs_src/response_model/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="17" + {!> ../../../docs_src/response_model/tutorial001.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="17" + {!> ../../../docs_src/response_model/tutorial001_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="15" + {!> ../../../docs_src/response_model/tutorial001_py310.py!} + ``` !!! note Notice that `response_model` is a parameter of the "decorator" method (`get`, `post`, etc). Not of your *path operation function*, like all the parameters and body. @@ -35,15 +49,31 @@ But most importantly: Here we are declaring a `UserIn` model, it will contain a plaintext password: -```Python hl_lines="9 11" -{!../../../docs_src/response_model/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9 11" + {!> ../../../docs_src/response_model/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7 9" + {!> ../../../docs_src/response_model/tutorial002_py310.py!} + ``` And we are using this model to declare our input and the same model to declare our output: -```Python hl_lines="17-18" -{!../../../docs_src/response_model/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="17-18" + {!> ../../../docs_src/response_model/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="15-16" + {!> ../../../docs_src/response_model/tutorial002_py310.py!} + ``` Now, whenever a browser is creating a user with a password, the API will return the same password in the response. @@ -58,21 +88,45 @@ But if we use the same model for another *path operation*, we could be sending o We can instead create an input model with the plaintext password and an output model without it: -```Python hl_lines="9 11 16" -{!../../../docs_src/response_model/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9 11 16" + {!> ../../../docs_src/response_model/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7 9 14" + {!> ../../../docs_src/response_model/tutorial003_py310.py!} + ``` Here, even though our *path operation function* is returning the same input user that contains the password: -```Python hl_lines="24" -{!../../../docs_src/response_model/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="24" + {!> ../../../docs_src/response_model/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="22" + {!> ../../../docs_src/response_model/tutorial003_py310.py!} + ``` ...we declared the `response_model` to be our model `UserOut`, that doesn't include the password: -```Python hl_lines="22" -{!../../../docs_src/response_model/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="22" + {!> ../../../docs_src/response_model/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="20" + {!> ../../../docs_src/response_model/tutorial003_py310.py!} + ``` So, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic). @@ -90,9 +144,23 @@ And both models will be used for the interactive API documentation: Your response model could have default values, like: -```Python hl_lines="11 13-14" -{!../../../docs_src/response_model/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="11 13-14" + {!> ../../../docs_src/response_model/tutorial004.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="11 13-14" + {!> ../../../docs_src/response_model/tutorial004_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="9 11-12" + {!> ../../../docs_src/response_model/tutorial004_py310.py!} + ``` * `description: Optional[str] = None` has a default of `None`. * `tax: float = 10.5` has a default of `10.5`. @@ -106,9 +174,23 @@ For example, if you have models with many optional attributes in a NoSQL databas You can set the *path operation decorator* parameter `response_model_exclude_unset=True`: -```Python hl_lines="24" -{!../../../docs_src/response_model/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="24" + {!> ../../../docs_src/response_model/tutorial004.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="24" + {!> ../../../docs_src/response_model/tutorial004_py39.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="22" + {!> ../../../docs_src/response_model/tutorial004_py310.py!} + ``` and those default values won't be included in the response, only the values actually set. @@ -185,9 +267,17 @@ This can be used as a quick shortcut if you have only one Pydantic model and wan This also applies to `response_model_by_alias` that works similarly. -```Python hl_lines="31 37" -{!../../../docs_src/response_model/tutorial005.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="31 37" + {!> ../../../docs_src/response_model/tutorial005.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="29 35" + {!> ../../../docs_src/response_model/tutorial005_py310.py!} + ``` !!! tip The syntax `{"name", "description"}` creates a `set` with those two values. @@ -198,9 +288,17 @@ This can be used as a quick shortcut if you have only one Pydantic model and wan If you forget to use a `set` and use a `list` or `tuple` instead, FastAPI will still convert it to a `set` and it will work correctly: -```Python hl_lines="31 37" -{!../../../docs_src/response_model/tutorial006.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="31 37" + {!> ../../../docs_src/response_model/tutorial006.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="29 35" + {!> ../../../docs_src/response_model/tutorial006_py310.py!} + ``` ## Recap diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md index 71f9a3918..c69df51dc 100644 --- a/docs/en/docs/tutorial/schema-extra-example.md +++ b/docs/en/docs/tutorial/schema-extra-example.md @@ -8,9 +8,17 @@ Here are several ways to do it. You can declare an `example` for a Pydantic model using `Config` and `schema_extra`, as described in Pydantic's docs: Schema customization: -```Python hl_lines="15-23" -{!../../../docs_src/schema_extra_example/tutorial001.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="15-23" + {!> ../../../docs_src/schema_extra_example/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="13-21" + {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!} + ``` That extra info will be added as-is to the output **JSON Schema** for that model, and it will be used in the API docs. @@ -25,9 +33,17 @@ When using `Field()` with Pydantic models, you can also declare extra info for t You can use this to add `example` for each field: -```Python hl_lines="4 10-13" -{!../../../docs_src/schema_extra_example/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="4 10-13" + {!> ../../../docs_src/schema_extra_example/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="2 8-11" + {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!} + ``` !!! warning Keep in mind that those extra arguments passed won't add any validation, only extra information, for documentation purposes. @@ -50,9 +66,17 @@ you can also declare a data `example` or a group of `examples` with additional i Here we pass an `example` of the data expected in `Body()`: -```Python hl_lines="21-26" -{!../../../docs_src/schema_extra_example/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="21-26" + {!> ../../../docs_src/schema_extra_example/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="19-24" + {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!} + ``` ### Example in the docs UI @@ -73,9 +97,17 @@ Each specific example `dict` in the `examples` can contain: * `value`: This is the actual example shown, e.g. a `dict`. * `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`. -```Python hl_lines="22-48" -{!../../../docs_src/schema_extra_example/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="22-48" + {!> ../../../docs_src/schema_extra_example/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="20-46" + {!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!} + ``` ### Examples in the docs UI diff --git a/docs/en/docs/tutorial/security/get-current-user.md b/docs/en/docs/tutorial/security/get-current-user.md index a41db2b67..13e867216 100644 --- a/docs/en/docs/tutorial/security/get-current-user.md +++ b/docs/en/docs/tutorial/security/get-current-user.md @@ -16,9 +16,17 @@ First, let's create a Pydantic user model. The same way we use Pydantic to declare bodies, we can use it anywhere else: -```Python hl_lines="5 12-16" -{!../../../docs_src/security/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="5 12-16" + {!> ../../../docs_src/security/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="3 10-14" + {!> ../../../docs_src/security/tutorial002_py310.py!} + ``` ## Create a `get_current_user` dependency @@ -30,25 +38,49 @@ Remember that dependencies can have sub-dependencies? The same as we were doing before in the *path operation* directly, our new dependency `get_current_user` will receive a `token` as a `str` from the sub-dependency `oauth2_scheme`: -```Python hl_lines="25" -{!../../../docs_src/security/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="25" + {!> ../../../docs_src/security/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="23" + {!> ../../../docs_src/security/tutorial002_py310.py!} + ``` ## Get the user `get_current_user` will use a (fake) utility function we created, that takes a token as a `str` and returns our Pydantic `User` model: -```Python hl_lines="19-22 26-27" -{!../../../docs_src/security/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="19-22 26-27" + {!> ../../../docs_src/security/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="17-20 24-25" + {!> ../../../docs_src/security/tutorial002_py310.py!} + ``` ## Inject the current user So now we can use the same `Depends` with our `get_current_user` in the *path operation*: -```Python hl_lines="31" -{!../../../docs_src/security/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="31" + {!> ../../../docs_src/security/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="29" + {!> ../../../docs_src/security/tutorial002_py310.py!} + ``` Notice that we declare the type of `current_user` as the Pydantic model `User`. @@ -64,7 +96,6 @@ This will help us inside of the function with all the completion and type checks We are not restricted to having only one dependency that can return that type of data. - ## Other models You can now get the current user directly in the *path operation functions* and deal with the security mechanisms at the **Dependency Injection** level, using `Depends`. @@ -81,7 +112,6 @@ You actually don't have users that log in to your application but robots, bots, Just use any kind of model, any kind of class, any kind of database that you need for your application. **FastAPI** has you covered with the dependency injection system. - ## Code size This example might seem verbose. Have in mind that we are mixing security, data models, utility functions and *path operations* in the same file. @@ -98,9 +128,17 @@ And all of them (or any portion of them that you want) can take the advantage of And all these thousands of *path operations* can be as small as 3 lines: -```Python hl_lines="30-32" -{!../../../docs_src/security/tutorial002.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="30-32" + {!> ../../../docs_src/security/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="28-30" + {!> ../../../docs_src/security/tutorial002_py310.py!} + ``` ## Recap diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index f88cf23c0..09557f1ac 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -109,9 +109,17 @@ And another utility to verify if a received password matches the hash stored. And another one to authenticate and return a user. -```Python hl_lines="7 48 55-56 59-60 69-75" -{!../../../docs_src/security/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="7 48 55-56 59-60 69-75" + {!> ../../../docs_src/security/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="6 47 54-55 58-59 68-74" + {!> ../../../docs_src/security/tutorial004_py310.py!} + ``` !!! note If you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`. @@ -144,9 +152,17 @@ Define a Pydantic Model that will be used in the token endpoint for the response Create a utility function to generate a new access token. -```Python hl_lines="6 12-14 28-30 78-86" -{!../../../docs_src/security/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="6 12-14 28-30 78-86" + {!> ../../../docs_src/security/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="5 11-13 27-29 77-85" + {!> ../../../docs_src/security/tutorial004_py310.py!} + ``` ## Update the dependencies @@ -156,9 +172,17 @@ Decode the received token, verify it, and return the current user. If the token is invalid, return an HTTP error right away. -```Python hl_lines="89-106" -{!../../../docs_src/security/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="89-106" + {!> ../../../docs_src/security/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="88-105" + {!> ../../../docs_src/security/tutorial004_py310.py!} + ``` ## Update the `/token` *path operation* @@ -166,9 +190,17 @@ Create a `timedelta` with the expiration time of the token. Create a real JWT access token and return it. -```Python hl_lines="115-128" -{!../../../docs_src/security/tutorial004.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="115-128" + {!> ../../../docs_src/security/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="114-127" + {!> ../../../docs_src/security/tutorial004_py310.py!} + ``` ### Technical details about the JWT "subject" `sub` diff --git a/docs/en/docs/tutorial/security/simple-oauth2.md b/docs/en/docs/tutorial/security/simple-oauth2.md index 2aa747847..505b223b1 100644 --- a/docs/en/docs/tutorial/security/simple-oauth2.md +++ b/docs/en/docs/tutorial/security/simple-oauth2.md @@ -49,9 +49,17 @@ Now let's use the utilities provided by **FastAPI** to handle this. First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` in the *path operation* for `/token`: -```Python hl_lines="4 76" -{!../../../docs_src/security/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="4 76" + {!> ../../../docs_src/security/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="2 74" + {!> ../../../docs_src/security/tutorial003_py310.py!} + ``` `OAuth2PasswordRequestForm` is a class dependency that declares a form body with: @@ -90,9 +98,17 @@ If there is no such user, we return an error saying "incorrect username or passw For the error, we use the exception `HTTPException`: -```Python hl_lines="3 77-79" -{!../../../docs_src/security/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="3 77-79" + {!> ../../../docs_src/security/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1 75-77" + {!> ../../../docs_src/security/tutorial003_py310.py!} + ``` ### Check the password @@ -118,9 +134,17 @@ If your database is stolen, the thief won't have your users' plaintext passwords So, the thief won't be able to try to use those same passwords in another system (as many users use the same password everywhere, this would be dangerous). -```Python hl_lines="80-83" -{!../../../docs_src/security/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="80-83" + {!> ../../../docs_src/security/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="78-81" + {!> ../../../docs_src/security/tutorial003_py310.py!} + ``` #### About `**user_dict` @@ -156,9 +180,17 @@ For this simple example, we are going to just be completely insecure and return But for now, let's focus on the specific details we need. -```Python hl_lines="85" -{!../../../docs_src/security/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="85" + {!> ../../../docs_src/security/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="83" + {!> ../../../docs_src/security/tutorial003_py310.py!} + ``` !!! tip By the spec, you should return a JSON with an `access_token` and a `token_type`, the same as in this example. @@ -181,9 +213,17 @@ Both of these dependencies will just return an HTTP error if the user doesn't ex So, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active: -```Python hl_lines="58-67 69-72 90" -{!../../../docs_src/security/tutorial003.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="58-66 69-72 90" + {!> ../../../docs_src/security/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="55-64 67-70 88" + {!> ../../../docs_src/security/tutorial003_py310.py!} + ``` !!! info The additional header `WWW-Authenticate` with value `Bearer` we are returning here is also part of the spec. diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md index e8ebb29c8..9dc2f64c6 100644 --- a/docs/en/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -248,9 +248,23 @@ So, the user will also have a `password` when creating it. But for security, the `password` won't be in other Pydantic *models*, for example, it won't be sent from the API when reading a user. -```Python hl_lines="3 6-8 11-12 23-24 27-28" -{!../../../docs_src/sql_databases/sql_app/schemas.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="3 6-8 11-12 23-24 27-28" + {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="3 6-8 11-12 23-24 27-28" + {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="1 4-6 9-10 21-22 25-26" + {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!} + ``` #### SQLAlchemy style and Pydantic style @@ -278,9 +292,23 @@ The same way, when reading a user, we can now declare that `items` will contain Not only the IDs of those items, but all the data that we defined in the Pydantic *model* for reading items: `Item`. -```Python hl_lines="15-17 31-34" -{!../../../docs_src/sql_databases/sql_app/schemas.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="15-17 31-34" + {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="15-17 31-34" + {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="13-15 29-32" + {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!} + ``` !!! tip Notice that the `User`, the Pydantic *model* that will be used when reading a user (returning it from the API) doesn't include the `password`. @@ -293,9 +321,23 @@ This ../../../docs_src/sql_databases/sql_app/schemas.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="15 19-20 31 36-37" + {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="13 17-18 29 34-35" + {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!} + ``` !!! tip Notice it's assigning a value with `=`, like: @@ -425,9 +467,17 @@ And now in the file `sql_app/main.py` let's integrate and use all the other part In a very simplistic way create the database tables: -```Python hl_lines="9" -{!../../../docs_src/sql_databases/sql_app/main.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/sql_databases/sql_app/main.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} + ``` #### Alembic Note @@ -451,9 +501,17 @@ For that, we will create a new dependency with `yield`, as explained before in t Our dependency will create a new SQLAlchemy `SessionLocal` that will be used in a single request, and then close it once the request is finished. -```Python hl_lines="15-20" -{!../../../docs_src/sql_databases/sql_app/main.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="15-20" + {!> ../../../docs_src/sql_databases/sql_app/main.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="13-18" + {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} + ``` !!! info We put the creation of the `SessionLocal()` and handling of the requests in a `try` block. @@ -468,9 +526,17 @@ And then, when using the dependency in a *path operation function*, we declare i This will then give us better editor support inside the *path operation function*, because the editor will know that the `db` parameter is of type `Session`: -```Python hl_lines="24 32 38 47 53" -{!../../../docs_src/sql_databases/sql_app/main.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="24 32 38 47 53" + {!> ../../../docs_src/sql_databases/sql_app/main.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="22 30 36 45 51" + {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} + ``` !!! info "Technical Details" The parameter `db` is actually of type `SessionLocal`, but this class (created with `sessionmaker()`) is a "proxy" of a SQLAlchemy `Session`, so, the editor doesn't really know what methods are provided. @@ -481,9 +547,17 @@ This will then give us better editor support inside the *path operation function Now, finally, here's the standard **FastAPI** *path operations* code. -```Python hl_lines="23-28 31-34 37-42 45-49 52-55" -{!../../../docs_src/sql_databases/sql_app/main.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="23-28 31-34 37-42 45-49 52-55" + {!> ../../../docs_src/sql_databases/sql_app/main.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="21-26 29-32 35-40 43-47 50-53" + {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} + ``` We are creating the database session before each request in the dependency with `yield`, and then closing it afterwards. @@ -566,9 +640,23 @@ For example, in a background task worker with ../../../docs_src/sql_databases/sql_app/schemas.py!} + ``` + +=== "Python 3.9 and above" + + ```Python + {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} + ``` + +=== "Python 3.10 and above" + + ```Python + {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!} + ``` * `sql_app/crud.py`: @@ -578,9 +666,17 @@ For example, in a background task worker with ../../../docs_src/sql_databases/sql_app/main.py!} + ``` + +=== "Python 3.9 and above" + + ```Python + {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} + ``` ## Check it @@ -629,9 +725,17 @@ A "middleware" is basically a function that is always executed for each request, The middleware we'll add (just a function) will create a new SQLAlchemy `SessionLocal` for each request, add it to the request and then close it once the request is finished. -```Python hl_lines="14-22" -{!../../../docs_src/sql_databases/sql_app/alt_main.py!} -``` +=== "Python 3.6 and above" + + ```Python hl_lines="14-22" + {!> ../../../docs_src/sql_databases/sql_app/alt_main.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="12-20" + {!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!} + ``` !!! info We put the creation of the `SessionLocal()` and handling of the requests in a `try` block. diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md index 9c9a8270c..7e2ae84d0 100644 --- a/docs/en/docs/tutorial/testing.md +++ b/docs/en/docs/tutorial/testing.md @@ -65,7 +65,7 @@ Now let's extend this example and add more details to see how to test different ### Extended **FastAPI** app file -Let's say you have a file `main_b.py` with your **FastAPI** app. +Let's say that now the file `main.py` with your **FastAPI** app has some other **path operations**. It has a `GET` operation that could return an error. @@ -73,16 +73,24 @@ It has a `POST` operation that could return several errors. Both *path operations* require an `X-Token` header. -```Python -{!../../../docs_src/app_testing/main_b.py!} -``` +=== "Python 3.6 and above" + + ```Python + {!> ../../../docs_src/app_testing/app_b/main.py!} + ``` + +=== "Python 3.10 and above" + + ```Python + {!> ../../../docs_src/app_testing/app_b_py310/main.py!} + ``` ### Extended testing file -You could then have a `test_main_b.py`, the same as before, with the extended tests: +You could then update `test_main.py` with the extended tests: ```Python -{!../../../docs_src/app_testing/test_main_b.py!} +{!> ../../../docs_src/app_testing/app_b/test_main.py!} ``` Whenever you need the client to pass information in the request and you don't know how to, you can search (Google) how to do it in `requests`. diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 5bdd2c54a..b3716f508 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: img/icon-white.svg diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index a4bc41154..06b015a1d 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index ff16e1d78..c42f92b8a 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index d70d2b3c3..0dc34a14f 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index e6d01fbde..18afbd547 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 39fd8a211..327fe862a 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 1d4d30913..5ffb71877 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 3c1351a12..724dc2725 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index f202f306d..f36ecf49d 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 6e17c287e..eb2597de7 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index d9c3dad4c..5afe0a665 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index f6ed7f5b9..40ba6d522 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index d0de8cc0e..a116d90a3 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index a929e3388..33d40129a 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -20,7 +20,6 @@ theme: features: - search.suggest - search.highlight - - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs_src/app_testing/app_b/__init__.py b/docs_src/app_testing/app_b/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/app_testing/main_b.py b/docs_src/app_testing/app_b/main.py similarity index 100% rename from docs_src/app_testing/main_b.py rename to docs_src/app_testing/app_b/main.py diff --git a/docs_src/app_testing/test_main_b.py b/docs_src/app_testing/app_b/test_main.py similarity index 98% rename from docs_src/app_testing/test_main_b.py rename to docs_src/app_testing/app_b/test_main.py index 83cc7d255..d186b8ecb 100644 --- a/docs_src/app_testing/test_main_b.py +++ b/docs_src/app_testing/app_b/test_main.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from .main_b import app +from .main import app client = TestClient(app) diff --git a/docs_src/app_testing/app_b_py310/__init__.py b/docs_src/app_testing/app_b_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/app_testing/app_b_py310/main.py b/docs_src/app_testing/app_b_py310/main.py new file mode 100644 index 000000000..d44ab9e7c --- /dev/null +++ b/docs_src/app_testing/app_b_py310/main.py @@ -0,0 +1,36 @@ +from fastapi import FastAPI, Header, HTTPException +from pydantic import BaseModel + +fake_secret_token = "coneofsilence" + +fake_db = { + "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"}, + "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"}, +} + +app = FastAPI() + + +class Item(BaseModel): + id: str + title: str + description: str | None = None + + +@app.get("/items/{item_id}", response_model=Item) +async def read_main(item_id: str, x_token: str = Header(...)): + if x_token != fake_secret_token: + raise HTTPException(status_code=400, detail="Invalid X-Token header") + if item_id not in fake_db: + raise HTTPException(status_code=404, detail="Item not found") + return fake_db[item_id] + + +@app.post("/items/", response_model=Item) +async def create_item(item: Item, x_token: str = Header(...)): + if x_token != fake_secret_token: + raise HTTPException(status_code=400, detail="Invalid X-Token header") + if item.id in fake_db: + raise HTTPException(status_code=400, detail="Item already exists") + fake_db[item.id] = item + return item diff --git a/docs_src/app_testing/app_b_py310/test_main.py b/docs_src/app_testing/app_b_py310/test_main.py new file mode 100644 index 000000000..d186b8ecb --- /dev/null +++ b/docs_src/app_testing/app_b_py310/test_main.py @@ -0,0 +1,65 @@ +from fastapi.testclient import TestClient + +from .main import app + +client = TestClient(app) + + +def test_read_item(): + response = client.get("/items/foo", headers={"X-Token": "coneofsilence"}) + assert response.status_code == 200 + assert response.json() == { + "id": "foo", + "title": "Foo", + "description": "There goes my hero", + } + + +def test_read_item_bad_token(): + response = client.get("/items/foo", headers={"X-Token": "hailhydra"}) + assert response.status_code == 400 + assert response.json() == {"detail": "Invalid X-Token header"} + + +def test_read_inexistent_item(): + response = client.get("/items/baz", headers={"X-Token": "coneofsilence"}) + assert response.status_code == 404 + assert response.json() == {"detail": "Item not found"} + + +def test_create_item(): + response = client.post( + "/items/", + headers={"X-Token": "coneofsilence"}, + json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"}, + ) + assert response.status_code == 200 + assert response.json() == { + "id": "foobar", + "title": "Foo Bar", + "description": "The Foo Barters", + } + + +def test_create_item_bad_token(): + response = client.post( + "/items/", + headers={"X-Token": "hailhydra"}, + json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"}, + ) + assert response.status_code == 400 + assert response.json() == {"detail": "Invalid X-Token header"} + + +def test_create_existing_item(): + response = client.post( + "/items/", + headers={"X-Token": "coneofsilence"}, + json={ + "id": "foo", + "title": "The Foo ID Stealers", + "description": "There goes my stealer", + }, + ) + assert response.status_code == 400 + assert response.json() == {"detail": "Item already exists"} diff --git a/docs_src/background_tasks/tutorial002_py310.py b/docs_src/background_tasks/tutorial002_py310.py new file mode 100644 index 000000000..626af1358 --- /dev/null +++ b/docs_src/background_tasks/tutorial002_py310.py @@ -0,0 +1,24 @@ +from fastapi import BackgroundTasks, Depends, FastAPI + +app = FastAPI() + + +def write_log(message: str): + with open("log.txt", mode="a") as log: + log.write(message) + + +def get_query(background_tasks: BackgroundTasks, q: str | None = None): + if q: + message = f"found query: {q}\n" + background_tasks.add_task(write_log, message) + return q + + +@app.post("/send-notification/{email}") +async def send_notification( + email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query) +): + message = f"message to {email}\n" + background_tasks.add_task(write_log, message) + return {"message": "Message sent"} diff --git a/docs_src/body/tutorial001_py310.py b/docs_src/body/tutorial001_py310.py new file mode 100644 index 000000000..b71a52b62 --- /dev/null +++ b/docs_src/body/tutorial001_py310.py @@ -0,0 +1,17 @@ +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +app = FastAPI() + + +@app.post("/items/") +async def create_item(item: Item): + return item diff --git a/docs_src/body/tutorial002_py310.py b/docs_src/body/tutorial002_py310.py new file mode 100644 index 000000000..8928b72b8 --- /dev/null +++ b/docs_src/body/tutorial002_py310.py @@ -0,0 +1,21 @@ +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +app = FastAPI() + + +@app.post("/items/") +async def create_item(item: Item): + item_dict = item.dict() + if item.tax: + price_with_tax = item.price + item.tax + item_dict.update({"price_with_tax": price_with_tax}) + return item_dict diff --git a/docs_src/body/tutorial003_py310.py b/docs_src/body/tutorial003_py310.py new file mode 100644 index 000000000..a936f28fd --- /dev/null +++ b/docs_src/body/tutorial003_py310.py @@ -0,0 +1,17 @@ +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +app = FastAPI() + + +@app.put("/items/{item_id}") +async def create_item(item_id: int, item: Item): + return {"item_id": item_id, **item.dict()} diff --git a/docs_src/body/tutorial004_py310.py b/docs_src/body/tutorial004_py310.py new file mode 100644 index 000000000..60cfd9610 --- /dev/null +++ b/docs_src/body/tutorial004_py310.py @@ -0,0 +1,20 @@ +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +app = FastAPI() + + +@app.put("/items/{item_id}") +async def create_item(item_id: int, item: Item, q: str | None = None): + result = {"item_id": item_id, **item.dict()} + if q: + result.update({"q": q}) + return result diff --git a/docs_src/body_fields/tutorial001_py310.py b/docs_src/body_fields/tutorial001_py310.py new file mode 100644 index 000000000..01e02a050 --- /dev/null +++ b/docs_src/body_fields/tutorial001_py310.py @@ -0,0 +1,19 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel, Field + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = Field( + None, title="The description of the item", max_length=300 + ) + price: float = Field(..., gt=0, description="The price must be greater than zero") + tax: float | None = None + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item = Body(..., embed=True)): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_multiple_params/tutorial001_py310.py b/docs_src/body_multiple_params/tutorial001_py310.py new file mode 100644 index 000000000..b08d397b3 --- /dev/null +++ b/docs_src/body_multiple_params/tutorial001_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI, Path +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000), + q: str | None = None, + item: Item | None = None, +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + if item: + results.update({"item": item}) + return results diff --git a/docs_src/body_multiple_params/tutorial002_py310.py b/docs_src/body_multiple_params/tutorial002_py310.py new file mode 100644 index 000000000..2c4eb824c --- /dev/null +++ b/docs_src/body_multiple_params/tutorial002_py310.py @@ -0,0 +1,22 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +class User(BaseModel): + username: str + full_name: str | None = None + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item, user: User): + results = {"item_id": item_id, "item": item, "user": user} + return results diff --git a/docs_src/body_multiple_params/tutorial003_py310.py b/docs_src/body_multiple_params/tutorial003_py310.py new file mode 100644 index 000000000..9ddbda3f7 --- /dev/null +++ b/docs_src/body_multiple_params/tutorial003_py310.py @@ -0,0 +1,24 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +class User(BaseModel): + username: str + full_name: str | None = None + + +@app.put("/items/{item_id}") +async def update_item( + item_id: int, item: Item, user: User, importance: int = Body(...) +): + results = {"item_id": item_id, "item": item, "user": user, "importance": importance} + return results diff --git a/docs_src/body_multiple_params/tutorial004_py310.py b/docs_src/body_multiple_params/tutorial004_py310.py new file mode 100644 index 000000000..77321300e --- /dev/null +++ b/docs_src/body_multiple_params/tutorial004_py310.py @@ -0,0 +1,31 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +class User(BaseModel): + username: str + full_name: str | None = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Item, + user: User, + importance: int = Body(..., gt=0), + q: str | None = None +): + results = {"item_id": item_id, "item": item, "user": user, "importance": importance} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/body_multiple_params/tutorial005_py310.py b/docs_src/body_multiple_params/tutorial005_py310.py new file mode 100644 index 000000000..97b213b16 --- /dev/null +++ b/docs_src/body_multiple_params/tutorial005_py310.py @@ -0,0 +1,17 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item = Body(..., embed=True)): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial001_py310.py b/docs_src/body_nested_models/tutorial001_py310.py new file mode 100644 index 000000000..d89be35d4 --- /dev/null +++ b/docs_src/body_nested_models/tutorial001_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: list = [] + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial002_py310.py b/docs_src/body_nested_models/tutorial002_py310.py new file mode 100644 index 000000000..71340e9fd --- /dev/null +++ b/docs_src/body_nested_models/tutorial002_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: list[str] = [] + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial002_py39.py b/docs_src/body_nested_models/tutorial002_py39.py new file mode 100644 index 000000000..af523a74e --- /dev/null +++ b/docs_src/body_nested_models/tutorial002_py39.py @@ -0,0 +1,20 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: list[str] = [] + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial003_py310.py b/docs_src/body_nested_models/tutorial003_py310.py new file mode 100644 index 000000000..194f2dc23 --- /dev/null +++ b/docs_src/body_nested_models/tutorial003_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = set() + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial003_py39.py b/docs_src/body_nested_models/tutorial003_py39.py new file mode 100644 index 000000000..931d92f88 --- /dev/null +++ b/docs_src/body_nested_models/tutorial003_py39.py @@ -0,0 +1,20 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = set() + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial004_py310.py b/docs_src/body_nested_models/tutorial004_py310.py new file mode 100644 index 000000000..ab0b63db1 --- /dev/null +++ b/docs_src/body_nested_models/tutorial004_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Image(BaseModel): + url: str + name: str + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = [] + image: Image | None = None + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial004_py39.py b/docs_src/body_nested_models/tutorial004_py39.py new file mode 100644 index 000000000..19985ec7a --- /dev/null +++ b/docs_src/body_nested_models/tutorial004_py39.py @@ -0,0 +1,26 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Image(BaseModel): + url: str + name: str + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = [] + image: Optional[Image] = None + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial005_py310.py b/docs_src/body_nested_models/tutorial005_py310.py new file mode 100644 index 000000000..009628453 --- /dev/null +++ b/docs_src/body_nested_models/tutorial005_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from pydantic import BaseModel, HttpUrl + +app = FastAPI() + + +class Image(BaseModel): + url: HttpUrl + name: str + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = set() + image: Image | None = None + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial005_py39.py b/docs_src/body_nested_models/tutorial005_py39.py new file mode 100644 index 000000000..504551883 --- /dev/null +++ b/docs_src/body_nested_models/tutorial005_py39.py @@ -0,0 +1,26 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel, HttpUrl + +app = FastAPI() + + +class Image(BaseModel): + url: HttpUrl + name: str + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = set() + image: Optional[Image] = None + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial006_py310.py b/docs_src/body_nested_models/tutorial006_py310.py new file mode 100644 index 000000000..c87cda3c8 --- /dev/null +++ b/docs_src/body_nested_models/tutorial006_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from pydantic import BaseModel, HttpUrl + +app = FastAPI() + + +class Image(BaseModel): + url: HttpUrl + name: str + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = set() + images: list[Image] | None = None + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial006_py39.py b/docs_src/body_nested_models/tutorial006_py39.py new file mode 100644 index 000000000..61898178e --- /dev/null +++ b/docs_src/body_nested_models/tutorial006_py39.py @@ -0,0 +1,26 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel, HttpUrl + +app = FastAPI() + + +class Image(BaseModel): + url: HttpUrl + name: str + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = set() + images: Optional[list[Image]] = None + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/body_nested_models/tutorial007_py310.py b/docs_src/body_nested_models/tutorial007_py310.py new file mode 100644 index 000000000..665ac56e5 --- /dev/null +++ b/docs_src/body_nested_models/tutorial007_py310.py @@ -0,0 +1,30 @@ +from fastapi import FastAPI +from pydantic import BaseModel, HttpUrl + +app = FastAPI() + + +class Image(BaseModel): + url: HttpUrl + name: str + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = set() + images: list[Image] | None = None + + +class Offer(BaseModel): + name: str + description: str | None = None + price: float + items: list[Item] + + +@app.post("/offers/") +async def create_offer(offer: Offer): + return offer diff --git a/docs_src/body_nested_models/tutorial007_py39.py b/docs_src/body_nested_models/tutorial007_py39.py new file mode 100644 index 000000000..0c7d32fbb --- /dev/null +++ b/docs_src/body_nested_models/tutorial007_py39.py @@ -0,0 +1,32 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel, HttpUrl + +app = FastAPI() + + +class Image(BaseModel): + url: HttpUrl + name: str + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = set() + images: Optional[list[Image]] = None + + +class Offer(BaseModel): + name: str + description: Optional[str] = None + price: float + items: list[Item] + + +@app.post("/offers/") +async def create_offer(offer: Offer): + return offer diff --git a/docs_src/body_nested_models/tutorial008_py39.py b/docs_src/body_nested_models/tutorial008_py39.py new file mode 100644 index 000000000..854a7a5a4 --- /dev/null +++ b/docs_src/body_nested_models/tutorial008_py39.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI +from pydantic import BaseModel, HttpUrl + +app = FastAPI() + + +class Image(BaseModel): + url: HttpUrl + name: str + + +@app.post("/images/multiple/") +async def create_multiple_images(images: list[Image]): + return images diff --git a/docs_src/body_nested_models/tutorial009_py39.py b/docs_src/body_nested_models/tutorial009_py39.py new file mode 100644 index 000000000..59c1e5082 --- /dev/null +++ b/docs_src/body_nested_models/tutorial009_py39.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.post("/index-weights/") +async def create_index_weights(weights: dict[int, float]): + return weights diff --git a/docs_src/body_updates/tutorial001_py310.py b/docs_src/body_updates/tutorial001_py310.py new file mode 100644 index 000000000..d275d7f84 --- /dev/null +++ b/docs_src/body_updates/tutorial001_py310.py @@ -0,0 +1,32 @@ +from fastapi import FastAPI +from fastapi.encoders import jsonable_encoder +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str | None = None + description: str | None = None + price: float | None = None + tax: float = 10.5 + tags: list[str] = [] + + +items = { + "foo": {"name": "Foo", "price": 50.2}, + "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, + "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, +} + + +@app.get("/items/{item_id}", response_model=Item) +async def read_item(item_id: str): + return items[item_id] + + +@app.put("/items/{item_id}", response_model=Item) +async def update_item(item_id: str, item: Item): + update_item_encoded = jsonable_encoder(item) + items[item_id] = update_item_encoded + return update_item_encoded diff --git a/docs_src/body_updates/tutorial001_py39.py b/docs_src/body_updates/tutorial001_py39.py new file mode 100644 index 000000000..5d5388b56 --- /dev/null +++ b/docs_src/body_updates/tutorial001_py39.py @@ -0,0 +1,34 @@ +from typing import Optional + +from fastapi import FastAPI +from fastapi.encoders import jsonable_encoder +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: Optional[str] = None + description: Optional[str] = None + price: Optional[float] = None + tax: float = 10.5 + tags: list[str] = [] + + +items = { + "foo": {"name": "Foo", "price": 50.2}, + "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, + "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, +} + + +@app.get("/items/{item_id}", response_model=Item) +async def read_item(item_id: str): + return items[item_id] + + +@app.put("/items/{item_id}", response_model=Item) +async def update_item(item_id: str, item: Item): + update_item_encoded = jsonable_encoder(item) + items[item_id] = update_item_encoded + return update_item_encoded diff --git a/docs_src/body_updates/tutorial002_py310.py b/docs_src/body_updates/tutorial002_py310.py new file mode 100644 index 000000000..349841496 --- /dev/null +++ b/docs_src/body_updates/tutorial002_py310.py @@ -0,0 +1,35 @@ +from fastapi import FastAPI +from fastapi.encoders import jsonable_encoder +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str | None = None + description: str | None = None + price: float | None = None + tax: float = 10.5 + tags: list[str] = [] + + +items = { + "foo": {"name": "Foo", "price": 50.2}, + "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, + "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, +} + + +@app.get("/items/{item_id}", response_model=Item) +async def read_item(item_id: str): + return items[item_id] + + +@app.patch("/items/{item_id}", response_model=Item) +async def update_item(item_id: str, item: Item): + stored_item_data = items[item_id] + stored_item_model = Item(**stored_item_data) + update_data = item.dict(exclude_unset=True) + updated_item = stored_item_model.copy(update=update_data) + items[item_id] = jsonable_encoder(updated_item) + return updated_item diff --git a/docs_src/body_updates/tutorial002_py39.py b/docs_src/body_updates/tutorial002_py39.py new file mode 100644 index 000000000..ab85bd5ae --- /dev/null +++ b/docs_src/body_updates/tutorial002_py39.py @@ -0,0 +1,37 @@ +from typing import Optional + +from fastapi import FastAPI +from fastapi.encoders import jsonable_encoder +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: Optional[str] = None + description: Optional[str] = None + price: Optional[float] = None + tax: float = 10.5 + tags: list[str] = [] + + +items = { + "foo": {"name": "Foo", "price": 50.2}, + "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, + "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, +} + + +@app.get("/items/{item_id}", response_model=Item) +async def read_item(item_id: str): + return items[item_id] + + +@app.patch("/items/{item_id}", response_model=Item) +async def update_item(item_id: str, item: Item): + stored_item_data = items[item_id] + stored_item_model = Item(**stored_item_data) + update_data = item.dict(exclude_unset=True) + updated_item = stored_item_model.copy(update=update_data) + items[item_id] = jsonable_encoder(updated_item) + return updated_item diff --git a/docs_src/cookie_params/tutorial001_py310.py b/docs_src/cookie_params/tutorial001_py310.py new file mode 100644 index 000000000..d0b004631 --- /dev/null +++ b/docs_src/cookie_params/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import Cookie, FastAPI + +app = FastAPI() + + +@app.get("/items/") +async def read_items(ads_id: str | None = Cookie(None)): + return {"ads_id": ads_id} diff --git a/docs_src/dependencies/tutorial001_py310.py b/docs_src/dependencies/tutorial001_py310.py new file mode 100644 index 000000000..662af9b1b --- /dev/null +++ b/docs_src/dependencies/tutorial001_py310.py @@ -0,0 +1,17 @@ +from fastapi import Depends, FastAPI + +app = FastAPI() + + +async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100): + return {"q": q, "skip": skip, "limit": limit} + + +@app.get("/items/") +async def read_items(commons: dict = Depends(common_parameters)): + return commons + + +@app.get("/users/") +async def read_users(commons: dict = Depends(common_parameters)): + return commons diff --git a/docs_src/dependencies/tutorial002_py310.py b/docs_src/dependencies/tutorial002_py310.py new file mode 100644 index 000000000..23c048ab9 --- /dev/null +++ b/docs_src/dependencies/tutorial002_py310.py @@ -0,0 +1,23 @@ +from fastapi import Depends, FastAPI + +app = FastAPI() + + +fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] + + +class CommonQueryParams: + def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100): + self.q = q + self.skip = skip + self.limit = limit + + +@app.get("/items/") +async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)): + response = {} + if commons.q: + response.update({"q": commons.q}) + items = fake_items_db[commons.skip : commons.skip + commons.limit] + response.update({"items": items}) + return response diff --git a/docs_src/dependencies/tutorial003_py310.py b/docs_src/dependencies/tutorial003_py310.py new file mode 100644 index 000000000..10d3771c1 --- /dev/null +++ b/docs_src/dependencies/tutorial003_py310.py @@ -0,0 +1,23 @@ +from fastapi import Depends, FastAPI + +app = FastAPI() + + +fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] + + +class CommonQueryParams: + def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100): + self.q = q + self.skip = skip + self.limit = limit + + +@app.get("/items/") +async def read_items(commons=Depends(CommonQueryParams)): + response = {} + if commons.q: + response.update({"q": commons.q}) + items = fake_items_db[commons.skip : commons.skip + commons.limit] + response.update({"items": items}) + return response diff --git a/docs_src/dependencies/tutorial004_py310.py b/docs_src/dependencies/tutorial004_py310.py new file mode 100644 index 000000000..5245bb0f6 --- /dev/null +++ b/docs_src/dependencies/tutorial004_py310.py @@ -0,0 +1,23 @@ +from fastapi import Depends, FastAPI + +app = FastAPI() + + +fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] + + +class CommonQueryParams: + def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100): + self.q = q + self.skip = skip + self.limit = limit + + +@app.get("/items/") +async def read_items(commons: CommonQueryParams = Depends()): + response = {} + if commons.q: + response.update({"q": commons.q}) + items = fake_items_db[commons.skip : commons.skip + commons.limit] + response.update({"items": items}) + return response diff --git a/docs_src/dependencies/tutorial005_py310.py b/docs_src/dependencies/tutorial005_py310.py new file mode 100644 index 000000000..5e1d7e0ef --- /dev/null +++ b/docs_src/dependencies/tutorial005_py310.py @@ -0,0 +1,20 @@ +from fastapi import Cookie, Depends, FastAPI + +app = FastAPI() + + +def query_extractor(q: str | None = None): + return q + + +def query_or_cookie_extractor( + q: str = Depends(query_extractor), last_query: str | None = Cookie(None) +): + if not q: + return last_query + return q + + +@app.get("/items/") +async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)): + return {"q_or_cookie": query_or_default} diff --git a/docs_src/encoder/tutorial001_py310.py b/docs_src/encoder/tutorial001_py310.py new file mode 100644 index 000000000..5baf13628 --- /dev/null +++ b/docs_src/encoder/tutorial001_py310.py @@ -0,0 +1,22 @@ +from datetime import datetime + +from fastapi import FastAPI +from fastapi.encoders import jsonable_encoder +from pydantic import BaseModel + +fake_db = {} + + +class Item(BaseModel): + title: str + timestamp: datetime + description: str | None = None + + +app = FastAPI() + + +@app.put("/items/{id}") +def update_item(id: str, item: Item): + json_compatible_item_data = jsonable_encoder(item) + fake_db[id] = json_compatible_item_data diff --git a/docs_src/extra_data_types/tutorial001_py310.py b/docs_src/extra_data_types/tutorial001_py310.py new file mode 100644 index 000000000..4a33481b7 --- /dev/null +++ b/docs_src/extra_data_types/tutorial001_py310.py @@ -0,0 +1,27 @@ +from datetime import datetime, time, timedelta +from uuid import UUID + +from fastapi import Body, FastAPI + +app = FastAPI() + + +@app.put("/items/{item_id}") +async def read_items( + item_id: UUID, + start_datetime: datetime | None = Body(None), + end_datetime: datetime | None = Body(None), + repeat_at: time | None = Body(None), + process_after: timedelta | None = Body(None), +): + start_process = start_datetime + process_after + duration = end_datetime - start_process + return { + "item_id": item_id, + "start_datetime": start_datetime, + "end_datetime": end_datetime, + "repeat_at": repeat_at, + "process_after": process_after, + "start_process": start_process, + "duration": duration, + } diff --git a/docs_src/extra_models/tutorial001_py310.py b/docs_src/extra_models/tutorial001_py310.py new file mode 100644 index 000000000..669386ae6 --- /dev/null +++ b/docs_src/extra_models/tutorial001_py310.py @@ -0,0 +1,41 @@ +from fastapi import FastAPI +from pydantic import BaseModel, EmailStr + +app = FastAPI() + + +class UserIn(BaseModel): + username: str + password: str + email: EmailStr + full_name: str | None = None + + +class UserOut(BaseModel): + username: str + email: EmailStr + full_name: str | None = None + + +class UserInDB(BaseModel): + username: str + hashed_password: str + email: EmailStr + full_name: str | None = None + + +def fake_password_hasher(raw_password: str): + return "supersecret" + raw_password + + +def fake_save_user(user_in: UserIn): + hashed_password = fake_password_hasher(user_in.password) + user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password) + print("User saved! ..not really") + return user_in_db + + +@app.post("/user/", response_model=UserOut) +async def create_user(user_in: UserIn): + user_saved = fake_save_user(user_in) + return user_saved diff --git a/docs_src/extra_models/tutorial002_py310.py b/docs_src/extra_models/tutorial002_py310.py new file mode 100644 index 000000000..5b8ed7de3 --- /dev/null +++ b/docs_src/extra_models/tutorial002_py310.py @@ -0,0 +1,39 @@ +from fastapi import FastAPI +from pydantic import BaseModel, EmailStr + +app = FastAPI() + + +class UserBase(BaseModel): + username: str + email: EmailStr + full_name: str | None = None + + +class UserIn(UserBase): + password: str + + +class UserOut(UserBase): + pass + + +class UserInDB(UserBase): + hashed_password: str + + +def fake_password_hasher(raw_password: str): + return "supersecret" + raw_password + + +def fake_save_user(user_in: UserIn): + hashed_password = fake_password_hasher(user_in.password) + user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password) + print("User saved! ..not really") + return user_in_db + + +@app.post("/user/", response_model=UserOut) +async def create_user(user_in: UserIn): + user_saved = fake_save_user(user_in) + return user_saved diff --git a/docs_src/extra_models/tutorial003_py310.py b/docs_src/extra_models/tutorial003_py310.py new file mode 100644 index 000000000..065439acc --- /dev/null +++ b/docs_src/extra_models/tutorial003_py310.py @@ -0,0 +1,35 @@ +from typing import Union + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class BaseItem(BaseModel): + description: str + type: str + + +class CarItem(BaseItem): + type = "car" + + +class PlaneItem(BaseItem): + type = "plane" + size: int + + +items = { + "item1": {"description": "All my friends drive a low rider", "type": "car"}, + "item2": { + "description": "Music is my aeroplane, it's my aeroplane", + "type": "plane", + "size": 5, + }, +} + + +@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem]) +async def read_item(item_id: str): + return items[item_id] diff --git a/docs_src/extra_models/tutorial004_py39.py b/docs_src/extra_models/tutorial004_py39.py new file mode 100644 index 000000000..28cacde4d --- /dev/null +++ b/docs_src/extra_models/tutorial004_py39.py @@ -0,0 +1,20 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str + + +items = [ + {"name": "Foo", "description": "There comes my hero"}, + {"name": "Red", "description": "It's my aeroplane"}, +] + + +@app.get("/items/", response_model=list[Item]) +async def read_items(): + return items diff --git a/docs_src/extra_models/tutorial005_py39.py b/docs_src/extra_models/tutorial005_py39.py new file mode 100644 index 000000000..9da2a0a0f --- /dev/null +++ b/docs_src/extra_models/tutorial005_py39.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/keyword-weights/", response_model=dict[str, float]) +async def read_keyword_weights(): + return {"foo": 2.3, "bar": 3.4} diff --git a/docs_src/header_params/tutorial001_py310.py b/docs_src/header_params/tutorial001_py310.py new file mode 100644 index 000000000..b28463346 --- /dev/null +++ b/docs_src/header_params/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, Header + +app = FastAPI() + + +@app.get("/items/") +async def read_items(user_agent: str | None = Header(None)): + return {"User-Agent": user_agent} diff --git a/docs_src/header_params/tutorial002_py310.py b/docs_src/header_params/tutorial002_py310.py new file mode 100644 index 000000000..98ab5a807 --- /dev/null +++ b/docs_src/header_params/tutorial002_py310.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI, Header + +app = FastAPI() + + +@app.get("/items/") +async def read_items( + strange_header: str | None = Header(None, convert_underscores=False) +): + return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial003_py310.py b/docs_src/header_params/tutorial003_py310.py new file mode 100644 index 000000000..2dac2c13c --- /dev/null +++ b/docs_src/header_params/tutorial003_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, Header + +app = FastAPI() + + +@app.get("/items/") +async def read_items(x_token: list[str] | None = Header(None)): + return {"X-Token values": x_token} diff --git a/docs_src/header_params/tutorial003_py39.py b/docs_src/header_params/tutorial003_py39.py new file mode 100644 index 000000000..359766527 --- /dev/null +++ b/docs_src/header_params/tutorial003_py39.py @@ -0,0 +1,10 @@ +from typing import Optional + +from fastapi import FastAPI, Header + +app = FastAPI() + + +@app.get("/items/") +async def read_items(x_token: Optional[list[str]] = Header(None)): + return {"X-Token values": x_token} diff --git a/docs_src/path_operation_configuration/tutorial001.py b/docs_src/path_operation_configuration/tutorial001.py index 66ea442ea..1316d9237 100644 --- a/docs_src/path_operation_configuration/tutorial001.py +++ b/docs_src/path_operation_configuration/tutorial001.py @@ -11,7 +11,7 @@ class Item(BaseModel): description: Optional[str] = None price: float tax: Optional[float] = None - tags: Set[str] = [] + tags: Set[str] = set() @app.post("/items/", response_model=Item, status_code=status.HTTP_201_CREATED) diff --git a/docs_src/path_operation_configuration/tutorial001_py310.py b/docs_src/path_operation_configuration/tutorial001_py310.py new file mode 100644 index 000000000..da078fdf5 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial001_py310.py @@ -0,0 +1,17 @@ +from fastapi import FastAPI, status +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = set() + + +@app.post("/items/", response_model=Item, status_code=status.HTTP_201_CREATED) +async def create_item(item: Item): + return item diff --git a/docs_src/path_operation_configuration/tutorial001_py39.py b/docs_src/path_operation_configuration/tutorial001_py39.py new file mode 100644 index 000000000..5c04d8bac --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial001_py39.py @@ -0,0 +1,19 @@ +from typing import Optional + +from fastapi import FastAPI, status +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = set() + + +@app.post("/items/", response_model=Item, status_code=status.HTTP_201_CREATED) +async def create_item(item: Item): + return item diff --git a/docs_src/path_operation_configuration/tutorial002.py b/docs_src/path_operation_configuration/tutorial002.py index 01df041b8..2df537d86 100644 --- a/docs_src/path_operation_configuration/tutorial002.py +++ b/docs_src/path_operation_configuration/tutorial002.py @@ -11,7 +11,7 @@ class Item(BaseModel): description: Optional[str] = None price: float tax: Optional[float] = None - tags: Set[str] = [] + tags: Set[str] = set() @app.post("/items/", response_model=Item, tags=["items"]) diff --git a/docs_src/path_operation_configuration/tutorial002_py310.py b/docs_src/path_operation_configuration/tutorial002_py310.py new file mode 100644 index 000000000..9a8af5432 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial002_py310.py @@ -0,0 +1,27 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = set() + + +@app.post("/items/", response_model=Item, tags=["items"]) +async def create_item(item: Item): + return item + + +@app.get("/items/", tags=["items"]) +async def read_items(): + return [{"name": "Foo", "price": 42}] + + +@app.get("/users/", tags=["users"]) +async def read_users(): + return [{"username": "johndoe"}] diff --git a/docs_src/path_operation_configuration/tutorial002_py39.py b/docs_src/path_operation_configuration/tutorial002_py39.py new file mode 100644 index 000000000..766d9fb0b --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial002_py39.py @@ -0,0 +1,29 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = set() + + +@app.post("/items/", response_model=Item, tags=["items"]) +async def create_item(item: Item): + return item + + +@app.get("/items/", tags=["items"]) +async def read_items(): + return [{"name": "Foo", "price": 42}] + + +@app.get("/users/", tags=["users"]) +async def read_users(): + return [{"username": "johndoe"}] diff --git a/docs_src/path_operation_configuration/tutorial003.py b/docs_src/path_operation_configuration/tutorial003.py index 29bcb4a22..269a1a253 100644 --- a/docs_src/path_operation_configuration/tutorial003.py +++ b/docs_src/path_operation_configuration/tutorial003.py @@ -11,7 +11,7 @@ class Item(BaseModel): description: Optional[str] = None price: float tax: Optional[float] = None - tags: Set[str] = [] + tags: Set[str] = set() @app.post( diff --git a/docs_src/path_operation_configuration/tutorial003_py310.py b/docs_src/path_operation_configuration/tutorial003_py310.py new file mode 100644 index 000000000..3d94afe2c --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial003_py310.py @@ -0,0 +1,22 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = set() + + +@app.post( + "/items/", + response_model=Item, + summary="Create an item", + description="Create an item with all the information, name, description, price, tax and a set of unique tags", +) +async def create_item(item: Item): + return item diff --git a/docs_src/path_operation_configuration/tutorial003_py39.py b/docs_src/path_operation_configuration/tutorial003_py39.py new file mode 100644 index 000000000..446198b5c --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial003_py39.py @@ -0,0 +1,24 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = set() + + +@app.post( + "/items/", + response_model=Item, + summary="Create an item", + description="Create an item with all the information, name, description, price, tax and a set of unique tags", +) +async def create_item(item: Item): + return item diff --git a/docs_src/path_operation_configuration/tutorial004.py b/docs_src/path_operation_configuration/tutorial004.py index ac95cc4bb..de83be836 100644 --- a/docs_src/path_operation_configuration/tutorial004.py +++ b/docs_src/path_operation_configuration/tutorial004.py @@ -11,7 +11,7 @@ class Item(BaseModel): description: Optional[str] = None price: float tax: Optional[float] = None - tags: Set[str] = [] + tags: Set[str] = set() @app.post("/items/", response_model=Item, summary="Create an item") diff --git a/docs_src/path_operation_configuration/tutorial004_py310.py b/docs_src/path_operation_configuration/tutorial004_py310.py new file mode 100644 index 000000000..4cb8bdd43 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial004_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = set() + + +@app.post("/items/", response_model=Item, summary="Create an item") +async def create_item(item: Item): + """ + Create an item with all the information: + + - **name**: each item must have a name + - **description**: a long description + - **price**: required + - **tax**: if the item doesn't have tax, you can omit this + - **tags**: a set of unique tag strings for this item + """ + return item diff --git a/docs_src/path_operation_configuration/tutorial004_py39.py b/docs_src/path_operation_configuration/tutorial004_py39.py new file mode 100644 index 000000000..bf6005b95 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial004_py39.py @@ -0,0 +1,28 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = set() + + +@app.post("/items/", response_model=Item, summary="Create an item") +async def create_item(item: Item): + """ + Create an item with all the information: + + - **name**: each item must have a name + - **description**: a long description + - **price**: required + - **tax**: if the item doesn't have tax, you can omit this + - **tags**: a set of unique tag strings for this item + """ + return item diff --git a/docs_src/path_operation_configuration/tutorial005.py b/docs_src/path_operation_configuration/tutorial005.py index c1b809887..0f62c3814 100644 --- a/docs_src/path_operation_configuration/tutorial005.py +++ b/docs_src/path_operation_configuration/tutorial005.py @@ -11,7 +11,7 @@ class Item(BaseModel): description: Optional[str] = None price: float tax: Optional[float] = None - tags: Set[str] = [] + tags: Set[str] = set() @app.post( diff --git a/docs_src/path_operation_configuration/tutorial005_py310.py b/docs_src/path_operation_configuration/tutorial005_py310.py new file mode 100644 index 000000000..b176631d8 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial005_py310.py @@ -0,0 +1,31 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: set[str] = set() + + +@app.post( + "/items/", + response_model=Item, + summary="Create an item", + response_description="The created item", +) +async def create_item(item: Item): + """ + Create an item with all the information: + + - **name**: each item must have a name + - **description**: a long description + - **price**: required + - **tax**: if the item doesn't have tax, you can omit this + - **tags**: a set of unique tag strings for this item + """ + return item diff --git a/docs_src/path_operation_configuration/tutorial005_py39.py b/docs_src/path_operation_configuration/tutorial005_py39.py new file mode 100644 index 000000000..5ef320405 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial005_py39.py @@ -0,0 +1,33 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: set[str] = set() + + +@app.post( + "/items/", + response_model=Item, + summary="Create an item", + response_description="The created item", +) +async def create_item(item: Item): + """ + Create an item with all the information: + + - **name**: each item must have a name + - **description**: a long description + - **price**: required + - **tax**: if the item doesn't have tax, you can omit this + - **tags**: a set of unique tag strings for this item + """ + return item diff --git a/docs_src/path_params_numeric_validations/tutorial001_py310.py b/docs_src/path_params_numeric_validations/tutorial001_py310.py new file mode 100644 index 000000000..b940a0949 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial001_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI, Path, Query + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + item_id: int = Path(..., title="The ID of the item to get"), + q: str | None = Query(None, alias="item-query"), +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/python_types/tutorial006_py39.py b/docs_src/python_types/tutorial006_py39.py new file mode 100644 index 000000000..486b67caf --- /dev/null +++ b/docs_src/python_types/tutorial006_py39.py @@ -0,0 +1,3 @@ +def process_items(items: list[str]): + for item in items: + print(item) diff --git a/docs_src/python_types/tutorial007_py39.py b/docs_src/python_types/tutorial007_py39.py new file mode 100644 index 000000000..ea96c7964 --- /dev/null +++ b/docs_src/python_types/tutorial007_py39.py @@ -0,0 +1,2 @@ +def process_items(items_t: tuple[int, int, str], items_s: set[bytes]): + return items_t, items_s diff --git a/docs_src/python_types/tutorial008.py b/docs_src/python_types/tutorial008.py index 9fb1043bb..a393385b0 100644 --- a/docs_src/python_types/tutorial008.py +++ b/docs_src/python_types/tutorial008.py @@ -1,7 +1,4 @@ -from typing import Dict - - -def process_items(prices: Dict[str, float]): +def process_items(prices: dict[str, float]): for item_name, item_price in prices.items(): print(item_name) print(item_price) diff --git a/docs_src/python_types/tutorial008b.py b/docs_src/python_types/tutorial008b.py new file mode 100644 index 000000000..e52539ead --- /dev/null +++ b/docs_src/python_types/tutorial008b.py @@ -0,0 +1,5 @@ +from typing import Union + + +def process_item(item: Union[int, str]): + print(item) diff --git a/docs_src/python_types/tutorial008b_py310.py b/docs_src/python_types/tutorial008b_py310.py new file mode 100644 index 000000000..6bb437841 --- /dev/null +++ b/docs_src/python_types/tutorial008b_py310.py @@ -0,0 +1,2 @@ +def process_item(item: int | str): + print(item) diff --git a/docs_src/python_types/tutorial009_py310.py b/docs_src/python_types/tutorial009_py310.py new file mode 100644 index 000000000..8464c6ff0 --- /dev/null +++ b/docs_src/python_types/tutorial009_py310.py @@ -0,0 +1,5 @@ +def say_hi(name: str | None = None): + if name is not None: + print(f"Hey {name}!") + else: + print("Hello World") diff --git a/docs_src/python_types/tutorial009b.py b/docs_src/python_types/tutorial009b.py new file mode 100644 index 000000000..9f1a05bc0 --- /dev/null +++ b/docs_src/python_types/tutorial009b.py @@ -0,0 +1,8 @@ +from typing import Union + + +def say_hi(name: Union[str, None] = None): + if name is not None: + print(f"Hey {name}!") + else: + print("Hello World") diff --git a/docs_src/python_types/tutorial011_py310.py b/docs_src/python_types/tutorial011_py310.py new file mode 100644 index 000000000..7f173880f --- /dev/null +++ b/docs_src/python_types/tutorial011_py310.py @@ -0,0 +1,22 @@ +from datetime import datetime + +from pydantic import BaseModel + + +class User(BaseModel): + id: int + name = "John Doe" + signup_ts: datetime | None = None + friends: list[int] = [] + + +external_data = { + "id": "123", + "signup_ts": "2017-06-01 12:22", + "friends": [1, "2", b"3"], +} +user = User(**external_data) +print(user) +# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3] +print(user.id) +# > 123 diff --git a/docs_src/python_types/tutorial011_py39.py b/docs_src/python_types/tutorial011_py39.py new file mode 100644 index 000000000..af79e2df0 --- /dev/null +++ b/docs_src/python_types/tutorial011_py39.py @@ -0,0 +1,23 @@ +from datetime import datetime +from typing import Optional + +from pydantic import BaseModel + + +class User(BaseModel): + id: int + name = "John Doe" + signup_ts: Optional[datetime] = None + friends: list[int] = [] + + +external_data = { + "id": "123", + "signup_ts": "2017-06-01 12:22", + "friends": [1, "2", b"3"], +} +user = User(**external_data) +print(user) +# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3] +print(user.id) +# > 123 diff --git a/docs_src/query_params/tutorial002_py310.py b/docs_src/query_params/tutorial002_py310.py new file mode 100644 index 000000000..bedb58ce8 --- /dev/null +++ b/docs_src/query_params/tutorial002_py310.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_item(item_id: str, q: str | None = None): + if q: + return {"item_id": item_id, "q": q} + return {"item_id": item_id} diff --git a/docs_src/query_params/tutorial003_py310.py b/docs_src/query_params/tutorial003_py310.py new file mode 100644 index 000000000..1eec66d90 --- /dev/null +++ b/docs_src/query_params/tutorial003_py310.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_item(item_id: str, q: str | None = None, short: bool = False): + item = {"item_id": item_id} + if q: + item.update({"q": q}) + if not short: + item.update( + {"description": "This is an amazing item that has a long description"} + ) + return item diff --git a/docs_src/query_params/tutorial004_py310.py b/docs_src/query_params/tutorial004_py310.py new file mode 100644 index 000000000..8ec4338df --- /dev/null +++ b/docs_src/query_params/tutorial004_py310.py @@ -0,0 +1,17 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/users/{user_id}/items/{item_id}") +async def read_user_item( + user_id: int, item_id: str, q: str | None = None, short: bool = False +): + item = {"item_id": item_id, "owner_id": user_id} + if q: + item.update({"q": q}) + if not short: + item.update( + {"description": "This is an amazing item that has a long description"} + ) + return item diff --git a/docs_src/query_params/tutorial006_py310.py b/docs_src/query_params/tutorial006_py310.py new file mode 100644 index 000000000..be2a44c31 --- /dev/null +++ b/docs_src/query_params/tutorial006_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_user_item( + item_id: str, needy: str, skip: int = 0, limit: int | None = None +): + item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit} + return item diff --git a/docs_src/query_params/tutorial006b.py b/docs_src/query_params/tutorial006b.py new file mode 100644 index 000000000..f0dbfe08f --- /dev/null +++ b/docs_src/query_params/tutorial006b.py @@ -0,0 +1,13 @@ +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_user_item( + item_id: str, needy: str, skip: int = 0, limit: Union[int, None] = None +): + item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit} + return item diff --git a/docs_src/query_params_str_validations/tutorial001_py310.py b/docs_src/query_params_str_validations/tutorial001_py310.py new file mode 100644 index 000000000..eeefddfa7 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial001_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str | None = None): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial002_py310.py b/docs_src/query_params_str_validations/tutorial002_py310.py new file mode 100644 index 000000000..fa3139d5a --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial002_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str | None = Query(None, max_length=50)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial003_py310.py b/docs_src/query_params_str_validations/tutorial003_py310.py new file mode 100644 index 000000000..335858a40 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial003_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str | None = Query(None, min_length=3, max_length=50)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial004_py310.py b/docs_src/query_params_str_validations/tutorial004_py310.py new file mode 100644 index 000000000..518b779f7 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial004_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items( + q: str | None = Query(None, min_length=3, max_length=50, regex="^fixedquery$") +): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial007_py310.py b/docs_src/query_params_str_validations/tutorial007_py310.py new file mode 100644 index 000000000..14ef4cb69 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial007_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str | None = Query(None, title="Query string", min_length=3)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial008_py310.py b/docs_src/query_params_str_validations/tutorial008_py310.py new file mode 100644 index 000000000..06bb02442 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial008_py310.py @@ -0,0 +1,19 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items( + q: str + | None = Query( + None, + title="Query string", + description="Query string for the items to search in the database that have a good match", + min_length=3, + ) +): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial009_py310.py b/docs_src/query_params_str_validations/tutorial009_py310.py new file mode 100644 index 000000000..e84c116f1 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial009_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str | None = Query(None, alias="item-query")): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial010_py310.py b/docs_src/query_params_str_validations/tutorial010_py310.py new file mode 100644 index 000000000..c35800858 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial010_py310.py @@ -0,0 +1,23 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items( + q: str + | None = Query( + None, + alias="item-query", + title="Query string", + description="Query string for the items to search in the database that have a good match", + min_length=3, + max_length=50, + regex="^fixedquery$", + deprecated=True, + ) +): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial011_py310.py b/docs_src/query_params_str_validations/tutorial011_py310.py new file mode 100644 index 000000000..c3d992e62 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial011_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: list[str] | None = Query(None)): + query_items = {"q": q} + return query_items diff --git a/docs_src/query_params_str_validations/tutorial011_py39.py b/docs_src/query_params_str_validations/tutorial011_py39.py new file mode 100644 index 000000000..38ba764d6 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial011_py39.py @@ -0,0 +1,11 @@ +from typing import Optional + +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: Optional[list[str]] = Query(None)): + query_items = {"q": q} + return query_items diff --git a/docs_src/query_params_str_validations/tutorial012_py39.py b/docs_src/query_params_str_validations/tutorial012_py39.py new file mode 100644 index 000000000..1900133d9 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial012_py39.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: list[str] = Query(["foo", "bar"])): + query_items = {"q": q} + return query_items diff --git a/docs_src/request_files/tutorial002_py39.py b/docs_src/request_files/tutorial002_py39.py new file mode 100644 index 000000000..26cd56769 --- /dev/null +++ b/docs_src/request_files/tutorial002_py39.py @@ -0,0 +1,31 @@ +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files(files: list[bytes] = File(...)): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files(files: list[UploadFile] = File(...)): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/response_model/tutorial001_py310.py b/docs_src/response_model/tutorial001_py310.py new file mode 100644 index 000000000..59efecde4 --- /dev/null +++ b/docs_src/response_model/tutorial001_py310.py @@ -0,0 +1,17 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + tags: list[str] = [] + + +@app.post("/items/", response_model=Item) +async def create_item(item: Item): + return item diff --git a/docs_src/response_model/tutorial001_py39.py b/docs_src/response_model/tutorial001_py39.py new file mode 100644 index 000000000..37b866864 --- /dev/null +++ b/docs_src/response_model/tutorial001_py39.py @@ -0,0 +1,19 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: Optional[float] = None + tags: list[str] = [] + + +@app.post("/items/", response_model=Item) +async def create_item(item: Item): + return item diff --git a/docs_src/response_model/tutorial002_py310.py b/docs_src/response_model/tutorial002_py310.py new file mode 100644 index 000000000..29ab9c9d2 --- /dev/null +++ b/docs_src/response_model/tutorial002_py310.py @@ -0,0 +1,17 @@ +from fastapi import FastAPI +from pydantic import BaseModel, EmailStr + +app = FastAPI() + + +class UserIn(BaseModel): + username: str + password: str + email: EmailStr + full_name: str | None = None + + +# Don't do this in production! +@app.post("/user/", response_model=UserIn) +async def create_user(user: UserIn): + return user diff --git a/docs_src/response_model/tutorial003_py310.py b/docs_src/response_model/tutorial003_py310.py new file mode 100644 index 000000000..fc9693e3c --- /dev/null +++ b/docs_src/response_model/tutorial003_py310.py @@ -0,0 +1,22 @@ +from fastapi import FastAPI +from pydantic import BaseModel, EmailStr + +app = FastAPI() + + +class UserIn(BaseModel): + username: str + password: str + email: EmailStr + full_name: str | None = None + + +class UserOut(BaseModel): + username: str + email: EmailStr + full_name: str | None = None + + +@app.post("/user/", response_model=UserOut) +async def create_user(user: UserIn): + return user diff --git a/docs_src/response_model/tutorial004_py310.py b/docs_src/response_model/tutorial004_py310.py new file mode 100644 index 000000000..a3e21b434 --- /dev/null +++ b/docs_src/response_model/tutorial004_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float = 10.5 + tags: list[str] = [] + + +items = { + "foo": {"name": "Foo", "price": 50.2}, + "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, + "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, +} + + +@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True) +async def read_item(item_id: str): + return items[item_id] diff --git a/docs_src/response_model/tutorial004_py39.py b/docs_src/response_model/tutorial004_py39.py new file mode 100644 index 000000000..07ccbbf41 --- /dev/null +++ b/docs_src/response_model/tutorial004_py39.py @@ -0,0 +1,26 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Optional[str] = None + price: float + tax: float = 10.5 + tags: list[str] = [] + + +items = { + "foo": {"name": "Foo", "price": 50.2}, + "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, + "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, +} + + +@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True) +async def read_item(item_id: str): + return items[item_id] diff --git a/docs_src/response_model/tutorial005_py310.py b/docs_src/response_model/tutorial005_py310.py new file mode 100644 index 000000000..acb3035b9 --- /dev/null +++ b/docs_src/response_model/tutorial005_py310.py @@ -0,0 +1,37 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float = 10.5 + + +items = { + "foo": {"name": "Foo", "price": 50.2}, + "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2}, + "baz": { + "name": "Baz", + "description": "There goes my baz", + "price": 50.2, + "tax": 10.5, + }, +} + + +@app.get( + "/items/{item_id}/name", + response_model=Item, + response_model_include={"name", "description"}, +) +async def read_item_name(item_id: str): + return items[item_id] + + +@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"}) +async def read_item_public_data(item_id: str): + return items[item_id] diff --git a/docs_src/response_model/tutorial006_py310.py b/docs_src/response_model/tutorial006_py310.py new file mode 100644 index 000000000..9ccec324e --- /dev/null +++ b/docs_src/response_model/tutorial006_py310.py @@ -0,0 +1,37 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float = 10.5 + + +items = { + "foo": {"name": "Foo", "price": 50.2}, + "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2}, + "baz": { + "name": "Baz", + "description": "There goes my baz", + "price": 50.2, + "tax": 10.5, + }, +} + + +@app.get( + "/items/{item_id}/name", + response_model=Item, + response_model_include=["name", "description"], +) +async def read_item_name(item_id: str): + return items[item_id] + + +@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"]) +async def read_item_public_data(item_id: str): + return items[item_id] diff --git a/docs_src/schema_extra_example/tutorial001_py310.py b/docs_src/schema_extra_example/tutorial001_py310.py new file mode 100644 index 000000000..77ceedd60 --- /dev/null +++ b/docs_src/schema_extra_example/tutorial001_py310.py @@ -0,0 +1,27 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + class Config: + schema_extra = { + "example": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + } + } + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial002_py310.py b/docs_src/schema_extra_example/tutorial002_py310.py new file mode 100644 index 000000000..4f8f8304e --- /dev/null +++ b/docs_src/schema_extra_example/tutorial002_py310.py @@ -0,0 +1,17 @@ +from fastapi import FastAPI +from pydantic import BaseModel, Field + +app = FastAPI() + + +class Item(BaseModel): + name: str = Field(..., example="Foo") + description: str | None = Field(None, example="A very nice Item") + price: float = Field(..., example=35.4) + tax: float | None = Field(None, example=3.2) + + +@app.put("/items/{item_id}") +async def update_item(item_id: int, item: Item): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial003_py310.py b/docs_src/schema_extra_example/tutorial003_py310.py new file mode 100644 index 000000000..cf4c99dc0 --- /dev/null +++ b/docs_src/schema_extra_example/tutorial003_py310.py @@ -0,0 +1,28 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +@app.put("/items/{item_id}") +async def update_item( + item_id: int, + item: Item = Body( + ..., + example={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ), +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial004_py310.py b/docs_src/schema_extra_example/tutorial004_py310.py new file mode 100644 index 000000000..6f29c1a5c --- /dev/null +++ b/docs_src/schema_extra_example/tutorial004_py310.py @@ -0,0 +1,50 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Item = Body( + ..., + examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/security/tutorial002_py310.py b/docs_src/security/tutorial002_py310.py new file mode 100644 index 000000000..3c2018f54 --- /dev/null +++ b/docs_src/security/tutorial002_py310.py @@ -0,0 +1,30 @@ +from fastapi import Depends, FastAPI +from fastapi.security import OAuth2PasswordBearer +from pydantic import BaseModel + +app = FastAPI() + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") + + +class User(BaseModel): + username: str + email: str | None = None + full_name: str | None = None + disabled: bool | None = None + + +def fake_decode_token(token): + return User( + username=token + "fakedecoded", email="john@example.com", full_name="John Doe" + ) + + +async def get_current_user(token: str = Depends(oauth2_scheme)): + user = fake_decode_token(token) + return user + + +@app.get("/users/me") +async def read_users_me(current_user: User = Depends(get_current_user)): + return current_user diff --git a/docs_src/security/tutorial003_py310.py b/docs_src/security/tutorial003_py310.py new file mode 100644 index 000000000..af935e997 --- /dev/null +++ b/docs_src/security/tutorial003_py310.py @@ -0,0 +1,88 @@ +from fastapi import Depends, FastAPI, HTTPException, status +from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm +from pydantic import BaseModel + +fake_users_db = { + "johndoe": { + "username": "johndoe", + "full_name": "John Doe", + "email": "johndoe@example.com", + "hashed_password": "fakehashedsecret", + "disabled": False, + }, + "alice": { + "username": "alice", + "full_name": "Alice Wonderson", + "email": "alice@example.com", + "hashed_password": "fakehashedsecret2", + "disabled": True, + }, +} + +app = FastAPI() + + +def fake_hash_password(password: str): + return "fakehashed" + password + + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") + + +class User(BaseModel): + username: str + email: str | None = None + full_name: str | None = None + disabled: bool | None = None + + +class UserInDB(User): + hashed_password: str + + +def get_user(db, username: str): + if username in db: + user_dict = db[username] + return UserInDB(**user_dict) + + +def fake_decode_token(token): + # This doesn't provide any security at all + # Check the next version + user = get_user(fake_users_db, token) + return user + + +async def get_current_user(token: str = Depends(oauth2_scheme)): + user = fake_decode_token(token) + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Invalid authentication credentials", + headers={"WWW-Authenticate": "Bearer"}, + ) + return user + + +async def get_current_active_user(current_user: User = Depends(get_current_user)): + if current_user.disabled: + raise HTTPException(status_code=400, detail="Inactive user") + return current_user + + +@app.post("/token") +async def login(form_data: OAuth2PasswordRequestForm = Depends()): + user_dict = fake_users_db.get(form_data.username) + if not user_dict: + raise HTTPException(status_code=400, detail="Incorrect username or password") + user = UserInDB(**user_dict) + hashed_password = fake_hash_password(form_data.password) + if not hashed_password == user.hashed_password: + raise HTTPException(status_code=400, detail="Incorrect username or password") + + return {"access_token": user.username, "token_type": "bearer"} + + +@app.get("/users/me") +async def read_users_me(current_user: User = Depends(get_current_active_user)): + return current_user diff --git a/docs_src/security/tutorial004_py310.py b/docs_src/security/tutorial004_py310.py new file mode 100644 index 000000000..797d56d04 --- /dev/null +++ b/docs_src/security/tutorial004_py310.py @@ -0,0 +1,137 @@ +from datetime import datetime, timedelta + +from fastapi import Depends, FastAPI, HTTPException, status +from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm +from jose import JWTError, jwt +from passlib.context import CryptContext +from pydantic import BaseModel + +# to get a string like this run: +# openssl rand -hex 32 +SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" +ALGORITHM = "HS256" +ACCESS_TOKEN_EXPIRE_MINUTES = 30 + + +fake_users_db = { + "johndoe": { + "username": "johndoe", + "full_name": "John Doe", + "email": "johndoe@example.com", + "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "disabled": False, + } +} + + +class Token(BaseModel): + access_token: str + token_type: str + + +class TokenData(BaseModel): + username: str | None = None + + +class User(BaseModel): + username: str + email: str | None = None + full_name: str | None = None + disabled: bool | None = None + + +class UserInDB(User): + hashed_password: str + + +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") + +app = FastAPI() + + +def verify_password(plain_password, hashed_password): + return pwd_context.verify(plain_password, hashed_password) + + +def get_password_hash(password): + return pwd_context.hash(password) + + +def get_user(db, username: str): + if username in db: + user_dict = db[username] + return UserInDB(**user_dict) + + +def authenticate_user(fake_db, username: str, password: str): + user = get_user(fake_db, username) + if not user: + return False + if not verify_password(password, user.hashed_password): + return False + return user + + +def create_access_token(data: dict, expires_delta: timedelta | None = None): + to_encode = data.copy() + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta(minutes=15) + to_encode.update({"exp": expire}) + encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) + return encoded_jwt + + +async def get_current_user(token: str = Depends(oauth2_scheme)): + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + headers={"WWW-Authenticate": "Bearer"}, + ) + try: + payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + username: str = payload.get("sub") + if username is None: + raise credentials_exception + token_data = TokenData(username=username) + except JWTError: + raise credentials_exception + user = get_user(fake_users_db, username=token_data.username) + if user is None: + raise credentials_exception + return user + + +async def get_current_active_user(current_user: User = Depends(get_current_user)): + if current_user.disabled: + raise HTTPException(status_code=400, detail="Inactive user") + return current_user + + +@app.post("/token", response_model=Token) +async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): + user = authenticate_user(fake_users_db, form_data.username, form_data.password) + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Bearer"}, + ) + access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": user.username}, expires_delta=access_token_expires + ) + return {"access_token": access_token, "token_type": "bearer"} + + +@app.get("/users/me/", response_model=User) +async def read_users_me(current_user: User = Depends(get_current_active_user)): + return current_user + + +@app.get("/users/me/items/") +async def read_own_items(current_user: User = Depends(get_current_active_user)): + return [{"item_id": "Foo", "owner": current_user.username}] diff --git a/docs_src/security/tutorial005_py310.py b/docs_src/security/tutorial005_py310.py new file mode 100644 index 000000000..c6a095d2c --- /dev/null +++ b/docs_src/security/tutorial005_py310.py @@ -0,0 +1,172 @@ +from datetime import datetime, timedelta + +from fastapi import Depends, FastAPI, HTTPException, Security, status +from fastapi.security import ( + OAuth2PasswordBearer, + OAuth2PasswordRequestForm, + SecurityScopes, +) +from jose import JWTError, jwt +from passlib.context import CryptContext +from pydantic import BaseModel, ValidationError + +# to get a string like this run: +# openssl rand -hex 32 +SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" +ALGORITHM = "HS256" +ACCESS_TOKEN_EXPIRE_MINUTES = 30 + + +fake_users_db = { + "johndoe": { + "username": "johndoe", + "full_name": "John Doe", + "email": "johndoe@example.com", + "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "disabled": False, + }, + "alice": { + "username": "alice", + "full_name": "Alice Chains", + "email": "alicechains@example.com", + "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "disabled": True, + }, +} + + +class Token(BaseModel): + access_token: str + token_type: str + + +class TokenData(BaseModel): + username: str | None = None + scopes: list[str] = [] + + +class User(BaseModel): + username: str + email: str | None = None + full_name: str | None = None + disabled: bool | None = None + + +class UserInDB(User): + hashed_password: str + + +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") + +oauth2_scheme = OAuth2PasswordBearer( + tokenUrl="token", + scopes={"me": "Read information about the current user.", "items": "Read items."}, +) + +app = FastAPI() + + +def verify_password(plain_password, hashed_password): + return pwd_context.verify(plain_password, hashed_password) + + +def get_password_hash(password): + return pwd_context.hash(password) + + +def get_user(db, username: str): + if username in db: + user_dict = db[username] + return UserInDB(**user_dict) + + +def authenticate_user(fake_db, username: str, password: str): + user = get_user(fake_db, username) + if not user: + return False + if not verify_password(password, user.hashed_password): + return False + return user + + +def create_access_token(data: dict, expires_delta: timedelta | None = None): + to_encode = data.copy() + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta(minutes=15) + to_encode.update({"exp": expire}) + encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) + return encoded_jwt + + +async def get_current_user( + security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme) +): + if security_scopes.scopes: + authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' + else: + authenticate_value = f"Bearer" + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + headers={"WWW-Authenticate": authenticate_value}, + ) + try: + payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + username: str = payload.get("sub") + if username is None: + raise credentials_exception + token_scopes = payload.get("scopes", []) + token_data = TokenData(scopes=token_scopes, username=username) + except (JWTError, ValidationError): + raise credentials_exception + user = get_user(fake_users_db, username=token_data.username) + if user is None: + raise credentials_exception + for scope in security_scopes.scopes: + if scope not in token_data.scopes: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Not enough permissions", + headers={"WWW-Authenticate": authenticate_value}, + ) + return user + + +async def get_current_active_user( + current_user: User = Security(get_current_user, scopes=["me"]) +): + if current_user.disabled: + raise HTTPException(status_code=400, detail="Inactive user") + return current_user + + +@app.post("/token", response_model=Token) +async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): + user = authenticate_user(fake_users_db, form_data.username, form_data.password) + if not user: + raise HTTPException(status_code=400, detail="Incorrect username or password") + access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": user.username, "scopes": form_data.scopes}, + expires_delta=access_token_expires, + ) + return {"access_token": access_token, "token_type": "bearer"} + + +@app.get("/users/me/", response_model=User) +async def read_users_me(current_user: User = Depends(get_current_active_user)): + return current_user + + +@app.get("/users/me/items/") +async def read_own_items( + current_user: User = Security(get_current_active_user, scopes=["items"]) +): + return [{"item_id": "Foo", "owner": current_user.username}] + + +@app.get("/status/") +async def read_system_status(current_user: User = Depends(get_current_user)): + return {"status": "ok"} diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py new file mode 100644 index 000000000..d45c08ce6 --- /dev/null +++ b/docs_src/security/tutorial005_py39.py @@ -0,0 +1,173 @@ +from datetime import datetime, timedelta +from typing import Optional + +from fastapi import Depends, FastAPI, HTTPException, Security, status +from fastapi.security import ( + OAuth2PasswordBearer, + OAuth2PasswordRequestForm, + SecurityScopes, +) +from jose import JWTError, jwt +from passlib.context import CryptContext +from pydantic import BaseModel, ValidationError + +# to get a string like this run: +# openssl rand -hex 32 +SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" +ALGORITHM = "HS256" +ACCESS_TOKEN_EXPIRE_MINUTES = 30 + + +fake_users_db = { + "johndoe": { + "username": "johndoe", + "full_name": "John Doe", + "email": "johndoe@example.com", + "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "disabled": False, + }, + "alice": { + "username": "alice", + "full_name": "Alice Chains", + "email": "alicechains@example.com", + "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "disabled": True, + }, +} + + +class Token(BaseModel): + access_token: str + token_type: str + + +class TokenData(BaseModel): + username: Optional[str] = None + scopes: list[str] = [] + + +class User(BaseModel): + username: str + email: Optional[str] = None + full_name: Optional[str] = None + disabled: Optional[bool] = None + + +class UserInDB(User): + hashed_password: str + + +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") + +oauth2_scheme = OAuth2PasswordBearer( + tokenUrl="token", + scopes={"me": "Read information about the current user.", "items": "Read items."}, +) + +app = FastAPI() + + +def verify_password(plain_password, hashed_password): + return pwd_context.verify(plain_password, hashed_password) + + +def get_password_hash(password): + return pwd_context.hash(password) + + +def get_user(db, username: str): + if username in db: + user_dict = db[username] + return UserInDB(**user_dict) + + +def authenticate_user(fake_db, username: str, password: str): + user = get_user(fake_db, username) + if not user: + return False + if not verify_password(password, user.hashed_password): + return False + return user + + +def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): + to_encode = data.copy() + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta(minutes=15) + to_encode.update({"exp": expire}) + encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) + return encoded_jwt + + +async def get_current_user( + security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme) +): + if security_scopes.scopes: + authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' + else: + authenticate_value = f"Bearer" + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + headers={"WWW-Authenticate": authenticate_value}, + ) + try: + payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + username: str = payload.get("sub") + if username is None: + raise credentials_exception + token_scopes = payload.get("scopes", []) + token_data = TokenData(scopes=token_scopes, username=username) + except (JWTError, ValidationError): + raise credentials_exception + user = get_user(fake_users_db, username=token_data.username) + if user is None: + raise credentials_exception + for scope in security_scopes.scopes: + if scope not in token_data.scopes: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Not enough permissions", + headers={"WWW-Authenticate": authenticate_value}, + ) + return user + + +async def get_current_active_user( + current_user: User = Security(get_current_user, scopes=["me"]) +): + if current_user.disabled: + raise HTTPException(status_code=400, detail="Inactive user") + return current_user + + +@app.post("/token", response_model=Token) +async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): + user = authenticate_user(fake_users_db, form_data.username, form_data.password) + if not user: + raise HTTPException(status_code=400, detail="Incorrect username or password") + access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": user.username, "scopes": form_data.scopes}, + expires_delta=access_token_expires, + ) + return {"access_token": access_token, "token_type": "bearer"} + + +@app.get("/users/me/", response_model=User) +async def read_users_me(current_user: User = Depends(get_current_active_user)): + return current_user + + +@app.get("/users/me/items/") +async def read_own_items( + current_user: User = Security(get_current_active_user, scopes=["items"]) +): + return [{"item_id": "Foo", "owner": current_user.username}] + + +@app.get("/status/") +async def read_system_status(current_user: User = Depends(get_current_user)): + return {"status": "ok"} diff --git a/docs_src/sql_databases/sql_app_py310/__init__.py b/docs_src/sql_databases/sql_app_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/sql_databases/sql_app_py310/alt_main.py b/docs_src/sql_databases/sql_app_py310/alt_main.py new file mode 100644 index 000000000..5de88ec3a --- /dev/null +++ b/docs_src/sql_databases/sql_app_py310/alt_main.py @@ -0,0 +1,60 @@ +from fastapi import Depends, FastAPI, HTTPException, Request, Response +from sqlalchemy.orm import Session + +from . import crud, models, schemas +from .database import SessionLocal, engine + +models.Base.metadata.create_all(bind=engine) + +app = FastAPI() + + +@app.middleware("http") +async def db_session_middleware(request: Request, call_next): + response = Response("Internal server error", status_code=500) + try: + request.state.db = SessionLocal() + response = await call_next(request) + finally: + request.state.db.close() + return response + + +# Dependency +def get_db(request: Request): + return request.state.db + + +@app.post("/users/", response_model=schemas.User) +def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)): + db_user = crud.get_user_by_email(db, email=user.email) + if db_user: + raise HTTPException(status_code=400, detail="Email already registered") + return crud.create_user(db=db, user=user) + + +@app.get("/users/", response_model=list[schemas.User]) +def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + users = crud.get_users(db, skip=skip, limit=limit) + return users + + +@app.get("/users/{user_id}", response_model=schemas.User) +def read_user(user_id: int, db: Session = Depends(get_db)): + db_user = crud.get_user(db, user_id=user_id) + if db_user is None: + raise HTTPException(status_code=404, detail="User not found") + return db_user + + +@app.post("/users/{user_id}/items/", response_model=schemas.Item) +def create_item_for_user( + user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db) +): + return crud.create_user_item(db=db, item=item, user_id=user_id) + + +@app.get("/items/", response_model=list[schemas.Item]) +def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + items = crud.get_items(db, skip=skip, limit=limit) + return items diff --git a/docs_src/sql_databases/sql_app_py310/crud.py b/docs_src/sql_databases/sql_app_py310/crud.py new file mode 100644 index 000000000..679acdb5c --- /dev/null +++ b/docs_src/sql_databases/sql_app_py310/crud.py @@ -0,0 +1,36 @@ +from sqlalchemy.orm import Session + +from . import models, schemas + + +def get_user(db: Session, user_id: int): + return db.query(models.User).filter(models.User.id == user_id).first() + + +def get_user_by_email(db: Session, email: str): + return db.query(models.User).filter(models.User.email == email).first() + + +def get_users(db: Session, skip: int = 0, limit: int = 100): + return db.query(models.User).offset(skip).limit(limit).all() + + +def create_user(db: Session, user: schemas.UserCreate): + fake_hashed_password = user.password + "notreallyhashed" + db_user = models.User(email=user.email, hashed_password=fake_hashed_password) + db.add(db_user) + db.commit() + db.refresh(db_user) + return db_user + + +def get_items(db: Session, skip: int = 0, limit: int = 100): + return db.query(models.Item).offset(skip).limit(limit).all() + + +def create_user_item(db: Session, item: schemas.ItemCreate, user_id: int): + db_item = models.Item(**item.dict(), owner_id=user_id) + db.add(db_item) + db.commit() + db.refresh(db_item) + return db_item diff --git a/docs_src/sql_databases/sql_app_py310/database.py b/docs_src/sql_databases/sql_app_py310/database.py new file mode 100644 index 000000000..45a8b9f69 --- /dev/null +++ b/docs_src/sql_databases/sql_app_py310/database.py @@ -0,0 +1,13 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db" +# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db" + +engine = create_engine( + SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} +) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() diff --git a/docs_src/sql_databases/sql_app_py310/main.py b/docs_src/sql_databases/sql_app_py310/main.py new file mode 100644 index 000000000..a9856d0b6 --- /dev/null +++ b/docs_src/sql_databases/sql_app_py310/main.py @@ -0,0 +1,53 @@ +from fastapi import Depends, FastAPI, HTTPException +from sqlalchemy.orm import Session + +from . import crud, models, schemas +from .database import SessionLocal, engine + +models.Base.metadata.create_all(bind=engine) + +app = FastAPI() + + +# Dependency +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + + +@app.post("/users/", response_model=schemas.User) +def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)): + db_user = crud.get_user_by_email(db, email=user.email) + if db_user: + raise HTTPException(status_code=400, detail="Email already registered") + return crud.create_user(db=db, user=user) + + +@app.get("/users/", response_model=list[schemas.User]) +def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + users = crud.get_users(db, skip=skip, limit=limit) + return users + + +@app.get("/users/{user_id}", response_model=schemas.User) +def read_user(user_id: int, db: Session = Depends(get_db)): + db_user = crud.get_user(db, user_id=user_id) + if db_user is None: + raise HTTPException(status_code=404, detail="User not found") + return db_user + + +@app.post("/users/{user_id}/items/", response_model=schemas.Item) +def create_item_for_user( + user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db) +): + return crud.create_user_item(db=db, item=item, user_id=user_id) + + +@app.get("/items/", response_model=list[schemas.Item]) +def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + items = crud.get_items(db, skip=skip, limit=limit) + return items diff --git a/docs_src/sql_databases/sql_app_py310/models.py b/docs_src/sql_databases/sql_app_py310/models.py new file mode 100644 index 000000000..62d8ab4aa --- /dev/null +++ b/docs_src/sql_databases/sql_app_py310/models.py @@ -0,0 +1,26 @@ +from sqlalchemy import Boolean, Column, ForeignKey, Integer, String +from sqlalchemy.orm import relationship + +from .database import Base + + +class User(Base): + __tablename__ = "users" + + id = Column(Integer, primary_key=True, index=True) + email = Column(String, unique=True, index=True) + hashed_password = Column(String) + is_active = Column(Boolean, default=True) + + items = relationship("Item", back_populates="owner") + + +class Item(Base): + __tablename__ = "items" + + id = Column(Integer, primary_key=True, index=True) + title = Column(String, index=True) + description = Column(String, index=True) + owner_id = Column(Integer, ForeignKey("users.id")) + + owner = relationship("User", back_populates="items") diff --git a/docs_src/sql_databases/sql_app_py310/schemas.py b/docs_src/sql_databases/sql_app_py310/schemas.py new file mode 100644 index 000000000..aea2e3f10 --- /dev/null +++ b/docs_src/sql_databases/sql_app_py310/schemas.py @@ -0,0 +1,35 @@ +from pydantic import BaseModel + + +class ItemBase(BaseModel): + title: str + description: str | None = None + + +class ItemCreate(ItemBase): + pass + + +class Item(ItemBase): + id: int + owner_id: int + + class Config: + orm_mode = True + + +class UserBase(BaseModel): + email: str + + +class UserCreate(UserBase): + password: str + + +class User(UserBase): + id: int + is_active: bool + items: list[Item] = [] + + class Config: + orm_mode = True diff --git a/docs_src/sql_databases/sql_app_py310/tests/__init__.py b/docs_src/sql_databases/sql_app_py310/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/sql_databases/sql_app_py310/tests/test_sql_app.py b/docs_src/sql_databases/sql_app_py310/tests/test_sql_app.py new file mode 100644 index 000000000..c60c3356f --- /dev/null +++ b/docs_src/sql_databases/sql_app_py310/tests/test_sql_app.py @@ -0,0 +1,47 @@ +from fastapi.testclient import TestClient +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from ..database import Base +from ..main import app, get_db + +SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" + +engine = create_engine( + SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} +) +TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + + +Base.metadata.create_all(bind=engine) + + +def override_get_db(): + try: + db = TestingSessionLocal() + yield db + finally: + db.close() + + +app.dependency_overrides[get_db] = override_get_db + +client = TestClient(app) + + +def test_create_user(): + response = client.post( + "/users/", + json={"email": "deadpool@example.com", "password": "chimichangas4life"}, + ) + assert response.status_code == 200, response.text + data = response.json() + assert data["email"] == "deadpool@example.com" + assert "id" in data + user_id = data["id"] + + response = client.get(f"/users/{user_id}") + assert response.status_code == 200, response.text + data = response.json() + assert data["email"] == "deadpool@example.com" + assert data["id"] == user_id diff --git a/docs_src/sql_databases/sql_app_py39/__init__.py b/docs_src/sql_databases/sql_app_py39/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/sql_databases/sql_app_py39/alt_main.py b/docs_src/sql_databases/sql_app_py39/alt_main.py new file mode 100644 index 000000000..5de88ec3a --- /dev/null +++ b/docs_src/sql_databases/sql_app_py39/alt_main.py @@ -0,0 +1,60 @@ +from fastapi import Depends, FastAPI, HTTPException, Request, Response +from sqlalchemy.orm import Session + +from . import crud, models, schemas +from .database import SessionLocal, engine + +models.Base.metadata.create_all(bind=engine) + +app = FastAPI() + + +@app.middleware("http") +async def db_session_middleware(request: Request, call_next): + response = Response("Internal server error", status_code=500) + try: + request.state.db = SessionLocal() + response = await call_next(request) + finally: + request.state.db.close() + return response + + +# Dependency +def get_db(request: Request): + return request.state.db + + +@app.post("/users/", response_model=schemas.User) +def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)): + db_user = crud.get_user_by_email(db, email=user.email) + if db_user: + raise HTTPException(status_code=400, detail="Email already registered") + return crud.create_user(db=db, user=user) + + +@app.get("/users/", response_model=list[schemas.User]) +def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + users = crud.get_users(db, skip=skip, limit=limit) + return users + + +@app.get("/users/{user_id}", response_model=schemas.User) +def read_user(user_id: int, db: Session = Depends(get_db)): + db_user = crud.get_user(db, user_id=user_id) + if db_user is None: + raise HTTPException(status_code=404, detail="User not found") + return db_user + + +@app.post("/users/{user_id}/items/", response_model=schemas.Item) +def create_item_for_user( + user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db) +): + return crud.create_user_item(db=db, item=item, user_id=user_id) + + +@app.get("/items/", response_model=list[schemas.Item]) +def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + items = crud.get_items(db, skip=skip, limit=limit) + return items diff --git a/docs_src/sql_databases/sql_app_py39/crud.py b/docs_src/sql_databases/sql_app_py39/crud.py new file mode 100644 index 000000000..679acdb5c --- /dev/null +++ b/docs_src/sql_databases/sql_app_py39/crud.py @@ -0,0 +1,36 @@ +from sqlalchemy.orm import Session + +from . import models, schemas + + +def get_user(db: Session, user_id: int): + return db.query(models.User).filter(models.User.id == user_id).first() + + +def get_user_by_email(db: Session, email: str): + return db.query(models.User).filter(models.User.email == email).first() + + +def get_users(db: Session, skip: int = 0, limit: int = 100): + return db.query(models.User).offset(skip).limit(limit).all() + + +def create_user(db: Session, user: schemas.UserCreate): + fake_hashed_password = user.password + "notreallyhashed" + db_user = models.User(email=user.email, hashed_password=fake_hashed_password) + db.add(db_user) + db.commit() + db.refresh(db_user) + return db_user + + +def get_items(db: Session, skip: int = 0, limit: int = 100): + return db.query(models.Item).offset(skip).limit(limit).all() + + +def create_user_item(db: Session, item: schemas.ItemCreate, user_id: int): + db_item = models.Item(**item.dict(), owner_id=user_id) + db.add(db_item) + db.commit() + db.refresh(db_item) + return db_item diff --git a/docs_src/sql_databases/sql_app_py39/database.py b/docs_src/sql_databases/sql_app_py39/database.py new file mode 100644 index 000000000..45a8b9f69 --- /dev/null +++ b/docs_src/sql_databases/sql_app_py39/database.py @@ -0,0 +1,13 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db" +# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db" + +engine = create_engine( + SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} +) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() diff --git a/docs_src/sql_databases/sql_app_py39/main.py b/docs_src/sql_databases/sql_app_py39/main.py new file mode 100644 index 000000000..a9856d0b6 --- /dev/null +++ b/docs_src/sql_databases/sql_app_py39/main.py @@ -0,0 +1,53 @@ +from fastapi import Depends, FastAPI, HTTPException +from sqlalchemy.orm import Session + +from . import crud, models, schemas +from .database import SessionLocal, engine + +models.Base.metadata.create_all(bind=engine) + +app = FastAPI() + + +# Dependency +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + + +@app.post("/users/", response_model=schemas.User) +def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)): + db_user = crud.get_user_by_email(db, email=user.email) + if db_user: + raise HTTPException(status_code=400, detail="Email already registered") + return crud.create_user(db=db, user=user) + + +@app.get("/users/", response_model=list[schemas.User]) +def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + users = crud.get_users(db, skip=skip, limit=limit) + return users + + +@app.get("/users/{user_id}", response_model=schemas.User) +def read_user(user_id: int, db: Session = Depends(get_db)): + db_user = crud.get_user(db, user_id=user_id) + if db_user is None: + raise HTTPException(status_code=404, detail="User not found") + return db_user + + +@app.post("/users/{user_id}/items/", response_model=schemas.Item) +def create_item_for_user( + user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db) +): + return crud.create_user_item(db=db, item=item, user_id=user_id) + + +@app.get("/items/", response_model=list[schemas.Item]) +def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + items = crud.get_items(db, skip=skip, limit=limit) + return items diff --git a/docs_src/sql_databases/sql_app_py39/models.py b/docs_src/sql_databases/sql_app_py39/models.py new file mode 100644 index 000000000..62d8ab4aa --- /dev/null +++ b/docs_src/sql_databases/sql_app_py39/models.py @@ -0,0 +1,26 @@ +from sqlalchemy import Boolean, Column, ForeignKey, Integer, String +from sqlalchemy.orm import relationship + +from .database import Base + + +class User(Base): + __tablename__ = "users" + + id = Column(Integer, primary_key=True, index=True) + email = Column(String, unique=True, index=True) + hashed_password = Column(String) + is_active = Column(Boolean, default=True) + + items = relationship("Item", back_populates="owner") + + +class Item(Base): + __tablename__ = "items" + + id = Column(Integer, primary_key=True, index=True) + title = Column(String, index=True) + description = Column(String, index=True) + owner_id = Column(Integer, ForeignKey("users.id")) + + owner = relationship("User", back_populates="items") diff --git a/docs_src/sql_databases/sql_app_py39/schemas.py b/docs_src/sql_databases/sql_app_py39/schemas.py new file mode 100644 index 000000000..a19f1cdfe --- /dev/null +++ b/docs_src/sql_databases/sql_app_py39/schemas.py @@ -0,0 +1,37 @@ +from typing import Optional + +from pydantic import BaseModel + + +class ItemBase(BaseModel): + title: str + description: Optional[str] = None + + +class ItemCreate(ItemBase): + pass + + +class Item(ItemBase): + id: int + owner_id: int + + class Config: + orm_mode = True + + +class UserBase(BaseModel): + email: str + + +class UserCreate(UserBase): + password: str + + +class User(UserBase): + id: int + is_active: bool + items: list[Item] = [] + + class Config: + orm_mode = True diff --git a/docs_src/sql_databases/sql_app_py39/tests/__init__.py b/docs_src/sql_databases/sql_app_py39/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/sql_databases/sql_app_py39/tests/test_sql_app.py b/docs_src/sql_databases/sql_app_py39/tests/test_sql_app.py new file mode 100644 index 000000000..c60c3356f --- /dev/null +++ b/docs_src/sql_databases/sql_app_py39/tests/test_sql_app.py @@ -0,0 +1,47 @@ +from fastapi.testclient import TestClient +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from ..database import Base +from ..main import app, get_db + +SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" + +engine = create_engine( + SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} +) +TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + + +Base.metadata.create_all(bind=engine) + + +def override_get_db(): + try: + db = TestingSessionLocal() + yield db + finally: + db.close() + + +app.dependency_overrides[get_db] = override_get_db + +client = TestClient(app) + + +def test_create_user(): + response = client.post( + "/users/", + json={"email": "deadpool@example.com", "password": "chimichangas4life"}, + ) + assert response.status_code == 200, response.text + data = response.json() + assert data["email"] == "deadpool@example.com" + assert "id" in data + user_id = data["id"] + + response = client.get(f"/users/{user_id}") + assert response.status_code == 200, response.text + data = response.json() + assert data["email"] == "deadpool@example.com" + assert data["id"] == user_id diff --git a/pyproject.toml b/pyproject.toml index e6148831b..fa399c492 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,7 @@ classifiers = [ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Internet :: WWW/HTTP", ] diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial002_py310.py b/tests/test_tutorial/test_background_tasks/test_tutorial002_py310.py new file mode 100644 index 000000000..6937c8fab --- /dev/null +++ b/tests/test_tutorial/test_background_tasks/test_tutorial002_py310.py @@ -0,0 +1,21 @@ +import os +from pathlib import Path + +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + + +@needs_py310 +def test(): + from docs_src.background_tasks.tutorial002_py310 import app + + client = TestClient(app) + log = Path("log.txt") + if log.is_file(): + os.remove(log) # pragma: no cover + response = client.post("/send-notification/foo@example.com?q=some-query") + assert response.status_code == 200, response.text + assert response.json() == {"message": "Message sent"} + with open("./log.txt") as f: + assert "found query: some-query\nmessage to foo@example.com" in f.read() diff --git a/tests/test_tutorial/test_body/test_tutorial001_py310.py b/tests/test_tutorial/test_body/test_tutorial001_py310.py new file mode 100644 index 000000000..e292b5346 --- /dev/null +++ b/tests/test_tutorial/test_body/test_tutorial001_py310.py @@ -0,0 +1,292 @@ +from unittest.mock import patch + +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "post": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + } + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + "description": {"title": "Description", "type": "string"}, + "tax": {"title": "Tax", "type": "number"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture +def client(): + from docs_src.body.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +price_missing = { + "detail": [ + { + "loc": ["body", "price"], + "msg": "field required", + "type": "value_error.missing", + } + ] +} + +price_not_float = { + "detail": [ + { + "loc": ["body", "price"], + "msg": "value is not a valid float", + "type": "type_error.float", + } + ] +} + +name_price_missing = { + "detail": [ + { + "loc": ["body", "name"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["body", "price"], + "msg": "field required", + "type": "value_error.missing", + }, + ] +} + +body_missing = { + "detail": [ + {"loc": ["body"], "msg": "field required", "type": "value_error.missing"} + ] +} + + +@needs_py310 +@pytest.mark.parametrize( + "path,body,expected_status,expected_response", + [ + ( + "/items/", + {"name": "Foo", "price": 50.5}, + 200, + {"name": "Foo", "price": 50.5, "description": None, "tax": None}, + ), + ( + "/items/", + {"name": "Foo", "price": "50.5"}, + 200, + {"name": "Foo", "price": 50.5, "description": None, "tax": None}, + ), + ( + "/items/", + {"name": "Foo", "price": "50.5", "description": "Some Foo"}, + 200, + {"name": "Foo", "price": 50.5, "description": "Some Foo", "tax": None}, + ), + ( + "/items/", + {"name": "Foo", "price": "50.5", "description": "Some Foo", "tax": 0.3}, + 200, + {"name": "Foo", "price": 50.5, "description": "Some Foo", "tax": 0.3}, + ), + ("/items/", {"name": "Foo"}, 422, price_missing), + ("/items/", {"name": "Foo", "price": "twenty"}, 422, price_not_float), + ("/items/", {}, 422, name_price_missing), + ("/items/", None, 422, body_missing), + ], +) +def test_post_body(path, body, expected_status, expected_response, client: TestClient): + response = client.post(path, json=body) + assert response.status_code == expected_status + assert response.json() == expected_response + + +@needs_py310 +def test_post_broken_body(client: TestClient): + response = client.post( + "/items/", + headers={"content-type": "application/json"}, + data="{some broken json}", + ) + assert response.status_code == 422, response.text + assert response.json() == { + "detail": [ + { + "loc": ["body", 1], + "msg": "Expecting property name enclosed in double quotes: line 1 column 2 (char 1)", + "type": "value_error.jsondecode", + "ctx": { + "msg": "Expecting property name enclosed in double quotes", + "doc": "{some broken json}", + "pos": 1, + "lineno": 1, + "colno": 2, + }, + } + ] + } + + +@needs_py310 +def test_post_form_for_json(client: TestClient): + response = client.post("/items/", data={"name": "Foo", "price": 50.5}) + assert response.status_code == 422, response.text + assert response.json() == { + "detail": [ + { + "loc": ["body"], + "msg": "value is not a valid dict", + "type": "type_error.dict", + } + ] + } + + +@needs_py310 +def test_explicit_content_type(client: TestClient): + response = client.post( + "/items/", + data='{"name": "Foo", "price": 50.5}', + headers={"Content-Type": "application/json"}, + ) + assert response.status_code == 200, response.text + + +@needs_py310 +def test_geo_json(client: TestClient): + response = client.post( + "/items/", + data='{"name": "Foo", "price": 50.5}', + headers={"Content-Type": "application/geo+json"}, + ) + assert response.status_code == 200, response.text + + +@needs_py310 +def test_no_content_type_is_json(client: TestClient): + response = client.post( + "/items/", + data='{"name": "Foo", "price": 50.5}', + ) + assert response.status_code == 200, response.text + assert response.json() == { + "name": "Foo", + "description": None, + "price": 50.5, + "tax": None, + } + + +@needs_py310 +def test_wrong_headers(client: TestClient): + data = '{"name": "Foo", "price": 50.5}' + invalid_dict = { + "detail": [ + { + "loc": ["body"], + "msg": "value is not a valid dict", + "type": "type_error.dict", + } + ] + } + + response = client.post("/items/", data=data, headers={"Content-Type": "text/plain"}) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + + response = client.post( + "/items/", data=data, headers={"Content-Type": "application/geo+json-seq"} + ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + response = client.post( + "/items/", data=data, headers={"Content-Type": "application/not-really-json"} + ) + assert response.status_code == 422, response.text + assert response.json() == invalid_dict + + +@needs_py310 +def test_other_exceptions(client: TestClient): + with patch("json.loads", side_effect=Exception): + response = client.post("/items/", json={"test": "test2"}) + assert response.status_code == 400, response.text diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py new file mode 100644 index 000000000..d7a525ea7 --- /dev/null +++ b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py @@ -0,0 +1,176 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "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": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_update_item_items__item_id__put" + } + } + }, + "required": True, + }, + } + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": { + "title": "The description of the item", + "maxLength": 300, + "type": "string", + }, + "price": { + "title": "Price", + "exclusiveMinimum": 0.0, + "type": "number", + "description": "The price must be greater than zero", + }, + "tax": {"title": "Tax", "type": "number"}, + }, + }, + "Body_update_item_items__item_id__put": { + "title": "Body_update_item_items__item_id__put", + "required": ["item"], + "type": "object", + "properties": {"item": {"$ref": "#/components/schemas/Item"}}, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.body_fields.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +price_not_greater = { + "detail": [ + { + "ctx": {"limit_value": 0}, + "loc": ["body", "item", "price"], + "msg": "ensure this value is greater than 0", + "type": "value_error.number.not_gt", + } + ] +} + + +@needs_py310 +@pytest.mark.parametrize( + "path,body,expected_status,expected_response", + [ + ( + "/items/5", + {"item": {"name": "Foo", "price": 3.0}}, + 200, + { + "item_id": 5, + "item": {"name": "Foo", "price": 3.0, "description": None, "tax": None}, + }, + ), + ( + "/items/6", + { + "item": { + "name": "Bar", + "price": 0.2, + "description": "Some bar", + "tax": "5.4", + } + }, + 200, + { + "item_id": 6, + "item": { + "name": "Bar", + "price": 0.2, + "description": "Some bar", + "tax": 5.4, + }, + }, + ), + ("/items/5", {"item": {"name": "Foo", "price": -3.0}}, 422, price_not_greater), + ], +) +def test(path, body, expected_status, expected_response, client: TestClient): + response = client.put(path, json=body) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py new file mode 100644 index 000000000..85ba41ce6 --- /dev/null +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py @@ -0,0 +1,155 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "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": "The ID of the item to get", + "maximum": 1000.0, + "minimum": 0.0, + "type": "integer", + }, + "name": "item_id", + "in": "path", + }, + { + "required": False, + "schema": {"title": "Q", "type": "string"}, + "name": "q", + "in": "query", + }, + ], + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + } + }, + } + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + "description": {"title": "Description", "type": "string"}, + "tax": {"title": "Tax", "type": "number"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.body_multiple_params.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +item_id_not_int = { + "detail": [ + { + "loc": ["path", "item_id"], + "msg": "value is not a valid integer", + "type": "type_error.integer", + } + ] +} + + +@needs_py310 +@pytest.mark.parametrize( + "path,body,expected_status,expected_response", + [ + ( + "/items/5?q=bar", + {"name": "Foo", "price": 50.5}, + 200, + { + "item_id": 5, + "item": { + "name": "Foo", + "price": 50.5, + "description": None, + "tax": None, + }, + "q": "bar", + }, + ), + ("/items/5?q=bar", None, 200, {"item_id": 5, "q": "bar"}), + ("/items/5", None, 200, {"item_id": 5}), + ("/items/foo", None, 422, item_id_not_int), + ], +) +def test_post_body(path, body, expected_status, expected_response, client: TestClient): + response = client.put(path, json=body) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py new file mode 100644 index 000000000..f896f7bf5 --- /dev/null +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py @@ -0,0 +1,206 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "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": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_update_item_items__item_id__put" + } + } + }, + "required": True, + }, + } + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + "description": {"title": "Description", "type": "string"}, + "tax": {"title": "Tax", "type": "number"}, + }, + }, + "User": { + "title": "User", + "required": ["username"], + "type": "object", + "properties": { + "username": {"title": "Username", "type": "string"}, + "full_name": {"title": "Full Name", "type": "string"}, + }, + }, + "Body_update_item_items__item_id__put": { + "title": "Body_update_item_items__item_id__put", + "required": ["item", "user", "importance"], + "type": "object", + "properties": { + "item": {"$ref": "#/components/schemas/Item"}, + "user": {"$ref": "#/components/schemas/User"}, + "importance": {"title": "Importance", "type": "integer"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.body_multiple_params.tutorial003_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +# Test required and embedded body parameters with no bodies sent +@needs_py310 +@pytest.mark.parametrize( + "path,body,expected_status,expected_response", + [ + ( + "/items/5", + { + "importance": 2, + "item": {"name": "Foo", "price": 50.5}, + "user": {"username": "Dave"}, + }, + 200, + { + "item_id": 5, + "importance": 2, + "item": { + "name": "Foo", + "price": 50.5, + "description": None, + "tax": None, + }, + "user": {"username": "Dave", "full_name": None}, + }, + ), + ( + "/items/5", + None, + 422, + { + "detail": [ + { + "loc": ["body", "item"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["body", "user"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["body", "importance"], + "msg": "field required", + "type": "value_error.missing", + }, + ] + }, + ), + ( + "/items/5", + [], + 422, + { + "detail": [ + { + "loc": ["body", "item"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["body", "user"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["body", "importance"], + "msg": "field required", + "type": "value_error.missing", + }, + ] + }, + ), + ], +) +def test_post_body(path, body, expected_status, expected_response, client: TestClient): + response = client.put(path, json=body) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py new file mode 100644 index 000000000..17ca29ce5 --- /dev/null +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py @@ -0,0 +1,113 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/index-weights/": { + "post": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Create Index Weights", + "operationId": "create_index_weights_index_weights__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "title": "Weights", + "type": "object", + "additionalProperties": {"type": "number"}, + } + } + }, + "required": True, + }, + } + } + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.body_nested_models.tutorial009_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py39 +def test_post_body(client: TestClient): + data = {"2": 2.2, "3": 3.3} + response = client.post("/index-weights/", json=data) + assert response.status_code == 200, response.text + assert response.json() == data + + +@needs_py39 +def test_post_invalid_body(client: TestClient): + data = {"foo": 2.2, "3": 3.3} + response = client.post("/index-weights/", json=data) + assert response.status_code == 422, response.text + assert response.json() == { + "detail": [ + { + "loc": ["body", "__key__"], + "msg": "value is not a valid integer", + "type": "type_error.integer", + } + ] + } diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py new file mode 100644 index 000000000..ca1d8c585 --- /dev/null +++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py @@ -0,0 +1,172 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + }, + "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/Item"} + } + }, + }, + "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/Item"} + } + }, + "required": True, + }, + }, + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + "tax": {"title": "Tax", "type": "number", "default": 10.5}, + "tags": { + "title": "Tags", + "type": "array", + "items": {"type": "string"}, + "default": [], + }, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.body_updates.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py310 +def test_get(client: TestClient): + response = client.get("/items/baz") + assert response.status_code == 200, response.text + assert response.json() == { + "name": "Baz", + "description": None, + "price": 50.2, + "tax": 10.5, + "tags": [], + } + + +@needs_py310 +def test_put(client: TestClient): + response = client.put( + "/items/bar", json={"name": "Barz", "price": 3, "description": None} + ) + assert response.json() == { + "name": "Barz", + "description": None, + "price": 3, + "tax": 10.5, + "tags": [], + } diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py new file mode 100644 index 000000000..f2b184c4f --- /dev/null +++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py @@ -0,0 +1,172 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + }, + "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/Item"} + } + }, + }, + "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/Item"} + } + }, + "required": True, + }, + }, + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + "tax": {"title": "Tax", "type": "number", "default": 10.5}, + "tags": { + "title": "Tags", + "type": "array", + "items": {"type": "string"}, + "default": [], + }, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.body_updates.tutorial001_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py39 +def test_get(client: TestClient): + response = client.get("/items/baz") + assert response.status_code == 200, response.text + assert response.json() == { + "name": "Baz", + "description": None, + "price": 50.2, + "tax": 10.5, + "tags": [], + } + + +@needs_py39 +def test_put(client: TestClient): + response = client.put( + "/items/bar", json={"name": "Barz", "price": 3, "description": None} + ) + assert response.json() == { + "name": "Barz", + "description": None, + "price": 3, + "tax": 10.5, + "tags": [], + } diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py new file mode 100644 index 000000000..587a328da --- /dev/null +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py @@ -0,0 +1,100 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Ads Id", "type": "string"}, + "name": "ads_id", + "in": "cookie", + } + ], + } + } + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.cookie_params.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +@pytest.mark.parametrize( + "path,cookies,expected_status,expected_response", + [ + ("/openapi.json", None, 200, openapi_schema), + ("/items", None, 200, {"ads_id": None}), + ("/items", {"ads_id": "ads_track"}, 200, {"ads_id": "ads_track"}), + ( + "/items", + {"ads_id": "ads_track", "session": "cookiesession"}, + 200, + {"ads_id": "ads_track"}, + ), + ("/items", {"session": "cookiesession"}, 200, {"ads_id": None}), + ], +) +def test(path, cookies, expected_status, expected_response, client: TestClient): + response = client.get(path, cookies=cookies) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py new file mode 100644 index 000000000..a7991170e --- /dev/null +++ b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py @@ -0,0 +1,157 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Q", "type": "string"}, + "name": "q", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Skip", "type": "integer", "default": 0}, + "name": "skip", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Limit", "type": "integer", "default": 100}, + "name": "limit", + "in": "query", + }, + ], + } + }, + "/users/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Users", + "operationId": "read_users_users__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Q", "type": "string"}, + "name": "q", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Skip", "type": "integer", "default": 0}, + "name": "skip", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Limit", "type": "integer", "default": 100}, + "name": "limit", + "in": "query", + }, + ], + } + }, + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.dependencies.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py310 +@pytest.mark.parametrize( + "path,expected_status,expected_response", + [ + ("/items", 200, {"q": None, "skip": 0, "limit": 100}), + ("/items?q=foo", 200, {"q": "foo", "skip": 0, "limit": 100}), + ("/items?q=foo&skip=5", 200, {"q": "foo", "skip": 5, "limit": 100}), + ("/items?q=foo&skip=5&limit=30", 200, {"q": "foo", "skip": 5, "limit": 30}), + ("/users", 200, {"q": None, "skip": 0, "limit": 100}), + ("/openapi.json", 200, openapi_schema), + ], +) +def test_get(path, expected_status, expected_response, client: TestClient): + response = client.get(path) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py new file mode 100644 index 000000000..f66a36a99 --- /dev/null +++ b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py @@ -0,0 +1,152 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Q", "type": "string"}, + "name": "q", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Skip", "type": "integer", "default": 0}, + "name": "skip", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Limit", "type": "integer", "default": 100}, + "name": "limit", + "in": "query", + }, + ], + } + } + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.dependencies.tutorial004_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py310 +@pytest.mark.parametrize( + "path,expected_status,expected_response", + [ + ( + "/items", + 200, + { + "items": [ + {"item_name": "Foo"}, + {"item_name": "Bar"}, + {"item_name": "Baz"}, + ] + }, + ), + ( + "/items?q=foo", + 200, + { + "items": [ + {"item_name": "Foo"}, + {"item_name": "Bar"}, + {"item_name": "Baz"}, + ], + "q": "foo", + }, + ), + ( + "/items?q=foo&skip=1", + 200, + {"items": [{"item_name": "Bar"}, {"item_name": "Baz"}], "q": "foo"}, + ), + ( + "/items?q=bar&limit=2", + 200, + {"items": [{"item_name": "Foo"}, {"item_name": "Bar"}], "q": "bar"}, + ), + ( + "/items?q=bar&skip=1&limit=1", + 200, + {"items": [{"item_name": "Bar"}], "q": "bar"}, + ), + ( + "/items?limit=1&q=bar&skip=1", + 200, + {"items": [{"item_name": "Bar"}], "q": "bar"}, + ), + ], +) +def test_get(path, expected_status, expected_response, client: TestClient): + response = client.get(path) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py new file mode 100644 index 000000000..3d4c1d07d --- /dev/null +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py @@ -0,0 +1,146 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Items", + "operationId": "read_items_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": { + "title": "Item Id", + "type": "string", + "format": "uuid", + }, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_read_items_items__item_id__put" + } + } + } + }, + } + } + }, + "components": { + "schemas": { + "Body_read_items_items__item_id__put": { + "title": "Body_read_items_items__item_id__put", + "type": "object", + "properties": { + "start_datetime": { + "title": "Start Datetime", + "type": "string", + "format": "date-time", + }, + "end_datetime": { + "title": "End Datetime", + "type": "string", + "format": "date-time", + }, + "repeat_at": { + "title": "Repeat At", + "type": "string", + "format": "time", + }, + "process_after": { + "title": "Process After", + "type": "number", + "format": "time-delta", + }, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.extra_data_types.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py310 +def test_extra_types(client: TestClient): + item_id = "ff97dd87-a4a5-4a12-b412-cde99f33e00e" + data = { + "start_datetime": "2018-12-22T14:00:00+00:00", + "end_datetime": "2018-12-24T15:00:00+00:00", + "repeat_at": "15:30:00", + "process_after": 300, + } + expected_response = data.copy() + expected_response.update( + { + "start_process": "2018-12-22T14:05:00+00:00", + "duration": 176_100, + "item_id": item_id, + } + ) + response = client.put(f"/items/{item_id}", json=data) + assert response.status_code == 200, response.text + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py new file mode 100644 index 000000000..185bc3a37 --- /dev/null +++ b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py @@ -0,0 +1,135 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Item Items Item Id Get", + "anyOf": [ + {"$ref": "#/components/schemas/PlaneItem"}, + {"$ref": "#/components/schemas/CarItem"}, + ], + } + } + }, + }, + "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", + } + ], + } + } + }, + "components": { + "schemas": { + "PlaneItem": { + "title": "PlaneItem", + "required": ["description", "size"], + "type": "object", + "properties": { + "description": {"title": "Description", "type": "string"}, + "type": {"title": "Type", "type": "string", "default": "plane"}, + "size": {"title": "Size", "type": "integer"}, + }, + }, + "CarItem": { + "title": "CarItem", + "required": ["description"], + "type": "object", + "properties": { + "description": {"title": "Description", "type": "string"}, + "type": {"title": "Type", "type": "string", "default": "car"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.extra_models.tutorial003_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py310 +def test_get_car(client: TestClient): + response = client.get("/items/item1") + assert response.status_code == 200, response.text + assert response.json() == { + "description": "All my friends drive a low rider", + "type": "car", + } + + +@needs_py310 +def test_get_plane(client: TestClient): + response = client.get("/items/item2") + assert response.status_code == 200, response.text + assert response.json() == { + "description": "Music is my aeroplane, it's my aeroplane", + "type": "plane", + "size": 5, + } diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py b/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py new file mode 100644 index 000000000..7f4f5b9be --- /dev/null +++ b/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py @@ -0,0 +1,69 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Items Items Get", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + } + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + } + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "required": ["name", "description"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + }, + } + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.extra_models.tutorial004_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py39 +def test_get_items(client: TestClient): + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + {"name": "Foo", "description": "There comes my hero"}, + {"name": "Red", "description": "It's my aeroplane"}, + ] diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py b/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py new file mode 100644 index 000000000..3bb5a99f1 --- /dev/null +++ b/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py @@ -0,0 +1,53 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/keyword-weights/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Read Keyword Weights Keyword Weights Get", + "type": "object", + "additionalProperties": {"type": "number"}, + } + } + }, + } + }, + "summary": "Read Keyword Weights", + "operationId": "read_keyword_weights_keyword_weights__get", + } + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.extra_models.tutorial005_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py39 +def test_get_items(client: TestClient): + response = client.get("/keyword-weights/") + assert response.status_code == 200, response.text + assert response.json() == {"foo": 2.3, "bar": 3.4} diff --git a/tests/test_tutorial/test_header_params/test_tutorial001_py310.py b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py new file mode 100644 index 000000000..f5ee17428 --- /dev/null +++ b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py @@ -0,0 +1,94 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "parameters": [ + { + "required": False, + "schema": {"title": "User-Agent", "type": "string"}, + "name": "user-agent", + "in": "header", + } + ], + } + } + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.header_params.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +@pytest.mark.parametrize( + "path,headers,expected_status,expected_response", + [ + ("/openapi.json", None, 200, openapi_schema), + ("/items", None, 200, {"User-Agent": "testclient"}), + ("/items", {"X-Header": "notvalid"}, 200, {"User-Agent": "testclient"}), + ("/items", {"User-Agent": "FastAPI test"}, 200, {"User-Agent": "FastAPI test"}), + ], +) +def test(path, headers, expected_status, expected_response, client: TestClient): + response = client.get(path, headers=headers) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py new file mode 100644 index 000000000..1f617da70 --- /dev/null +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py @@ -0,0 +1,121 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "post": { + "responses": { + "200": { + "description": "The created item", + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + }, + "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/Item"} + } + }, + "required": True, + }, + } + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + "description": {"title": "Description", "type": "string"}, + "tax": {"title": "Tax", "type": "number"}, + "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": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.path_operation_configuration.tutorial005_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py310 +def test_query_params_str_validations(client: TestClient): + response = client.post("/items/", json={"name": "Foo", "price": 42}) + assert response.status_code == 200, response.text + assert response.json() == { + "name": "Foo", + "price": 42, + "description": None, + "tax": None, + "tags": [], + } diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py new file mode 100644 index 000000000..ffdf05081 --- /dev/null +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py @@ -0,0 +1,121 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "post": { + "responses": { + "200": { + "description": "The created item", + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + }, + "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/Item"} + } + }, + "required": True, + }, + } + } + }, + "components": { + "schemas": { + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + "description": {"title": "Description", "type": "string"}, + "tax": {"title": "Tax", "type": "number"}, + "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": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.path_operation_configuration.tutorial005_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py39 +def test_query_params_str_validations(client: TestClient): + response = client.post("/items/", json={"name": "Foo", "price": 42}) + assert response.status_code == 200, response.text + assert response.json() == { + "name": "Foo", + "price": 42, + "description": None, + "tax": None, + "tags": [], + } diff --git a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py new file mode 100644 index 000000000..1986d27d0 --- /dev/null +++ b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py @@ -0,0 +1,148 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read User Item", + "operationId": "read_user_item_items__item_id__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "string"}, + "name": "item_id", + "in": "path", + }, + { + "required": True, + "schema": {"title": "Needy", "type": "string"}, + "name": "needy", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Skip", "type": "integer", "default": 0}, + "name": "skip", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Limit", "type": "integer"}, + "name": "limit", + "in": "query", + }, + ], + } + } + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +query_required = { + "detail": [ + { + "loc": ["query", "needy"], + "msg": "field required", + "type": "value_error.missing", + } + ] +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.query_params.tutorial006_py310 import app + + c = TestClient(app) + return c + + +@needs_py310 +@pytest.mark.parametrize( + "path,expected_status,expected_response", + [ + ("/openapi.json", 200, openapi_schema), + ( + "/items/foo?needy=very", + 200, + {"item_id": "foo", "needy": "very", "skip": 0, "limit": None}, + ), + ( + "/items/foo?skip=a&limit=b", + 422, + { + "detail": [ + { + "loc": ["query", "needy"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["query", "skip"], + "msg": "value is not a valid integer", + "type": "type_error.integer", + }, + { + "loc": ["query", "limit"], + "msg": "value is not a valid integer", + "type": "type_error.integer", + }, + ] + }, + ), + ], +) +def test(path, expected_status, expected_response, client: TestClient): + response = client.get(path) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py new file mode 100644 index 000000000..66b24017e --- /dev/null +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py @@ -0,0 +1,132 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "parameters": [ + { + "description": "Query string for the items to search in the database that have a good match", + "required": False, + "deprecated": True, + "schema": { + "title": "Query string", + "maxLength": 50, + "minLength": 3, + "pattern": "^fixedquery$", + "type": "string", + "description": "Query string for the items to search in the database that have a good match", + }, + "name": "item-query", + "in": "query", + } + ], + } + } + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.query_params_str_validations.tutorial010_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +regex_error = { + "detail": [ + { + "ctx": {"pattern": "^fixedquery$"}, + "loc": ["query", "item-query"], + "msg": 'string does not match regex "^fixedquery$"', + "type": "value_error.str.regex", + } + ] +} + + +@needs_py310 +@pytest.mark.parametrize( + "q_name,q,expected_status,expected_response", + [ + (None, None, 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}), + ( + "item-query", + "fixedquery", + 200, + {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}], "q": "fixedquery"}, + ), + ("q", "fixedquery", 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}), + ("item-query", "nonregexquery", 422, regex_error), + ], +) +def test_query_params_str_validations( + q_name, q, expected_status, expected_response, client: TestClient +): + url = "/items/" + if q_name and q: + url = f"{url}?{q_name}={q}" + response = client.get(url) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py new file mode 100644 index 000000000..8894ee1b5 --- /dev/null +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py @@ -0,0 +1,105 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Q", + "type": "array", + "items": {"type": "string"}, + }, + "name": "q", + "in": "query", + } + ], + } + } + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.query_params_str_validations.tutorial011_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py310 +def test_multi_query_values(client: TestClient): + url = "/items/?q=foo&q=bar" + response = client.get(url) + assert response.status_code == 200, response.text + assert response.json() == {"q": ["foo", "bar"]} + + +@needs_py310 +def test_query_no_values(client: TestClient): + url = "/items/" + response = client.get(url) + assert response.status_code == 200, response.text + assert response.json() == {"q": None} diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py new file mode 100644 index 000000000..b10e70af7 --- /dev/null +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py @@ -0,0 +1,105 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Q", + "type": "array", + "items": {"type": "string"}, + }, + "name": "q", + "in": "query", + } + ], + } + } + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.query_params_str_validations.tutorial011_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py39 +def test_multi_query_values(client: TestClient): + url = "/items/?q=foo&q=bar" + response = client.get(url) + assert response.status_code == 200, response.text + assert response.json() == {"q": ["foo", "bar"]} + + +@needs_py39 +def test_query_no_values(client: TestClient): + url = "/items/" + response = client.get(url) + assert response.status_code == 200, response.text + assert response.json() == {"q": None} diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py new file mode 100644 index 000000000..a9cbce02a --- /dev/null +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py @@ -0,0 +1,106 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Items", + "operationId": "read_items_items__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Q", + "type": "array", + "items": {"type": "string"}, + "default": ["foo", "bar"], + }, + "name": "q", + "in": "query", + } + ], + } + } + }, + "components": { + "schemas": { + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.query_params_str_validations.tutorial012_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py39 +def test_default_query_values(client: TestClient): + url = "/items/" + response = client.get(url) + assert response.status_code == 200, response.text + assert response.json() == {"q": ["foo", "bar"]} + + +@needs_py39 +def test_multi_query_values(client: TestClient): + url = "/items/?q=baz&q=foobar" + response = client.get(url) + assert response.status_code == 200, response.text + assert response.json() == {"q": ["baz", "foobar"]} diff --git a/tests/test_tutorial/test_request_files/test_tutorial002_py39.py b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py new file mode 100644 index 000000000..bbdf25cd9 --- /dev/null +++ b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py @@ -0,0 +1,235 @@ +import pytest +from fastapi import FastAPI +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/files/": { + "post": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Create Files", + "operationId": "create_files_files__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_files_files__post" + } + } + }, + "required": True, + }, + } + }, + "/uploadfiles/": { + "post": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Create Upload Files", + "operationId": "create_upload_files_uploadfiles__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_upload_files_uploadfiles__post" + } + } + }, + "required": True, + }, + } + }, + "/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + "summary": "Main", + "operationId": "main__get", + } + }, + }, + "components": { + "schemas": { + "Body_create_upload_files_uploadfiles__post": { + "title": "Body_create_upload_files_uploadfiles__post", + "required": ["files"], + "type": "object", + "properties": { + "files": { + "title": "Files", + "type": "array", + "items": {"type": "string", "format": "binary"}, + } + }, + }, + "Body_create_files_files__post": { + "title": "Body_create_files_files__post", + "required": ["files"], + "type": "object", + "properties": { + "files": { + "title": "Files", + "type": "array", + "items": {"type": "string", "format": "binary"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "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"}, + } + }, + }, + } + }, +} + + +@pytest.fixture(name="app") +def get_app(): + from docs_src.request_files.tutorial002_py39 import app + + return app + + +@pytest.fixture(name="client") +def get_client(app: FastAPI): + + client = TestClient(app) + return client + + +@needs_py39 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +file_required = { + "detail": [ + { + "loc": ["body", "files"], + "msg": "field required", + "type": "value_error.missing", + } + ] +} + + +@needs_py39 +def test_post_form_no_body(client: TestClient): + response = client.post("/files/") + assert response.status_code == 422, response.text + assert response.json() == file_required + + +@needs_py39 +def test_post_body_json(client: TestClient): + response = client.post("/files/", json={"file": "Foo"}) + assert response.status_code == 422, response.text + assert response.json() == file_required + + +@needs_py39 +def test_post_files(tmp_path, app: FastAPI): + path = tmp_path / "test.txt" + path.write_bytes(b"") + path2 = tmp_path / "test2.txt" + path2.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file, path2.open("rb") as file2: + response = client.post( + "/files/", + files=( + ("files", ("test.txt", file)), + ("files", ("test2.txt", file2)), + ), + ) + assert response.status_code == 200, response.text + assert response.json() == {"file_sizes": [14, 15]} + + +@needs_py39 +def test_post_upload_file(tmp_path, app: FastAPI): + path = tmp_path / "test.txt" + path.write_bytes(b"") + path2 = tmp_path / "test2.txt" + path2.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file, path2.open("rb") as file2: + response = client.post( + "/uploadfiles/", + files=( + ("files", ("test.txt", file)), + ("files", ("test2.txt", file2)), + ), + ) + assert response.status_code == 200, response.text + assert response.json() == {"filenames": ["test.txt", "test2.txt"]} + + +@needs_py39 +def test_get_root(app: FastAPI): + client = TestClient(app) + response = client.get("/") + assert response.status_code == 200, response.text + assert b" Date: Fri, 7 Jan 2022 14:12:16 +0000 Subject: [PATCH 339/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ce1d3144d..f6e66d805 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add docs and tests for Python 3.9 and Python 3.10. PR [#3712](https://github.com/tiangolo/fastapi/pull/3712) by [@tiangolo](https://github.com/tiangolo). * ⬆ Upgrade MkDocs Material and configs. PR [#4385](https://github.com/tiangolo/fastapi/pull/4385) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade Starlette to 0.17.1. PR [#4145](https://github.com/tiangolo/fastapi/pull/4145) by [@simondale00](https://github.com/simondale00). ## 0.70.1 From a1ede32f29366902033e701f09bfe77c29d0442e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 7 Jan 2022 15:17:13 +0100 Subject: [PATCH 340/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20FastAPI=20Trove=20?= =?UTF-8?q?Classifier=20for=20PyPI=20(#4386)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index fa399c492..77c01322f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ classifiers = [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", + "Framework :: FastAPI", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3 :: Only", From 4da33e303148cbabeb96bb3e17cd236ef4402d33 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 7 Jan 2022 14:17:49 +0000 Subject: [PATCH 341/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f6e66d805..9453909be 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add FastAPI Trove Classifier for PyPI as now there's one 🤷😁. PR [#4386](https://github.com/tiangolo/fastapi/pull/4386) by [@tiangolo](https://github.com/tiangolo). * ✨ Add docs and tests for Python 3.9 and Python 3.10. PR [#3712](https://github.com/tiangolo/fastapi/pull/3712) by [@tiangolo](https://github.com/tiangolo). * ⬆ Upgrade MkDocs Material and configs. PR [#4385](https://github.com/tiangolo/fastapi/pull/4385) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade Starlette to 0.17.1. PR [#4145](https://github.com/tiangolo/fastapi/pull/4145) by [@simondale00](https://github.com/simondale00). From 44f4885c663f498c5902ba1a951d6e0e3d318fa1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Jan 2022 15:18:45 +0100 Subject: [PATCH 342/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#4354)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/people.yml | 98 ++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 45 deletions(-) diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 89c6f8dc3..df088f39f 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -6,8 +6,8 @@ maintainers: url: https://github.com/tiangolo experts: - login: Kludex - count: 315 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + count: 316 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 url: https://github.com/Kludex - login: dmontagu count: 262 @@ -34,7 +34,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik - login: raphaelauv - count: 63 + count: 67 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv - login: falkben @@ -45,6 +45,10 @@ experts: count: 48 avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 url: https://github.com/sm-Fifteen +- login: insomnes + count: 46 + avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 + url: https://github.com/insomnes - login: Dustyposa count: 42 avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 @@ -53,10 +57,6 @@ experts: count: 38 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 url: https://github.com/includeamin -- login: insomnes - count: 37 - avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 - url: https://github.com/insomnes - login: prostomarkeloff count: 33 avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4 @@ -78,7 +78,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 url: https://github.com/frankie567 - login: adriangb - count: 26 + count: 28 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 url: https://github.com/adriangb - login: ghandic @@ -97,6 +97,10 @@ experts: count: 24 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak +- login: panla + count: 23 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla - login: acnebs count: 22 avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4 @@ -109,10 +113,6 @@ experts: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 url: https://github.com/chris-allnutt -- login: panla - count: 21 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 - url: https://github.com/panla - login: retnikt count: 19 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 @@ -137,14 +137,14 @@ experts: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 url: https://github.com/acidjunk +- login: dstlny + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 + url: https://github.com/dstlny - login: haizaar count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar -- login: dstlny - count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 - url: https://github.com/dstlny - login: David-Lor count: 12 avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4 @@ -182,22 +182,30 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/2858306?u=1bb1182a5944e93624b7fb26585f22c8f7a9d76e&v=4 url: https://github.com/oligond last_month_active: +- login: insomnes + count: 10 + avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 + url: https://github.com/insomnes - login: raphaelauv count: 6 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv -- login: oligond - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/2858306?u=1bb1182a5944e93624b7fb26585f22c8f7a9d76e&v=4 - url: https://github.com/oligond +- login: jgould22 + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 + url: https://github.com/jgould22 +- login: harunyasar + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 + url: https://github.com/harunyasar - login: Kludex - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 - url: https://github.com/Kludex -- login: Dustyposa count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 - url: https://github.com/Dustyposa + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 + url: https://github.com/Kludex +- login: panla + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla top_contributors: - login: waynerv count: 25 @@ -237,7 +245,7 @@ top_contributors: url: https://github.com/RunningIkkyu - login: Kludex count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 url: https://github.com/Kludex - login: hard-coders count: 7 @@ -273,12 +281,12 @@ top_contributors: url: https://github.com/komtaki - login: NinaHwang count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=36ca24be1fc3daa967b0f409bab0e17132d8c80c&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 url: https://github.com/NinaHwang top_reviewers: - login: Kludex count: 91 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 url: https://github.com/Kludex - login: waynerv count: 47 @@ -364,6 +372,10 @@ top_reviewers: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4 url: https://github.com/sh0nk +- login: yezz123 + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 + url: https://github.com/yezz123 - login: mariacamilagl count: 10 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 @@ -376,10 +388,6 @@ top_reviewers: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4 url: https://github.com/maoyibo -- login: yezz123 - count: 9 - avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 - url: https://github.com/yezz123 - login: graingert count: 9 avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4 @@ -420,6 +428,10 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv +- login: BilalAlpaslan + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 + url: https://github.com/BilalAlpaslan - login: NastasiaSaby count: 7 avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4 @@ -436,10 +448,6 @@ top_reviewers: count: 6 avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 url: https://github.com/jovicon -- login: BilalAlpaslan - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 - url: https://github.com/BilalAlpaslan - login: diogoduartec count: 5 avatarUrl: https://avatars.githubusercontent.com/u/31852339?u=b50fc11c531e9b77922e19edfc9e7233d4d7b92e&v=4 @@ -448,6 +456,10 @@ top_reviewers: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4 url: https://github.com/nimctl +- login: israteneda + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/20668624?u=d7b2961d330aca65fbce5bdb26a0800a3d23ed2d&v=4 + url: https://github.com/israteneda - login: juntatalor count: 5 avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4 @@ -464,11 +476,7 @@ top_reviewers: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/83456692?v=4 url: https://github.com/oandersonmagalhaes -- login: euri10 - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4 - url: https://github.com/euri10 -- login: rkbeatss - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/23391143?u=56ab6bff50be950fa8cae5cf736f2ae66e319ff3&v=4 - url: https://github.com/rkbeatss +- login: qysfblog + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/52229895?v=4 + url: https://github.com/qysfblog From 66c27c3e0752b63bfe6e843dcf2af28d774caaa7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 7 Jan 2022 14:19:23 +0000 Subject: [PATCH 343/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9453909be..02e2c8879 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#4354](https://github.com/tiangolo/fastapi/pull/4354) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🔧 Add FastAPI Trove Classifier for PyPI as now there's one 🤷😁. PR [#4386](https://github.com/tiangolo/fastapi/pull/4386) by [@tiangolo](https://github.com/tiangolo). * ✨ Add docs and tests for Python 3.9 and Python 3.10. PR [#3712](https://github.com/tiangolo/fastapi/pull/3712) by [@tiangolo](https://github.com/tiangolo). * ⬆ Upgrade MkDocs Material and configs. PR [#4385](https://github.com/tiangolo/fastapi/pull/4385) by [@tiangolo](https://github.com/tiangolo). From 672c55ac626b20cc6219696023cdcc5871e5141d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 7 Jan 2022 18:07:59 +0100 Subject: [PATCH 344/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.71?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 14 ++++++++++++-- fastapi/__init__.py | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 02e2c8879..01df31267 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,11 +2,21 @@ ## Latest Changes +## 0.71.0 + +### Features + +* ✨ Add docs and tests for Python 3.9 and Python 3.10. PR [#3712](https://github.com/tiangolo/fastapi/pull/3712) by [@tiangolo](https://github.com/tiangolo). + * You can start with [Python Types Intro](https://fastapi.tiangolo.com/python-types/), it explains what changes between different Python versions, in Python 3.9 and in Python 3.10. + * All the FastAPI docs are updated. Each code example in the docs that could use different syntax in Python 3.9 or Python 3.10 now has all the alternatives in tabs. +* ⬆️ Upgrade Starlette to 0.17.1. PR [#4145](https://github.com/tiangolo/fastapi/pull/4145) by [@simondale00](https://github.com/simondale00). + +### Internal + * 👥 Update FastAPI People. PR [#4354](https://github.com/tiangolo/fastapi/pull/4354) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🔧 Add FastAPI Trove Classifier for PyPI as now there's one 🤷😁. PR [#4386](https://github.com/tiangolo/fastapi/pull/4386) by [@tiangolo](https://github.com/tiangolo). -* ✨ Add docs and tests for Python 3.9 and Python 3.10. PR [#3712](https://github.com/tiangolo/fastapi/pull/3712) by [@tiangolo](https://github.com/tiangolo). * ⬆ Upgrade MkDocs Material and configs. PR [#4385](https://github.com/tiangolo/fastapi/pull/4385) by [@tiangolo](https://github.com/tiangolo). -* ⬆️ Upgrade Starlette to 0.17.1. PR [#4145](https://github.com/tiangolo/fastapi/pull/4145) by [@simondale00](https://github.com/simondale00). + ## 0.70.1 There's nothing interesting in this particular FastAPI release. It is mainly to enable/unblock the release of the next version of Pydantic that comes packed with features and improvements. 🤩 diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 8bb6ce15b..5b735aed5 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.70.1" +__version__ = "0.71.0" from starlette import status as status From ca2b1dbb648b24ba776cf73f4dfa7026d5ff4a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 16 Jan 2022 15:34:45 +0100 Subject: [PATCH 345/814] =?UTF-8?q?=F0=9F=94=A7=20Enable=20MkDocs=20Materi?= =?UTF-8?q?al=20Insiders'=20`content.tabs.link`=20(#4399)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/az/mkdocs.yml | 1 + docs/de/mkdocs.yml | 1 + docs/en/mkdocs.yml | 1 + docs/es/mkdocs.yml | 1 + docs/fr/mkdocs.yml | 1 + docs/id/mkdocs.yml | 1 + docs/it/mkdocs.yml | 1 + docs/ja/mkdocs.yml | 1 + docs/ko/mkdocs.yml | 1 + docs/pl/mkdocs.yml | 1 + docs/pt/mkdocs.yml | 1 + docs/ru/mkdocs.yml | 1 + docs/sq/mkdocs.yml | 1 + docs/tr/mkdocs.yml | 1 + docs/uk/mkdocs.yml | 1 + docs/zh/mkdocs.yml | 1 + 16 files changed, 16 insertions(+) diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index dbff7b26a..66220f63e 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 8f29ef316..360fa8c4a 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index b3716f508..5bdd2c54a 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: img/icon-white.svg diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 06b015a1d..a4bc41154 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index c42f92b8a..ff16e1d78 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index 0dc34a14f..d70d2b3c3 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index 18afbd547..e6d01fbde 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 327fe862a..39fd8a211 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 5ffb71877..1d4d30913 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 724dc2725..3c1351a12 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index f36ecf49d..f202f306d 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index eb2597de7..6e17c287e 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index 5afe0a665..d9c3dad4c 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 40ba6d522..f6ed7f5b9 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index a116d90a3..d0de8cc0e 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 33d40129a..a929e3388 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -20,6 +20,7 @@ theme: features: - search.suggest - search.highlight + - content.tabs.link icon: repo: fontawesome/brands/github-alt logo: https://fastapi.tiangolo.com/img/icon-white.svg From b8ae84d460f331b8adc4d25b5b6f0bcb40baaac8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 16 Jan 2022 14:35:21 +0000 Subject: [PATCH 346/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 01df31267..5bf2302b2 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Enable MkDocs Material Insiders' `content.tabs.link`. PR [#4399](https://github.com/tiangolo/fastapi/pull/4399) by [@tiangolo](https://github.com/tiangolo). ## 0.71.0 ### Features From 7fe79441c1cb7cf3baecc271a3e9680006c8f2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 16 Jan 2022 15:44:08 +0100 Subject: [PATCH 347/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20Python=20Types?= =?UTF-8?q?=20docs,=20add=20missing=203.6=20/=203.9=20example=20(#4434)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/python-types.md | 2 +- docs_src/python_types/tutorial008.py | 5 ++++- docs_src/python_types/tutorial008_py39.py | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 docs_src/python_types/tutorial008_py39.py diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index 76d442855..fe56dadec 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -252,7 +252,7 @@ The second type parameter is for the values of the `dict`: === "Python 3.9 and above" ```Python hl_lines="1" - {!> ../../../docs_src/python_types/tutorial008.py!} + {!> ../../../docs_src/python_types/tutorial008_py39.py!} ``` This means: diff --git a/docs_src/python_types/tutorial008.py b/docs_src/python_types/tutorial008.py index a393385b0..9fb1043bb 100644 --- a/docs_src/python_types/tutorial008.py +++ b/docs_src/python_types/tutorial008.py @@ -1,4 +1,7 @@ -def process_items(prices: dict[str, float]): +from typing import Dict + + +def process_items(prices: Dict[str, float]): for item_name, item_price in prices.items(): print(item_name) print(item_price) diff --git a/docs_src/python_types/tutorial008_py39.py b/docs_src/python_types/tutorial008_py39.py new file mode 100644 index 000000000..a393385b0 --- /dev/null +++ b/docs_src/python_types/tutorial008_py39.py @@ -0,0 +1,4 @@ +def process_items(prices: dict[str, float]): + for item_name, item_price in prices.items(): + print(item_name) + print(item_price) From 9af8cc69d509cd8538bba3d481687d9f85cb52b4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 16 Jan 2022 14:44:43 +0000 Subject: [PATCH 348/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5bf2302b2..b33e9dcfc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update Python Types docs, add missing 3.6 / 3.9 example. PR [#4434](https://github.com/tiangolo/fastapi/pull/4434) by [@tiangolo](https://github.com/tiangolo). * 🔧 Enable MkDocs Material Insiders' `content.tabs.link`. PR [#4399](https://github.com/tiangolo/fastapi/pull/4399) by [@tiangolo](https://github.com/tiangolo). ## 0.71.0 From a85aa125d24acb225b7b722bb4f3e331a21ec267 Mon Sep 17 00:00:00 2001 From: John Riebold Date: Sun, 16 Jan 2022 11:26:24 -0800 Subject: [PATCH 349/814] =?UTF-8?q?=E2=9C=A8=20Enable=20configuring=20Swag?= =?UTF-8?q?ger=20UI=20parameters=20(#2568)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Artem Ivanov Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/extending-openapi.md | 79 ++++++++++++++++++ .../tutorial/extending-openapi/image02.png | Bin 0 -> 11292 bytes .../tutorial/extending-openapi/image03.png | Bin 0 -> 11176 bytes .../tutorial/extending-openapi/image04.png | Bin 0 -> 11180 bytes docs_src/extending_openapi/tutorial003.py | 8 ++ docs_src/extending_openapi/tutorial004.py | 8 ++ docs_src/extending_openapi/tutorial005.py | 8 ++ fastapi/applications.py | 3 + fastapi/openapi/docs.py | 22 +++-- .../test_tutorial003.py | 41 +++++++++ .../test_tutorial004.py | 44 ++++++++++ .../test_tutorial005.py | 44 ++++++++++ 12 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 docs/en/docs/img/tutorial/extending-openapi/image02.png create mode 100644 docs/en/docs/img/tutorial/extending-openapi/image03.png create mode 100644 docs/en/docs/img/tutorial/extending-openapi/image04.png create mode 100644 docs_src/extending_openapi/tutorial003.py create mode 100644 docs_src/extending_openapi/tutorial004.py create mode 100644 docs_src/extending_openapi/tutorial005.py create mode 100644 tests/test_tutorial/test_extending_openapi/test_tutorial003.py create mode 100644 tests/test_tutorial/test_extending_openapi/test_tutorial004.py create mode 100644 tests/test_tutorial/test_extending_openapi/test_tutorial005.py diff --git a/docs/en/docs/advanced/extending-openapi.md b/docs/en/docs/advanced/extending-openapi.md index d8d280ba6..d1b14bc00 100644 --- a/docs/en/docs/advanced/extending-openapi.md +++ b/docs/en/docs/advanced/extending-openapi.md @@ -233,3 +233,82 @@ Now, to be able to test that everything works, create a *path operation*: Now, you should be able to disconnect your WiFi, go to your docs at
http://127.0.0.1:8000/docs, and reload the page. And even without Internet, you would be able to see the docs for your API and interact with it. + +## Configuring Swagger UI + +You can configure some extra Swagger UI parameters. + +To configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function. + +`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly. + +FastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs. + +### Disable Syntax Highlighting + +For example, you could disable syntax highlighting in Swagger UI. + +Without changing the settings, syntax highlighting is enabled by default: + + + +But you can disable it by setting `syntaxHighlight` to `False`: + +```Python hl_lines="3" +{!../../../docs_src/extending_openapi/tutorial003.py!} +``` + +...and then Swagger UI won't show the syntax highlighting anymore: + + + +### Change the Theme + +The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle): + +```Python hl_lines="3" +{!../../../docs_src/extending_openapi/tutorial004.py!} +``` + +That configuration would change the syntax highlighting color theme: + + + +### Change Default Swagger UI Parameters + +FastAPI includes some default configuration parameters appropriate for most of the use cases. + +It includes these default configurations: + +```Python +{!../../../fastapi/openapi/docs.py[ln:7-13]!} +``` + +You can override any of them by setting a different value in the argument `swagger_ui_parameters`. + +For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`: + +```Python hl_lines="3" +{!../../../docs_src/extending_openapi/tutorial005.py!} +``` + +### Other Swagger UI Parameters + +To see all the other possible configurations you can use, read the official docs for Swagger UI parameters. + +### JavaScript-only settings + +Swagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions). + +FastAPI also includes these JavaScript-only `presets` settings: + +```JavaScript +presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIBundle.SwaggerUIStandalonePreset +] +``` + +These are **JavaScript** objects, not strings, so you can't pass them from Python code directly. + +If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need. diff --git a/docs/en/docs/img/tutorial/extending-openapi/image02.png b/docs/en/docs/img/tutorial/extending-openapi/image02.png new file mode 100644 index 0000000000000000000000000000000000000000..91453fb56f687b99fc725afa0a7fa07eb1955137 GIT binary patch literal 11292 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/extending-openapi/image04.png b/docs/en/docs/img/tutorial/extending-openapi/image04.png new file mode 100644 index 0000000000000000000000000000000000000000..394d2bb431ab5eadaa919087ce1618f996bd829e GIT binary patch literal 11180 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 None: self._debug: bool = debug @@ -120,6 +121,7 @@ class FastAPI(Starlette): self.redoc_url = redoc_url self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url self.swagger_ui_init_oauth = swagger_ui_init_oauth + self.swagger_ui_parameters = swagger_ui_parameters self.extra = extra self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {} @@ -174,6 +176,7 @@ class FastAPI(Starlette): title=self.title + " - Swagger UI", oauth2_redirect_url=oauth2_redirect_url, init_oauth=self.swagger_ui_init_oauth, + swagger_ui_parameters=self.swagger_ui_parameters, ) self.add_route(self.docs_url, swagger_ui_html, include_in_schema=False) diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py index fd22e4e8c..1be90d188 100644 --- a/fastapi/openapi/docs.py +++ b/fastapi/openapi/docs.py @@ -4,6 +4,14 @@ from typing import Any, Dict, Optional from fastapi.encoders import jsonable_encoder from starlette.responses import HTMLResponse +swagger_ui_default_parameters = { + "dom_id": "#swagger-ui", + "layout": "BaseLayout", + "deepLinking": True, + "showExtensions": True, + "showCommonExtensions": True, +} + def get_swagger_ui_html( *, @@ -14,7 +22,11 @@ def get_swagger_ui_html( swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png", oauth2_redirect_url: Optional[str] = None, init_oauth: Optional[Dict[str, Any]] = None, + swagger_ui_parameters: Optional[Dict[str, Any]] = None, ) -> HTMLResponse: + current_swagger_ui_parameters = swagger_ui_default_parameters.copy() + if swagger_ui_parameters: + current_swagger_ui_parameters.update(swagger_ui_parameters) html = f""" @@ -34,19 +46,17 @@ def get_swagger_ui_html( url: '{openapi_url}', """ + for key, value in current_swagger_ui_parameters.items(): + html += f"{json.dumps(key)}: {json.dumps(jsonable_encoder(value))},\n" + if oauth2_redirect_url: html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}'," html += """ - dom_id: '#swagger-ui', - presets: [ + presets: [ SwaggerUIBundle.presets.apis, SwaggerUIBundle.SwaggerUIStandalonePreset ], - layout: "BaseLayout", - deepLinking: true, - showExtensions: true, - showCommonExtensions: true })""" if init_oauth: diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial003.py b/tests/test_tutorial/test_extending_openapi/test_tutorial003.py new file mode 100644 index 000000000..0184dd9f8 --- /dev/null +++ b/tests/test_tutorial/test_extending_openapi/test_tutorial003.py @@ -0,0 +1,41 @@ +from fastapi.testclient import TestClient + +from docs_src.extending_openapi.tutorial003 import app + +client = TestClient(app) + + +def test_swagger_ui(): + response = client.get("/docs") + assert response.status_code == 200, response.text + assert ( + '"syntaxHighlight": false' in response.text + ), "syntaxHighlight should be included and converted to JSON" + assert ( + '"dom_id": "#swagger-ui"' in response.text + ), "default configs should be preserved" + assert "presets: [" in response.text, "default configs should be preserved" + assert ( + "SwaggerUIBundle.presets.apis," in response.text + ), "default configs should be preserved" + assert ( + "SwaggerUIBundle.SwaggerUIStandalonePreset" in response.text + ), "default configs should be preserved" + assert ( + '"layout": "BaseLayout",' in response.text + ), "default configs should be preserved" + assert ( + '"deepLinking": true,' in response.text + ), "default configs should be preserved" + assert ( + '"showExtensions": true,' in response.text + ), "default configs should be preserved" + assert ( + '"showCommonExtensions": true,' in response.text + ), "default configs should be preserved" + + +def test_get_users(): + response = client.get("/users/foo") + assert response.status_code == 200, response.text + assert response.json() == {"message": "Hello foo"} diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial004.py b/tests/test_tutorial/test_extending_openapi/test_tutorial004.py new file mode 100644 index 000000000..4f7615126 --- /dev/null +++ b/tests/test_tutorial/test_extending_openapi/test_tutorial004.py @@ -0,0 +1,44 @@ +from fastapi.testclient import TestClient + +from docs_src.extending_openapi.tutorial004 import app + +client = TestClient(app) + + +def test_swagger_ui(): + response = client.get("/docs") + assert response.status_code == 200, response.text + assert ( + '"syntaxHighlight": false' not in response.text + ), "not used parameters should not be included" + assert ( + '"syntaxHighlight.theme": "obsidian"' in response.text + ), "parameters with middle dots should be included in a JSON compatible way" + assert ( + '"dom_id": "#swagger-ui"' in response.text + ), "default configs should be preserved" + assert "presets: [" in response.text, "default configs should be preserved" + assert ( + "SwaggerUIBundle.presets.apis," in response.text + ), "default configs should be preserved" + assert ( + "SwaggerUIBundle.SwaggerUIStandalonePreset" in response.text + ), "default configs should be preserved" + assert ( + '"layout": "BaseLayout",' in response.text + ), "default configs should be preserved" + assert ( + '"deepLinking": true,' in response.text + ), "default configs should be preserved" + assert ( + '"showExtensions": true,' in response.text + ), "default configs should be preserved" + assert ( + '"showCommonExtensions": true,' in response.text + ), "default configs should be preserved" + + +def test_get_users(): + response = client.get("/users/foo") + assert response.status_code == 200, response.text + assert response.json() == {"message": "Hello foo"} diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial005.py b/tests/test_tutorial/test_extending_openapi/test_tutorial005.py new file mode 100644 index 000000000..24aeb93db --- /dev/null +++ b/tests/test_tutorial/test_extending_openapi/test_tutorial005.py @@ -0,0 +1,44 @@ +from fastapi.testclient import TestClient + +from docs_src.extending_openapi.tutorial005 import app + +client = TestClient(app) + + +def test_swagger_ui(): + response = client.get("/docs") + assert response.status_code == 200, response.text + assert ( + '"deepLinking": false,' in response.text + ), "overridden configs should be preserved" + assert ( + '"deepLinking": true' not in response.text + ), "overridden configs should not include the old value" + assert ( + '"syntaxHighlight": false' not in response.text + ), "not used parameters should not be included" + assert ( + '"dom_id": "#swagger-ui"' in response.text + ), "default configs should be preserved" + assert "presets: [" in response.text, "default configs should be preserved" + assert ( + "SwaggerUIBundle.presets.apis," in response.text + ), "default configs should be preserved" + assert ( + "SwaggerUIBundle.SwaggerUIStandalonePreset" in response.text + ), "default configs should be preserved" + assert ( + '"layout": "BaseLayout",' in response.text + ), "default configs should be preserved" + assert ( + '"showExtensions": true,' in response.text + ), "default configs should be preserved" + assert ( + '"showCommonExtensions": true,' in response.text + ), "default configs should be preserved" + + +def test_get_users(): + response = client.get("/users/foo") + assert response.status_code == 200, response.text + assert response.json() == {"message": "Hello foo"} From acbe79da371bc7e3673c86cafeb6d07ca64712f4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 16 Jan 2022 19:27:03 +0000 Subject: [PATCH 350/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b33e9dcfc..2ed9729d0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Enable configuring Swagger UI parameters. PR [#2568](https://github.com/tiangolo/fastapi/pull/2568) by [@jmriebold](https://github.com/jmriebold). * 📝 Update Python Types docs, add missing 3.6 / 3.9 example. PR [#4434](https://github.com/tiangolo/fastapi/pull/4434) by [@tiangolo](https://github.com/tiangolo). * 🔧 Enable MkDocs Material Insiders' `content.tabs.link`. PR [#4399](https://github.com/tiangolo/fastapi/pull/4399) by [@tiangolo](https://github.com/tiangolo). ## 0.71.0 From 5c62a59e7b99a49ce25c622747e510e211f22692 Mon Sep 17 00:00:00 2001 From: jaystone776 Date: Mon, 17 Jan 2022 03:34:28 +0800 Subject: [PATCH 351/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20`docs\tutorial\path-operation-configuration.md`=20(?= =?UTF-8?q?#3312)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../tutorial/path-operation-configuration.md | 101 ++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 102 insertions(+) create mode 100644 docs/zh/docs/tutorial/path-operation-configuration.md diff --git a/docs/zh/docs/tutorial/path-operation-configuration.md b/docs/zh/docs/tutorial/path-operation-configuration.md new file mode 100644 index 000000000..ad0e08d30 --- /dev/null +++ b/docs/zh/docs/tutorial/path-operation-configuration.md @@ -0,0 +1,101 @@ +# 路径操作配置 + +*路径操作装饰器*支持多种配置参数。 + +!!! warning "警告" + + 注意:以下参数应直接传递给**路径操作装饰器**,不能传递给*路径操作函数*。 + +## `status_code` 状态码 + +`status_code` 用于定义*路径操作*响应中的 HTTP 状态码。 + +可以直接传递 `int` 代码, 比如 `404`。 + +如果记不住数字码的涵义,也可以用 `status` 的快捷常量: + +```Python hl_lines="3 17" +{!../../../docs_src/path_operation_configuration/tutorial001.py!} +``` + +状态码在响应中使用,并会被添加到 OpenAPI 概图。 + +!!! note "技术细节" + + 也可以使用 `from starlette import status` 导入状态码。 + + **FastAPI** 的`fastapi.status` 和 `starlette.status` 一样,只是快捷方式。实际上,`fastapi.status` 直接继承自 Starlette。 + +## `tags` 参数 + +`tags` 参数的值是由 `str` 组成的 `list` (一般只有一个 `str` ),`tags` 用于为*路径操作*添加标签: + +```Python hl_lines="17 22 27" +{!../../../docs_src/path_operation_configuration/tutorial002.py!} +``` + +OpenAPI 概图会自动添加标签,供 API 文档接口使用: + + + +## `summary` 和 `description` 参数 + +路径装饰器还支持 `summary` 和 `description` 这两个参数: + +```Python hl_lines="20-21" +{!../../../docs_src/path_operation_configuration/tutorial003.py!} +``` + +## 文档字符串(`docstring`) + +描述内容比较长且占用多行时,可以在函数的 docstring 中声明*路径操作*的描述,**FastAPI** 支持从文档字符串中读取描述内容。 + +文档字符串支持 Markdown,能正确解析和显示 Markdown 的内容,但要注意文档字符串的缩进。 + +```Python hl_lines="19-27" +{!../../../docs_src/path_operation_configuration/tutorial004.py!} +``` + +下图为 Markdown 文本在 API 文档中的显示效果: + + + +## 响应描述 + +`response_description` 参数用于定义响应的描述说明: + +```Python hl_lines="21" +{!../../../docs_src/path_operation_configuration/tutorial005.py!} +``` + +!!! info "说明" + + 注意,`response_description` 只用于描述响应,`description` 一般则用于描述*路径操作*。 + +!!! check "检查" + + OpenAPI 规定每个*路径操作*都要有响应描述。 + + 如果没有定义响应描述,**FastAPI** 则自动生成内容为 "Successful response" 的响应描述。 + + + +## 弃用*路径操作* + +`deprecated` 参数可以把*路径操作*标记为弃用,无需直接删除: + +```Python hl_lines="16" +{!../../../docs_src/path_operation_configuration/tutorial006.py!} +``` + +API 文档会把该路径操作标记为弃用: + + + +下图显示了正常*路径操作*与弃用*路径操作* 的区别: + + + +## 小结 + +通过传递参数给*路径操作装饰器* ,即可轻松地配置*路径操作*、添加元数据。 diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index a929e3388..1d050fddd 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -78,6 +78,7 @@ nav: - tutorial/request-files.md - tutorial/request-forms-and-files.md - tutorial/handling-errors.md + - tutorial/path-operation-configuration.md - tutorial/body-updates.md - 依赖项: - tutorial/dependencies/index.md From 436261b3ea75a095efbf67c4d537baa588331301 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 16 Jan 2022 19:35:00 +0000 Subject: [PATCH 352/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2ed9729d0..9066792d8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for `docs\tutorial\path-operation-configuration.md`. PR [#3312](https://github.com/tiangolo/fastapi/pull/3312) by [@jaystone776](https://github.com/jaystone776). * ✨ Enable configuring Swagger UI parameters. PR [#2568](https://github.com/tiangolo/fastapi/pull/2568) by [@jmriebold](https://github.com/jmriebold). * 📝 Update Python Types docs, add missing 3.6 / 3.9 example. PR [#4434](https://github.com/tiangolo/fastapi/pull/4434) by [@tiangolo](https://github.com/tiangolo). * 🔧 Enable MkDocs Material Insiders' `content.tabs.link`. PR [#4399](https://github.com/tiangolo/fastapi/pull/4399) by [@tiangolo](https://github.com/tiangolo). From 5c5b889288f6330e2a64ab74c9bf50c95e829190 Mon Sep 17 00:00:00 2001 From: MicroPanda123 Date: Sun, 16 Jan 2022 19:36:42 +0000 Subject: [PATCH 353/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Polish=20translati?= =?UTF-8?q?on=20for=20`docs/pl/docs/index.md`=20(#4245)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dawid Dutkiewicz Co-authored-by: Dima Tisnek Co-authored-by: Bart Skowron Co-authored-by: Bart Skowron --- docs/pl/docs/index.md | 306 +++++++++++++++++++++--------------------- 1 file changed, 150 insertions(+), 156 deletions(-) diff --git a/docs/pl/docs/index.md b/docs/pl/docs/index.md index 95fb7ae21..4a300ae63 100644 --- a/docs/pl/docs/index.md +++ b/docs/pl/docs/index.md @@ -1,12 +1,8 @@ - -{!../../../docs/missing-translation.md!} - -

FastAPI

- FastAPI framework, high performance, easy to learn, fast to code, ready for production + FastAPI to szybki, prosty w nauce i gotowy do użycia w produkcji framework

@@ -22,29 +18,28 @@ --- -**Documentation**: https://fastapi.tiangolo.com +**Dokumentacja**: https://fastapi.tiangolo.com -**Source Code**: https://github.com/tiangolo/fastapi +**Kod żródłowy**: https://github.com/tiangolo/fastapi --- -FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. +FastAPI to nowoczesny, wydajny framework webowy do budowania API z użyciem Pythona 3.6+ bazujący na standardowym typowaniu Pythona. -The key features are: +Kluczowe cechy: -* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). +* **Wydajność**: FastAPI jest bardzo wydajny, na równi z **NodeJS** oraz **Go** (dzięki Starlette i Pydantic). [Jeden z najszybszych dostępnych frameworków Pythonowych](#wydajnosc). +* **Szybkość kodowania**: Przyśpiesza szybkość pisania nowych funkcjonalności o około 200% do 300%. * +* **Mniejsza ilość błędów**: Zmniejsza ilość ludzkich (dewelopera) błędy o około 40%. * +* **Intuicyjność**: Wspaniałe wsparcie dla edytorów kodu. Dostępne wszędzie automatyczne uzupełnianie kodu. Krótszy czas debugowania. +* **Łatwość**: Zaprojektowany by być prosty i łatwy do nauczenia. Mniej czasu spędzonego na czytanie dokumentacji. +* **Kompaktowość**: Minimalizacja powtarzającego się kodu. Wiele funkcjonalności dla każdej deklaracji parametru. Mniej błędów. +* **Solidność**: Kod gotowy dla środowiska produkcyjnego. Wraz z automatyczną interaktywną dokumentacją. +* **Bazujący na standardach**: Oparty na (i w pełni kompatybilny z) otwartych standardach API: OpenAPI (wcześniej znane jako Swagger) oraz JSON Schema. -* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * -* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * -* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. -* **Easy**: Designed to be easy to use and learn. Less time reading docs. -* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. -* **Robust**: Get production-ready code. With automatic interactive documentation. -* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. +* oszacowania bazowane na testach wykonanych przez wewnętrzny zespół deweloperów, budujących aplikacie używane na środowisku produkcyjnym. -* estimation based on tests on an internal development team, building production applications. - -## Sponsors +## Sponsorzy @@ -59,9 +54,9 @@ The key features are: -Other sponsors +Inni sponsorzy -## Opinions +## Opinie "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" @@ -101,24 +96,24 @@ The key features are: --- -## **Typer**, the FastAPI of CLIs +## **Typer**, FastAPI aplikacji konsolowych -If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. +Jeżeli tworzysz aplikacje CLI, która ma być używana w terminalu zamiast API, sprawdź **Typer**. -**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 +**Typer** to młodsze rodzeństwo FastAPI. Jego celem jest pozostanie **FastAPI aplikacji konsolowych** . ⌨️ 🚀 -## Requirements +## Wymagania Python 3.6+ -FastAPI stands on the shoulders of giants: +FastAPI oparty jest na: -* Starlette for the web parts. -* Pydantic for the data parts. +* Starlette dla części webowej. +* Pydantic dla części obsługujących dane. -## Installation +## Instalacja

@@ -130,7 +125,7 @@ $ pip install fastapi
-You will also need an ASGI server, for production such as Uvicorn or Hypercorn. +Na serwerze produkcyjnym będziesz także potrzebował serwera ASGI, np. Uvicorn lub Hypercorn.
@@ -142,11 +137,11 @@ $ pip install uvicorn[standard]
-## Example +## Przykład -### Create it +### Stwórz -* Create a file `main.py` with: +* Utwórz plik o nazwie `main.py` z: ```Python from typing import Optional @@ -167,9 +162,9 @@ def read_item(item_id: int, q: Optional[str] = None): ```
-Or use async def... +Albo użyj async def... -If your code uses `async` / `await`, use `async def`: +Jeżeli twój kod korzysta z `async` / `await`, użyj `async def`: ```Python hl_lines="9 14" from typing import Optional @@ -189,15 +184,15 @@ async def read_item(item_id: int, q: Optional[str] = None): return {"item_id": item_id, "q": q} ``` -**Note**: +**Przypis**: -If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. +Jeżeli nie znasz, sprawdź sekcję _"In a hurry?"_ o `async` i `await` w dokumentacji.
-### Run it +### Uruchom -Run the server with: +Uruchom serwer używając:
@@ -214,54 +209,53 @@ INFO: Application startup complete.
-About the command uvicorn main:app --reload... +O komendzie uvicorn main:app --reload... +Komenda `uvicorn main:app` odnosi się do: -The command `uvicorn main:app` refers to: - -* `main`: the file `main.py` (the Python "module"). -* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. -* `--reload`: make the server restart after code changes. Only do this for development. +* `main`: plik `main.py` ("moduł" w Pythonie). +* `app`: obiekt stworzony w `main.py` w lini `app = FastAPI()`. +* `--reload`: spraw by serwer resetował się po każdej zmianie w kodzie. Używaj tego tylko w środowisku deweloperskim.
-### Check it +### Wypróbuj -Open your browser at http://127.0.0.1:8000/items/5?q=somequery. +Otwórz link http://127.0.0.1:8000/items/5?q=somequery w przeglądarce. -You will see the JSON response as: +Zobaczysz następującą odpowiedź JSON: ```JSON {"item_id": 5, "q": "somequery"} ``` -You already created an API that: +Właśnie stworzyłeś API które: -* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. -* Both _paths_ take `GET` operations (also known as HTTP _methods_). -* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. -* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. +* Otrzymuje żądania HTTP w _ścieżce_ `/` i `/items/{item_id}`. +* Obie _ścieżki_ używają operacji `GET` (znane także jako _metody_ HTTP). +* _Ścieżka_ `/items/{item_id}` ma _parametr ścieżki_ `item_id` który powinien być obiektem typu `int`. +* _Ścieżka_ `/items/{item_id}` ma opcjonalny _parametr zapytania_ typu `str` o nazwie `q`. -### Interactive API docs +### Interaktywna dokumentacja API -Now go to http://127.0.0.1:8000/docs. +Otwórz teraz stronę http://127.0.0.1:8000/docs. -You will see the automatic interactive API documentation (provided by Swagger UI): +Zobaczysz automatyczną interaktywną dokumentację API (dostarczoną z pomocą Swagger UI): ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -### Alternative API docs +### Alternatywna dokumentacja API -And now, go to http://127.0.0.1:8000/redoc. +Otwórz teraz http://127.0.0.1:8000/redoc. -You will see the alternative automatic documentation (provided by ReDoc): +Zobaczysz alternatywną, lecz wciąż automatyczną dokumentację (wygenerowaną z pomocą ReDoc): ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## Example upgrade +## Aktualizacja przykładu -Now modify the file `main.py` to receive a body from a `PUT` request. +Zmodyfikuj teraz plik `main.py`, aby otrzmywał treść (body) żądania `PUT`. -Declare the body using standard Python types, thanks to Pydantic. +Zadeklaruj treść żądania, używając standardowych typów w Pythonie dzięki Pydantic. ```Python hl_lines="4 9-12 25-27" from typing import Optional @@ -293,175 +287,175 @@ def update_item(item_id: int, item: Item): return {"item_name": item.name, "item_id": item_id} ``` -The server should reload automatically (because you added `--reload` to the `uvicorn` command above). +Serwer powinien przeładować się automatycznie (ponieważ dodałeś `--reload` do komendy `uvicorn` powyżej). -### Interactive API docs upgrade +### Zaktualizowana interaktywna dokumentacja API -Now go to http://127.0.0.1:8000/docs. +Wejdź teraz na http://127.0.0.1:8000/docs. -* The interactive API documentation will be automatically updated, including the new body: +* Interaktywna dokumentacja API zaktualizuje sie automatycznie, także z nową treścią żądania (body): ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) -* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: +* Kliknij przycisk "Try it out" (wypróbuj), pozwoli Ci to wypełnić parametry i bezpośrednio użyć API: ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) -* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: +* Kliknij potem przycisk "Execute" (wykonaj), interfejs użytkownika połączy się z API, wyśle parametry, otrzyma odpowiedź i wyświetli ją na ekranie: ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) -### Alternative API docs upgrade +### Zaktualizowana alternatywna dokumentacja API -And now, go to http://127.0.0.1:8000/redoc. +Otwórz teraz http://127.0.0.1:8000/redoc. -* The alternative documentation will also reflect the new query parameter and body: +* Alternatywna dokumentacja również pokaże zaktualizowane parametry i treść żądania (body): ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) -### Recap +### Podsumowanie -In summary, you declare **once** the types of parameters, body, etc. as function parameters. +Podsumowując, musiałeś zadeklarować typy parametrów, treści żądania (body) itp. tylko **raz**, i są one dostępne jako parametry funkcji. -You do that with standard modern Python types. +Robisz to tak samo jak ze standardowymi typami w Pythonie. -You don't have to learn a new syntax, the methods or classes of a specific library, etc. +Nie musisz sie uczyć żadnej nowej składni, metod lub klas ze specyficznych bibliotek itp. -Just standard **Python 3.6+**. +Po prostu standardowy **Python 3.6+**. -For example, for an `int`: +Na przykład, dla danych typu `int`: ```Python item_id: int ``` -or for a more complex `Item` model: +albo dla bardziej złożonego obiektu `Item`: ```Python item: Item ``` -...and with that single declaration you get: +...i z pojedyńczą deklaracją otrzymujesz: -* Editor support, including: - * Completion. - * Type checks. -* Validation of data: - * Automatic and clear errors when the data is invalid. - * Validation even for deeply nested JSON objects. -* Conversion of input data: coming from the network to Python data and types. Reading from: +* Wsparcie edytorów kodu, wliczając: + * Auto-uzupełnianie. + * Sprawdzanie typów. +* Walidacja danych: + * Automatyczne i przejrzyste błędy gdy dane są niepoprawne. + * Walidacja nawet dla głęboko zagnieżdżonych obiektów JSON. +* Konwersja danych wejściowych: przychodzących z sieci na Pythonowe typy. Pozwala na przetwarzanie danych: * JSON. - * Path parameters. - * Query parameters. - * Cookies. - * Headers. - * Forms. - * Files. -* Conversion of output data: converting from Python data and types to network data (as JSON): - * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). - * `datetime` objects. - * `UUID` objects. - * Database models. - * ...and many more. -* Automatic interactive API documentation, including 2 alternative user interfaces: + * Parametrów ścieżki. + * Parametrów zapytania. + * Dane cookies. + * Dane nagłówków (headers). + * Formularze. + * Pliki. +* Konwersja danych wyjściowych: wychodzących z Pythona do sieci (jako JSON): + * Przetwarzanie Pythonowych typów (`str`, `int`, `float`, `bool`, `list`, itp). + * Obiekty `datetime`. + * Obiekty `UUID`. + * Modele baz danych. + * ...i wiele więcej. +* Automatyczne interaktywne dokumentacje API, wliczając 2 alternatywne interfejsy użytkownika: * Swagger UI. * ReDoc. --- -Coming back to the previous code example, **FastAPI** will: +Wracając do poprzedniego przykładu, **FastAPI** : -* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. -* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. - * If it is not, the client will see a useful, clear error. -* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. - * As the `q` parameter is declared with `= None`, it is optional. - * Without the `None` it would be required (as is the body in the case with `PUT`). -* For `PUT` requests to `/items/{item_id}`, Read the body as JSON: - * Check that it has a required attribute `name` that should be a `str`. - * Check that it has a required attribute `price` that has to be a `float`. - * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. - * All this would also work for deeply nested JSON objects. -* Convert from and to JSON automatically. -* Document everything with OpenAPI, that can be used by: - * Interactive documentation systems. - * Automatic client code generation systems, for many languages. -* Provide 2 interactive documentation web interfaces directly. +* Potwierdzi, że w ścieżce jest `item_id` dla żądań `GET` i `PUT`. +* Potwierdzi, że `item_id` jest typu `int` dla żądań `GET` i `PUT`. + * Jeżeli nie jest, odbiorca zobaczy przydatną, przejrzystą wiadomość z błędem. +* Sprawdzi czy w ścieżce jest opcjonalny parametr zapytania `q` (np. `http://127.0.0.1:8000/items/foo?q=somequery`) dla żądania `GET`. + * Jako że parametr `q` jest zadeklarowany jako `= None`, jest on opcjonalny. + * Gdyby tego `None` nie było, parametr ten byłby wymagany (tak jak treść żądania w żądaniu `PUT`). +* Dla żądania `PUT` z ścieżką `/items/{item_id}`, odczyta treść żądania jako JSON: + * Sprawdzi czy posiada wymagany atrybut `name`, który powinien być typu `str`. + * Sprawdzi czy posiada wymagany atrybut `price`, który musi być typu `float`. + * Sprawdzi czy posiada opcjonalny atrybut `is_offer`, który (jeżeli obecny) powinien być typu `bool`. + * To wszystko będzie również działać dla głęboko zagnieżdżonych obiektów JSON. +* Automatycznie konwertuje z i do JSON. +* Dokumentuje wszystko w OpenAPI, które może być używane przez: + * Interaktywne systemy dokumentacji. + * Systemy automatycznego generowania kodu klienckiego, dla wielu języków. +* Dostarczy bezpośrednio 2 interaktywne dokumentacje webowe. --- -We just scratched the surface, but you already get the idea of how it all works. +To dopiero początek, ale już masz mniej-więcej pojęcie jak to wszystko działa. -Try changing the line with: +Spróbuj zmienić linijkę: ```Python return {"item_name": item.name, "item_id": item_id} ``` -...from: +...z: ```Python ... "item_name": item.name ... ``` -...to: +...na: ```Python ... "item_price": item.price ... ``` -...and see how your editor will auto-complete the attributes and know their types: +...i zobacz jak edytor kodu automatycznie uzupełni atrybuty i będzie znał ich typy: ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) -For a more complete example including more features, see the Tutorial - User Guide. +Dla bardziej kompletnych przykładów posiadających więcej funkcjonalności, zobacz Tutorial - User Guide. -**Spoiler alert**: the tutorial - user guide includes: +**Uwaga Spoiler**: tutorial - user guide zawiera: -* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. -* How to set **validation constraints** as `maximum_length` or `regex`. -* A very powerful and easy to use **Dependency Injection** system. -* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. -* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). -* Many extra features (thanks to Starlette) as: - * **WebSockets** +* Deklaracje **parametrów** z innych miejsc takich jak: **nagłówki**, **pliki cookies**, **formularze** i **pliki**. +* Jak ustawić **ograniczenia walidacyjne** takie jak `maksymalna długość` lub `regex`. +* Potężny i łatwy w użyciu system **Dependency Injection**. +* Zabezpieczenia i autentykacja, wliczając wsparcie dla **OAuth2** z **tokenami JWT** oraz autoryzacją **HTTP Basic**. +* Bardziej zaawansowane (ale równie proste) techniki deklarowania **głęboko zagnieżdżonych modeli JSON** (dzięki Pydantic). +* Wiele dodatkowych funkcji (dzięki Starlette) takie jak: + * **WebSockety** * **GraphQL** - * extremely easy tests based on `requests` and `pytest` + * bardzo proste testy bazujące na `requests` oraz `pytest` * **CORS** - * **Cookie Sessions** - * ...and more. + * **Sesje cookie** + * ...i więcej. -## Performance +## Wydajność -Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) +Niezależne benchmarki TechEmpower pokazują, że **FastAPI** (uruchomiony na serwerze Uvicorn) jest jednym z najszybszych dostępnych Pythonowych frameworków, zaraz po Starlette i Uvicorn (używanymi wewnątrznie przez FastAPI). (*) -To understand more about it, see the section Benchmarks. +Aby dowiedzieć się o tym więcej, zobacz sekcję Benchmarks. -## Optional Dependencies +## Opcjonalne zależności -Used by Pydantic: +Używane przez Pydantic: -* ujson - for faster JSON "parsing". -* email_validator - for email validation. +* ujson - dla szybszego "parsowania" danych JSON. +* email_validator - dla walidacji adresów email. -Used by Starlette: +Używane przez Starlette: -* requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. -* jinja2 - Required if you want to use the default template configuration. -* python-multipart - Required if you want to support form "parsing", with `request.form()`. -* itsdangerous - Required for `SessionMiddleware` support. -* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). -* graphene - Required for `GraphQLApp` support. -* ujson - Required if you want to use `UJSONResponse`. +* requests - Wymagane jeżeli chcesz korzystać z `TestClient`. +* aiofiles - Wymagane jeżeli chcesz korzystać z `FileResponse` albo `StaticFiles`. +* jinja2 - Wymagane jeżeli chcesz używać domyślnej konfiguracji szablonów. +* python-multipart - Wymagane jeżelich chcesz wsparcie "parsowania" formularzy, używając `request.form()`. +* itsdangerous - Wymagany dla wsparcia `SessionMiddleware`. +* pyyaml - Wymagane dla wsparcia `SchemaGenerator` z Starlette (z FastAPI prawdopodobnie tego nie potrzebujesz). +* graphene - Wymagane dla wsparcia `GraphQLApp`. +* ujson - Wymagane jeżeli chcesz korzystać z `UJSONResponse`. -Used by FastAPI / Starlette: +Używane przez FastAPI / Starlette: -* uvicorn - for the server that loads and serves your application. -* orjson - Required if you want to use `ORJSONResponse`. +* uvicorn - jako serwer, który ładuje i obsługuje Twoją aplikację. +* orjson - Wymagane jeżeli chcesz używać `ORJSONResponse`. -You can install all of these with `pip install fastapi[all]`. +Możesz zainstalować wszystkie te aplikacje przy pomocy `pip install fastapi[all]`. -## License +## Licencja -This project is licensed under the terms of the MIT license. +Ten projekt jest na licencji MIT. From 24968937e5a788fd15f801c705da9afba35c2517 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 16 Jan 2022 19:37:21 +0000 Subject: [PATCH 354/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9066792d8..658fd4255 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Polish translation for `docs/pl/docs/index.md`. PR [#4245](https://github.com/tiangolo/fastapi/pull/4245) by [@MicroPanda123](https://github.com/MicroPanda123). * 🌐 Add Chinese translation for `docs\tutorial\path-operation-configuration.md`. PR [#3312](https://github.com/tiangolo/fastapi/pull/3312) by [@jaystone776](https://github.com/jaystone776). * ✨ Enable configuring Swagger UI parameters. PR [#2568](https://github.com/tiangolo/fastapi/pull/2568) by [@jmriebold](https://github.com/jmriebold). * 📝 Update Python Types docs, add missing 3.6 / 3.9 example. PR [#4434](https://github.com/tiangolo/fastapi/pull/4434) by [@tiangolo](https://github.com/tiangolo). From 26e94116c12f46035ea3f4949c74d566aaa89116 Mon Sep 17 00:00:00 2001 From: kty4119 <49435654+kty4119@users.noreply.github.com> Date: Mon, 17 Jan 2022 04:41:13 +0900 Subject: [PATCH 355/814] =?UTF-8?q?=F0=9F=8C=90=20Fix=20Korean=20translati?= =?UTF-8?q?on=20for=20`docs/ko/docs/index.md`=20(#4195)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/ko/docs/index.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md index ee3edded6..d0c236906 100644 --- a/docs/ko/docs/index.md +++ b/docs/ko/docs/index.md @@ -35,7 +35,7 @@ FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트 * **직관적**: 훌륭한 편집기 지원. 모든 곳에서 자동완성. 적은 디버깅 시간. * **쉬움**: 쉽게 사용하고 배우도록 설계. 적은 문서 읽기 시간. * **짧음**: 코드 중복 최소화. 각 매개변수 선언의 여러 기능. 적은 버그. -* **견고함**: 준비된 프로덕션 용 코드를 얻으세요. 자동 대화형 문서와 함께. +* **견고함**: 준비된 프로덕션 용 코드를 얻으십시오. 자동 대화형 문서와 함께. * **표준 기반**: API에 대한 (완전히 호환되는) 개방형 표준 기반: OpenAPI (이전에 Swagger로 알려졌던) 및 JSON 스키마. * 내부 개발팀의 프로덕션 애플리케이션을 빌드한 테스트에 근거한 측정 @@ -89,9 +89,9 @@ FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트 --- -"_REST API를 만들기 위해 **현대적인 프레임워크**를 찾고 있다면 **FastAPI**를 확인해 보세요. [...] 빠르고, 쓰기 쉽고, 배우기도 쉽습니다 [...]_" +"_REST API를 만들기 위해 **현대적인 프레임워크**를 찾고 있다면 **FastAPI**를 확인해 보십시오. [...] 빠르고, 쓰기 쉽고, 배우기도 쉽습니다 [...]_" -"_우리 **API**를 **FastAPI**로 바꿨습니다 [...] 아마 여러분도 좋아하실 겁니다 [...]_" +"_우리 **API**를 **FastAPI**로 바꿨습니다 [...] 아마 여러분도 좋아하실 것입니다 [...]_"
Ines Montani - Matthew Honnibal - Explosion AI 설립자 - spaCy 제작자 (ref) - (ref)
@@ -193,7 +193,7 @@ async def read_item(item_id: int, q: Optional[str] = None): ### 실행하기 -서버를 실행하세요: +서버를 실행하십시오:
@@ -239,7 +239,7 @@ INFO: Application startup complete. ### 대화형 API 문서 -이제 http://127.0.0.1:8000/docs로 가보세요. +이제 http://127.0.0.1:8000/docs로 가보십시오. 자동 대화형 API 문서를 볼 수 있습니다 (Swagger UI 제공): @@ -388,7 +388,7 @@ item: Item 우리는 그저 수박 겉핡기만 했을 뿐인데 여러분은 벌써 어떻게 작동하는지 알고 있습니다. -다음 줄을 바꿔보세요: +다음 줄을 바꿔보십시오: ```Python return {"item_name": item.name, "item_id": item_id} @@ -447,7 +447,7 @@ Starlette이 사용하는: * jinja2 - 기본 템플릿 설정을 사용하려면 필요. * python-multipart - `request.form()`과 함께 "parsing"의 지원을 원하면 필요. * itsdangerous - `SessionMiddleware` 지원을 위해 필요. -* pyyaml - Starlette의 `SchemaGenerator` 지원을 위해 필요 (FastAPI와 쓸때는 필요가 없을 겁니다). +* pyyaml - Starlette의 `SchemaGenerator` 지원을 위해 필요 (FastAPI와 쓸때는 필요 없을 것입니다). * graphene - `GraphQLApp` 지원을 위해 필요. * ujson - `UJSONResponse`를 사용하려면 필요. From d23b295b96ca9a4c9ebef381a111de4435acd222 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 16 Jan 2022 19:41:49 +0000 Subject: [PATCH 356/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 658fd4255..15602b1e8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix Korean translation for `docs/ko/docs/index.md`. PR [#4195](https://github.com/tiangolo/fastapi/pull/4195) by [@kty4119](https://github.com/kty4119). * 🌐 Add Polish translation for `docs/pl/docs/index.md`. PR [#4245](https://github.com/tiangolo/fastapi/pull/4245) by [@MicroPanda123](https://github.com/MicroPanda123). * 🌐 Add Chinese translation for `docs\tutorial\path-operation-configuration.md`. PR [#3312](https://github.com/tiangolo/fastapi/pull/3312) by [@jaystone776](https://github.com/jaystone776). * ✨ Enable configuring Swagger UI parameters. PR [#2568](https://github.com/tiangolo/fastapi/pull/2568) by [@jmriebold](https://github.com/jmriebold). From e1c6d7d31083e3c637c352d36b7d9f8d93508b15 Mon Sep 17 00:00:00 2001 From: jaystone776 Date: Mon, 17 Jan 2022 03:41:59 +0800 Subject: [PATCH 357/814] =?UTF-8?q?=F0=9F=8C=90=20Update=20Chinese=20trans?= =?UTF-8?q?lation=20for=20`docs/help-fastapi.md`=20(#3847)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zh/docs/help-fastapi.md | 164 ++++++++++++++++++++++------------- 1 file changed, 103 insertions(+), 61 deletions(-) diff --git a/docs/zh/docs/help-fastapi.md b/docs/zh/docs/help-fastapi.md index 99e37b7c1..6f3f5159b 100644 --- a/docs/zh/docs/help-fastapi.md +++ b/docs/zh/docs/help-fastapi.md @@ -1,107 +1,149 @@ -# 帮助 FastAPI - 获取帮助 +# 帮助 FastAPI 与求助 -你喜欢 **FastAPI** 吗? +您喜欢 **FastAPI** 吗? -您愿意去帮助 FastAPI,帮助其他用户以及作者吗? +想帮助 FastAPI?其它用户?还有项目作者? -或者你想要获得有关 **FastAPI** 的帮助? +或要求助怎么使用 **FastAPI**? -下面是一些非常简单的方式去提供帮助(有些只需单击一两次链接)。 +以下几种帮助的方式都非常简单(有些只需要点击一两下鼠标)。 -以及几种获取帮助的途径。 +求助的渠道也很多。 -## 在 GitHub 上 Star **FastAPI** +## 订阅新闻邮件 -你可以在 GitHub 上 "star" FastAPI(点击右上角的 star 按钮):https://github.com/tiangolo/fastapi。 +您可以订阅 [**FastAPI 和它的小伙伴** 新闻邮件](/newsletter/){.internal-link target=_blank}(不会经常收到) -通过添加 star,其他用户将会更容易发现 FastAPI,并了解已经有许多人认为它有用。 +* FastAPI 及其小伙伴的新闻 🚀 +* 指南 📝 +* 功能 ✨ +* 破坏性更改 🚨 +* 开发技巧 ✅ -## Watch GitHub 仓库的版本发布 +## 在推特上关注 FastAPI -你可以在 GitHub 上 "watch" FastAPI(点击右上角的 watch 按钮):https://github.com/tiangolo/fastapi。 +在 **Twitter** 上关注 @fastapi 获取 **FastAPI** 的最新消息。🐦 -这时你可以选择 "Releases only" 选项。 +## 在 GitHub 上为 **FastAPI** 加星 -之后,只要有 **FastAPI** 的新版本(包含缺陷修复和新功能)发布,你都会(通过电子邮件)收到通知。 +您可以在 GitHub 上 **Star** FastAPI(只要点击右上角的星星就可以了): https://github.com/tiangolo/fastapi。⭐️ -## 加入聊天室 +**Star** 以后,其它用户就能更容易找到 FastAPI,并了解到已经有其他用户在使用它了。 -加入 Gitter 上的聊天室:https://gitter.im/tiangolo/fastapi。 +## 关注 GitHub 资源库的版本发布 -在这里你可以快速提问、帮助他人、分享想法等。 +您还可以在 GitHub 上 **Watch** FastAPI,(点击右上角的 **Watch** 按钮)https://github.com/tiangolo/fastapi。👀 -## 与作者联系 +您可以选择只关注发布(**Releases only**)。 -你可以联系 我 (Sebastián Ramírez / `tiangolo`) - FastAPI 的作者。 +这样,您就可以(在电子邮件里)接收到 **FastAPI** 新版发布的通知,及时了解 bug 修复与新功能。 -你可以: +## 联系作者 -* 在 **GitHub** 上关注我。 - * 查看我创建的其他的可能对你有帮助的开源项目。 - * 关注我以了解我创建的新开源项目。 -* 在 **Twitter** 上关注我。 - * 告诉我你是如何使用 FastAPI 的(我很乐意听到)。 - * 提出问题。 -* 在 **Linkedin** 上联系我。 - * 与我交流。 - * 认可我的技能或推荐我 :) -* 在 **Medium** 上阅读我写的文章(或关注我)。 - * 阅读我创建的其他想法,文章和工具。 - * 关注我以了解我发布的新内容。 +您可以联系项目作者,就是我(Sebastián Ramírez / `tiangolo`)。 -## 发布和 **FastAPI** 有关的推特 +您可以: - 发布和 **FastAPI** 有关的推特 让我和其他人知道你为什么喜欢它。 +* 在 **GitHub** 上关注我 + * 了解其它我创建的开源项目,或许对您会有帮助 + * 关注我什么时候创建新的开源项目 +* 在 **Twitter** 上关注我 + * 告诉我您使用 FastAPI(我非常乐意听到这种消息) + * 接收我发布公告或新工具的消息 + * 您还可以关注@fastapi on Twitter,这是个独立的账号 +* 在**领英**上联系我 + * 接收我发布公告或新工具的消息(虽然我用 Twitter 比较多) +* 阅读我在 **Dev.to****Medium** 上的文章,或关注我 + * 阅读我的其它想法、文章,了解我创建的工具 + * 关注我,这样就可以随时看到我发布的新文章 -## 告诉我你正在如何使用 **FastAPI** +## Tweet about **FastAPI** -我很乐意听到有关 **FastAPI** 被如何使用、你喜欢它的哪一点、被投入使用的项目/公司等等信息。 +Tweet about **FastAPI** 让我和大家知道您为什么喜欢 FastAPI。🎉 -你可以通过以下平台让我知道: - -* **Twitter**。 -* **Linkedin**。 -* **Medium**。 +知道有人使用 **FastAPI**,我会很开心,我也想知道您为什么喜欢 FastAPI,以及您在什么项目/哪些公司使用 FastAPI,等等。 ## 为 FastAPI 投票 -* 在 Slant 上为 **FastAPI** 投票。 +* 在 Slant 上为 **FastAPI** 投票 +* 在 AlternativeTo 上为 **FastAPI** 投票 -## 帮助他人解决 GitHub 的 issues +## 在 GitHub 上帮助其他人解决问题 -你可以查看 已有的 issues 并尝试帮助其他人。 +您可以查看现有 issues,并尝试帮助其他人解决问题,说不定您能解决这些问题呢。🤓 -## Watch GitHub 仓库 +如果帮助很多人解决了问题,您就有可能成为 [FastAPI 的官方专家](fastapi-people.md#experts){.internal-link target=_blank}。🎉 -你可以在 GitHub 上 "watch" FastAPI(点击右上角的 "watch" 按钮):https://github.com/tiangolo/fastapi。 +## 监听 GitHub 资源库 -如果你选择的是 "Watching" 而不是 "Releases only" 选项,你会在其他人创建了新的 issue 时收到通知。 +您可以在 GitHub 上「监听」FastAPI(点击右上角的 "watch" 按钮): https://github.com/tiangolo/fastapi. 👀 -然后你可以尝试帮助他们解决这些 issue。 +如果您选择 "Watching" 而不是 "Releases only",有人创建新 Issue 时,您会接收到通知。 -## 创建 issue +然后您就可以尝试并帮助他们解决问题。 -你可以在 GitHub 仓库中 创建一个新 issue 用来: +## 创建 Issue -* 报告 bug 或问题。 -* 提议新的特性。 -* 提问。 +您可以在 GitHub 资源库中创建 Issue,例如: -## 创建 Pull Request +* 提出**问题**或**意见** +* 提出新**特性**建议 -你可以 创建一个 Pull Request 用来: +**注意**:如果您创建 Issue,我会要求您也要帮助别的用户。😉 -* 纠正你在文档中发现的错别字。 -* 添加新的文档内容。 -* 修复已有的 bug 或问题。 -* 添加新的特性。 +## 创建 PR + +您可以创建 PR 为源代码做[贡献](contributing.md){.internal-link target=_blank},例如: + +* 修改文档错别字 +* 编辑这个文件,分享 FastAPI 的文章、视频、博客,不论是您自己的,还是您看到的都成 + * 注意,添加的链接要放在对应区块的开头 +* [翻译文档](contributing.md#translations){.internal-link target=_blank} + * 审阅别人翻译的文档 +* 添加新的文档内容 +* 修复现有问题/Bug +* 添加新功能 + +## 加入聊天 + +快加入 👥 Discord 聊天服务器 👥 和 FastAPI 社区里的小伙伴一起哈皮吧。 + +!!! tip "提示" + + 如有问题,请在 GitHub Issues 里提问,在这里更容易得到 [FastAPI 专家](fastapi-people.md#experts){.internal-link target=_blank}的帮助。 + + 聊天室仅供闲聊。 + +我们之前还使用过 Gitter chat,但它不支持频道等高级功能,聊天也比较麻烦,所以现在推荐使用 Discord。 + +### 别在聊天室里提问 + +注意,聊天室更倾向于“闲聊”,经常有人会提出一些笼统得让人难以回答的问题,所以在这里提问一般没人回答。 + +GitHub Issues 里提供了模板,指引您提出正确的问题,有利于获得优质的回答,甚至可能解决您还没有想到的问题。而且就算答疑解惑要耗费不少时间,我还是会尽量在 GitHub 里回答问题。但在聊天室里,我就没功夫这么做了。😅 + +聊天室里的聊天内容也不如 GitHub 里好搜索,聊天里的问答很容易就找不到了。只有在 GitHub Issues 里的问答才能帮助您成为 [FastAPI 专家](fastapi-people.md#experts){.internal-link target=_blank},在 GitHub Issues 中为您带来更多关注。 + +另一方面,聊天室里有成千上万的用户,在这里,您有很大可能遇到聊得来的人。😄 ## 赞助作者 -你还可以通过 GitHub sponsors 在经济上支持作者(我)。 +您还可以通过 GitHub 赞助商资助本项目的作者(就是我)。 -这样你可以给我买杯咖啡☕️以示谢意😄。 +给我买杯咖啡 ☕️ 以示感谢 😄 + +当然您也可以成为 FastAPI 的金牌或银牌赞助商。🏅🎉 + +## 赞助 FastAPI 使用的工具 + +如您在本文档中所见,FastAPI 站在巨人的肩膀上,它们分别是 Starlette 和 Pydantic。 + +您还可以赞助: + +* Samuel Colvin (Pydantic) +* Encode (Starlette, Uvicorn) --- -感谢! +谢谢!🚀 + From 93e4a19e3526369b2a9a0c5ef71101833faa2987 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 16 Jan 2022 19:42:33 +0000 Subject: [PATCH 358/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 15602b1e8..6ce21a8af 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Update Chinese translation for `docs/help-fastapi.md`. PR [#3847](https://github.com/tiangolo/fastapi/pull/3847) by [@jaystone776](https://github.com/jaystone776). * 🌐 Fix Korean translation for `docs/ko/docs/index.md`. PR [#4195](https://github.com/tiangolo/fastapi/pull/4195) by [@kty4119](https://github.com/kty4119). * 🌐 Add Polish translation for `docs/pl/docs/index.md`. PR [#4245](https://github.com/tiangolo/fastapi/pull/4245) by [@MicroPanda123](https://github.com/MicroPanda123). * 🌐 Add Chinese translation for `docs\tutorial\path-operation-configuration.md`. PR [#3312](https://github.com/tiangolo/fastapi/pull/3312) by [@jaystone776](https://github.com/jaystone776). From 9e2f5c67b603d73a77c420b629e2ee4e7378de1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 16 Jan 2022 21:08:04 +0100 Subject: [PATCH 359/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6ce21a8af..090a344a6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,13 +2,25 @@ ## Latest Changes +### Features + +* ✨ Enable configuring Swagger UI parameters. Original PR [#2568](https://github.com/tiangolo/fastapi/pull/2568) by [@jmriebold](https://github.com/jmriebold). Here are the new docs: [Configuring Swagger UI](https://fastapi.tiangolo.com/advanced/extending-openapi/#configuring-swagger-ui). + +### Docs + +* 📝 Update Python Types docs, add missing 3.6 / 3.9 example. PR [#4434](https://github.com/tiangolo/fastapi/pull/4434) by [@tiangolo](https://github.com/tiangolo). + +### Translations + * 🌐 Update Chinese translation for `docs/help-fastapi.md`. PR [#3847](https://github.com/tiangolo/fastapi/pull/3847) by [@jaystone776](https://github.com/jaystone776). * 🌐 Fix Korean translation for `docs/ko/docs/index.md`. PR [#4195](https://github.com/tiangolo/fastapi/pull/4195) by [@kty4119](https://github.com/kty4119). * 🌐 Add Polish translation for `docs/pl/docs/index.md`. PR [#4245](https://github.com/tiangolo/fastapi/pull/4245) by [@MicroPanda123](https://github.com/MicroPanda123). * 🌐 Add Chinese translation for `docs\tutorial\path-operation-configuration.md`. PR [#3312](https://github.com/tiangolo/fastapi/pull/3312) by [@jaystone776](https://github.com/jaystone776). -* ✨ Enable configuring Swagger UI parameters. PR [#2568](https://github.com/tiangolo/fastapi/pull/2568) by [@jmriebold](https://github.com/jmriebold). -* 📝 Update Python Types docs, add missing 3.6 / 3.9 example. PR [#4434](https://github.com/tiangolo/fastapi/pull/4434) by [@tiangolo](https://github.com/tiangolo). + +### Internal + * 🔧 Enable MkDocs Material Insiders' `content.tabs.link`. PR [#4399](https://github.com/tiangolo/fastapi/pull/4399) by [@tiangolo](https://github.com/tiangolo). + ## 0.71.0 ### Features From f0388915a8b1cd9f3ae2259bace234ac6249c51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 16 Jan 2022 21:09:10 +0100 Subject: [PATCH 360/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.72?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 090a344a6..2dfb47c12 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.72.0 + ### Features * ✨ Enable configuring Swagger UI parameters. Original PR [#2568](https://github.com/tiangolo/fastapi/pull/2568) by [@jmriebold](https://github.com/jmriebold). Here are the new docs: [Configuring Swagger UI](https://fastapi.tiangolo.com/advanced/extending-openapi/#configuring-swagger-ui). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 5b735aed5..d83fe6fbd 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.71.0" +__version__ = "0.72.0" from starlette import status as status From a75d0801241dc59590d928c48da7665856a52963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 23 Jan 2022 15:56:14 +0100 Subject: [PATCH 361/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20sponsor=20Dropbase?= =?UTF-8?q?=20(#4465)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/en/data/sponsors.yml | 3 + docs/en/data/sponsors_badge.yml | 1 + docs/en/docs/img/sponsors/dropbase-banner.svg | 117 +++++++++++++++++ docs/en/docs/img/sponsors/dropbase.svg | 124 ++++++++++++++++++ docs/en/overrides/main.html | 6 + 6 files changed, 252 insertions(+) create mode 100644 docs/en/docs/img/sponsors/dropbase-banner.svg create mode 100644 docs/en/docs/img/sponsors/dropbase.svg diff --git a/README.md b/README.md index 53de38bd9..c9c69d3e8 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index baa2e440d..b98e68b65 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -5,6 +5,9 @@ gold: - url: https://cryptapi.io/ title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway." img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg + - url: https://www.dropbase.io/careers + title: Dropbase - seamlessly collect, clean, and centralize data. + img: https://fastapi.tiangolo.com/img/sponsors/dropbase.svg silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index 759748728..0c4e716d7 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -7,3 +7,4 @@ logins: - koaning - deepset-ai - cryptapi + - DropbaseHQ diff --git a/docs/en/docs/img/sponsors/dropbase-banner.svg b/docs/en/docs/img/sponsors/dropbase-banner.svg new file mode 100644 index 000000000..d65abf1d9 --- /dev/null +++ b/docs/en/docs/img/sponsors/dropbase-banner.svg @@ -0,0 +1,117 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/docs/img/sponsors/dropbase.svg b/docs/en/docs/img/sponsors/dropbase.svg new file mode 100644 index 000000000..d0defb4df --- /dev/null +++ b/docs/en/docs/img/sponsors/dropbase.svg @@ -0,0 +1,124 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 70b0253bd..0f452b515 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -46,6 +46,12 @@
+
{% endblock %} From 347e391271e09244c3d95ac46dd5493a9b472ee4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 23 Jan 2022 14:56:44 +0000 Subject: [PATCH 362/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2dfb47c12..41fa8493e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add sponsor Dropbase. PR [#4465](https://github.com/tiangolo/fastapi/pull/4465) by [@tiangolo](https://github.com/tiangolo). ## 0.72.0 From ca5d57ea799028d771101bd711ca87a301dd45d8 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 23 Jan 2022 23:54:59 +0800 Subject: [PATCH 363/814] =?UTF-8?q?=E2=9C=A8=20Allow=20hiding=20from=20Ope?= =?UTF-8?q?nAPI=20(and=20Swagger=20UI)=20`Query`,=20`Cookie`,=20`Header`,?= =?UTF-8?q?=20and=20`Path`=20parameters=20(#3144)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../tutorial/query-params-str-validations.md | 16 ++ .../tutorial014.py | 15 ++ .../tutorial014_py310.py | 11 + fastapi/openapi/utils.py | 2 + fastapi/param_functions.py | 8 + fastapi/params.py | 10 + tests/test_param_include_in_schema.py | 239 ++++++++++++++++++ .../test_tutorial014.py | 82 ++++++ .../test_tutorial014_py310.py | 91 +++++++ 9 files changed, 474 insertions(+) create mode 100644 docs_src/query_params_str_validations/tutorial014.py create mode 100644 docs_src/query_params_str_validations/tutorial014_py310.py create mode 100644 tests/test_param_include_in_schema.py create mode 100644 tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py create mode 100644 tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py diff --git a/docs/en/docs/tutorial/query-params-str-validations.md b/docs/en/docs/tutorial/query-params-str-validations.md index fcac1a4e0..ee62b9718 100644 --- a/docs/en/docs/tutorial/query-params-str-validations.md +++ b/docs/en/docs/tutorial/query-params-str-validations.md @@ -387,6 +387,22 @@ The docs will show it like this: +## Exclude from OpenAPI + +To exclude a query parameter from the generated OpenAPI schema (and thus, from the automatic documentation systems), set the parameter `include_in_schema` of `Query` to `False`: + +=== "Python 3.6 and above" + + ```Python hl_lines="10" + {!> ../../../docs_src/query_params_str_validations/tutorial014.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!} + ``` + ## Recap You can declare additional validations and metadata for your parameters. diff --git a/docs_src/query_params_str_validations/tutorial014.py b/docs_src/query_params_str_validations/tutorial014.py new file mode 100644 index 000000000..fb50bc27b --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial014.py @@ -0,0 +1,15 @@ +from typing import Optional + +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items( + hidden_query: Optional[str] = Query(None, include_in_schema=False) +): + if hidden_query: + return {"hidden_query": hidden_query} + else: + return {"hidden_query": "Not found"} diff --git a/docs_src/query_params_str_validations/tutorial014_py310.py b/docs_src/query_params_str_validations/tutorial014_py310.py new file mode 100644 index 000000000..7ae39c7f9 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial014_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(hidden_query: str | None = Query(None, include_in_schema=False)): + if hidden_query: + return {"hidden_query": hidden_query} + else: + return {"hidden_query": "Not found"} diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 0e73e21bf..aff76b15e 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -92,6 +92,8 @@ def get_openapi_operation_parameters( for param in all_route_params: field_info = param.field_info field_info = cast(Param, field_info) + if not field_info.include_in_schema: + continue parameter = { "name": param.alias, "in": field_info.in_.value, diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py index ff65d7271..a553a1461 100644 --- a/fastapi/param_functions.py +++ b/fastapi/param_functions.py @@ -20,6 +20,7 @@ def Path( # noqa: N802 example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, + include_in_schema: bool = True, **extra: Any, ) -> Any: return params.Path( @@ -37,6 +38,7 @@ def Path( # noqa: N802 example=example, examples=examples, deprecated=deprecated, + include_in_schema=include_in_schema, **extra, ) @@ -57,6 +59,7 @@ def Query( # noqa: N802 example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, + include_in_schema: bool = True, **extra: Any, ) -> Any: return params.Query( @@ -74,6 +77,7 @@ def Query( # noqa: N802 example=example, examples=examples, deprecated=deprecated, + include_in_schema=include_in_schema, **extra, ) @@ -95,6 +99,7 @@ def Header( # noqa: N802 example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, + include_in_schema: bool = True, **extra: Any, ) -> Any: return params.Header( @@ -113,6 +118,7 @@ def Header( # noqa: N802 example=example, examples=examples, deprecated=deprecated, + include_in_schema=include_in_schema, **extra, ) @@ -133,6 +139,7 @@ def Cookie( # noqa: N802 example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, + include_in_schema: bool = True, **extra: Any, ) -> Any: return params.Cookie( @@ -150,6 +157,7 @@ def Cookie( # noqa: N802 example=example, examples=examples, deprecated=deprecated, + include_in_schema=include_in_schema, **extra, ) diff --git a/fastapi/params.py b/fastapi/params.py index 3cab98b78..042bbd42f 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -31,11 +31,13 @@ class Param(FieldInfo): example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, + include_in_schema: bool = True, **extra: Any, ): self.deprecated = deprecated self.example = example self.examples = examples + self.include_in_schema = include_in_schema super().__init__( default, alias=alias, @@ -75,6 +77,7 @@ class Path(Param): example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, + include_in_schema: bool = True, **extra: Any, ): self.in_ = self.in_ @@ -93,6 +96,7 @@ class Path(Param): deprecated=deprecated, example=example, examples=examples, + include_in_schema=include_in_schema, **extra, ) @@ -117,6 +121,7 @@ class Query(Param): example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, + include_in_schema: bool = True, **extra: Any, ): super().__init__( @@ -134,6 +139,7 @@ class Query(Param): deprecated=deprecated, example=example, examples=examples, + include_in_schema=include_in_schema, **extra, ) @@ -159,6 +165,7 @@ class Header(Param): example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, + include_in_schema: bool = True, **extra: Any, ): self.convert_underscores = convert_underscores @@ -177,6 +184,7 @@ class Header(Param): deprecated=deprecated, example=example, examples=examples, + include_in_schema=include_in_schema, **extra, ) @@ -201,6 +209,7 @@ class Cookie(Param): example: Any = Undefined, examples: Optional[Dict[str, Any]] = None, deprecated: Optional[bool] = None, + include_in_schema: bool = True, **extra: Any, ): super().__init__( @@ -218,6 +227,7 @@ class Cookie(Param): deprecated=deprecated, example=example, examples=examples, + include_in_schema=include_in_schema, **extra, ) diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py new file mode 100644 index 000000000..4eaac72d8 --- /dev/null +++ b/tests/test_param_include_in_schema.py @@ -0,0 +1,239 @@ +from typing import Optional + +import pytest +from fastapi import Cookie, FastAPI, Header, Path, Query +from fastapi.testclient import TestClient + +app = FastAPI() + + +@app.get("/hidden_cookie") +async def hidden_cookie( + hidden_cookie: Optional[str] = Cookie(None, include_in_schema=False) +): + return {"hidden_cookie": hidden_cookie} + + +@app.get("/hidden_header") +async def hidden_header( + hidden_header: Optional[str] = Header(None, include_in_schema=False) +): + return {"hidden_header": hidden_header} + + +@app.get("/hidden_path/{hidden_path}") +async def hidden_path(hidden_path: str = Path(..., include_in_schema=False)): + return {"hidden_path": hidden_path} + + +@app.get("/hidden_query") +async def hidden_query( + hidden_query: Optional[str] = Query(None, include_in_schema=False) +): + return {"hidden_query": hidden_query} + + +client = TestClient(app) + +openapi_shema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/hidden_cookie": { + "get": { + "summary": "Hidden Cookie", + "operationId": "hidden_cookie_hidden_cookie_get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/hidden_header": { + "get": { + "summary": "Hidden Header", + "operationId": "hidden_header_hidden_header_get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/hidden_path/{hidden_path}": { + "get": { + "summary": "Hidden Path", + "operationId": "hidden_path_hidden_path__hidden_path__get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/hidden_query": { + "get": { + "summary": "Hidden Query", + "operationId": "hidden_query_hidden_query_get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_shema + + +@pytest.mark.parametrize( + "path,cookies,expected_status,expected_response", + [ + ( + "/hidden_cookie", + {}, + 200, + {"hidden_cookie": None}, + ), + ( + "/hidden_cookie", + {"hidden_cookie": "somevalue"}, + 200, + {"hidden_cookie": "somevalue"}, + ), + ], +) +def test_hidden_cookie(path, cookies, expected_status, expected_response): + response = client.get(path, cookies=cookies) + assert response.status_code == expected_status + assert response.json() == expected_response + + +@pytest.mark.parametrize( + "path,headers,expected_status,expected_response", + [ + ( + "/hidden_header", + {}, + 200, + {"hidden_header": None}, + ), + ( + "/hidden_header", + {"Hidden-Header": "somevalue"}, + 200, + {"hidden_header": "somevalue"}, + ), + ], +) +def test_hidden_header(path, headers, expected_status, expected_response): + response = client.get(path, headers=headers) + assert response.status_code == expected_status + assert response.json() == expected_response + + +def test_hidden_path(): + response = client.get("/hidden_path/hidden_path") + assert response.status_code == 200 + assert response.json() == {"hidden_path": "hidden_path"} + + +@pytest.mark.parametrize( + "path,expected_status,expected_response", + [ + ( + "/hidden_query", + 200, + {"hidden_query": None}, + ), + ( + "/hidden_query?hidden_query=somevalue", + 200, + {"hidden_query": "somevalue"}, + ), + ], +) +def test_hidden_query(path, expected_status, expected_response): + response = client.get(path) + assert response.status_code == expected_status + assert response.json() == expected_response diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py new file mode 100644 index 000000000..98ae5a684 --- /dev/null +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py @@ -0,0 +1,82 @@ +from fastapi.testclient import TestClient + +from docs_src.query_params_str_validations.tutorial014 import app + +client = TestClient(app) + + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_hidden_query(): + response = client.get("/items?hidden_query=somevalue") + assert response.status_code == 200, response.text + assert response.json() == {"hidden_query": "somevalue"} + + +def test_no_hidden_query(): + response = client.get("/items") + assert response.status_code == 200, response.text + assert response.json() == {"hidden_query": "Not found"} diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py new file mode 100644 index 000000000..33f3d5f77 --- /dev/null +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py @@ -0,0 +1,91 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.query_params_str_validations.tutorial014_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py310 +def test_hidden_query(client: TestClient): + response = client.get("/items?hidden_query=somevalue") + assert response.status_code == 200, response.text + assert response.json() == {"hidden_query": "somevalue"} + + +@needs_py310 +def test_no_hidden_query(client: TestClient): + response = client.get("/items") + assert response.status_code == 200, response.text + assert response.json() == {"hidden_query": "Not found"} From 85518bc58b131ddc8d7f251c9349f473d194a9b2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 23 Jan 2022 15:55:36 +0000 Subject: [PATCH 364/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 41fa8493e..afd109d88 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Allow hiding from OpenAPI (and Swagger UI) `Query`, `Cookie`, `Header`, and `Path` parameters. PR [#3144](https://github.com/tiangolo/fastapi/pull/3144) by [@astraldawn](https://github.com/astraldawn). * 🔧 Add sponsor Dropbase. PR [#4465](https://github.com/tiangolo/fastapi/pull/4465) by [@tiangolo](https://github.com/tiangolo). ## 0.72.0 From 3de0fb82bf17fa4179caa38c3126786a7d99cf67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 23 Jan 2022 17:13:49 +0100 Subject: [PATCH 365/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20docs=20dependencie?= =?UTF-8?q?s=20cache,=20to=20get=20the=20latest=20Material=20for=20MkDocs?= =?UTF-8?q?=20(#4466)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index eba5fc57e..ccf964486 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -20,7 +20,7 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-docs + key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-docs-v2 - name: Install Flit if: steps.cache.outputs.cache-hit != 'true' run: python3.7 -m pip install flit From 699b5ef84198a352a332beea9953fe1db33315b6 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 23 Jan 2022 16:14:28 +0000 Subject: [PATCH 366/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index afd109d88..997fb7529 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix docs dependencies cache, to get the latest Material for MkDocs. PR [#4466](https://github.com/tiangolo/fastapi/pull/4466) by [@tiangolo](https://github.com/tiangolo). * ✨ Allow hiding from OpenAPI (and Swagger UI) `Query`, `Cookie`, `Header`, and `Path` parameters. PR [#3144](https://github.com/tiangolo/fastapi/pull/3144) by [@astraldawn](https://github.com/astraldawn). * 🔧 Add sponsor Dropbase. PR [#4465](https://github.com/tiangolo/fastapi/pull/4465) by [@tiangolo](https://github.com/tiangolo). From d4608a00cf4855021dfb1a780556e24dedc94b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 23 Jan 2022 17:32:04 +0100 Subject: [PATCH 367/814] =?UTF-8?q?=F0=9F=90=9B=20Prefer=20custom=20encode?= =?UTF-8?q?r=20over=20defaults=20if=20specified=20in=20`jsonable=5Fencoder?= =?UTF-8?q?`=20(#4467)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vivek Sunder --- fastapi/encoders.py | 18 +++++++++--------- tests/test_jsonable_encoder.py | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/fastapi/encoders.py b/fastapi/encoders.py index 3f599c9fa..4b7ffe313 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -34,9 +34,17 @@ def jsonable_encoder( exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, - custom_encoder: Dict[Any, Callable[[Any], Any]] = {}, + custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None, sqlalchemy_safe: bool = True, ) -> Any: + custom_encoder = custom_encoder or {} + if custom_encoder: + if type(obj) in custom_encoder: + return custom_encoder[type(obj)](obj) + else: + for encoder_type, encoder_instance in custom_encoder.items(): + if isinstance(obj, encoder_type): + return encoder_instance(obj) if include is not None and not isinstance(include, (set, dict)): include = set(include) if exclude is not None and not isinstance(exclude, (set, dict)): @@ -118,14 +126,6 @@ def jsonable_encoder( ) return encoded_list - if custom_encoder: - if type(obj) in custom_encoder: - return custom_encoder[type(obj)](obj) - else: - for encoder_type, encoder in custom_encoder.items(): - if isinstance(obj, encoder_type): - return encoder(obj) - if type(obj) in ENCODERS_BY_TYPE: return ENCODERS_BY_TYPE[type(obj)](obj) for encoder, classes_tuple in encoders_by_class_tuples.items(): diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py index e2aa8adf8..fa82b5ea8 100644 --- a/tests/test_jsonable_encoder.py +++ b/tests/test_jsonable_encoder.py @@ -161,6 +161,21 @@ def test_custom_encoders(): assert encoded_instance["dt_field"] == instance.dt_field.isoformat() +def test_custom_enum_encoders(): + def custom_enum_encoder(v: Enum): + return v.value.lower() + + class MyEnum(Enum): + ENUM_VAL_1 = "ENUM_VAL_1" + + instance = MyEnum.ENUM_VAL_1 + + encoded_instance = jsonable_encoder( + instance, custom_encoder={MyEnum: custom_enum_encoder} + ) + assert encoded_instance == custom_enum_encoder(instance) + + def test_encode_model_with_path(model_with_path): if isinstance(model_with_path.path, PureWindowsPath): expected = "\\foo\\bar" From f4963f05bf4295e02cce1a28386712a5e6776fc4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 23 Jan 2022 16:32:35 +0000 Subject: [PATCH 368/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 997fb7529..49747539d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Prefer custom encoder over defaults if specified in `jsonable_encoder`. PR [#4467](https://github.com/tiangolo/fastapi/pull/4467) by [@tiangolo](https://github.com/tiangolo). * 🐛 Fix docs dependencies cache, to get the latest Material for MkDocs. PR [#4466](https://github.com/tiangolo/fastapi/pull/4466) by [@tiangolo](https://github.com/tiangolo). * ✨ Allow hiding from OpenAPI (and Swagger UI) `Query`, `Cookie`, `Header`, and `Path` parameters. PR [#3144](https://github.com/tiangolo/fastapi/pull/3144) by [@astraldawn](https://github.com/astraldawn). * 🔧 Add sponsor Dropbase. PR [#4465](https://github.com/tiangolo/fastapi/pull/4465) by [@tiangolo](https://github.com/tiangolo). From 6215fdd39e54422561d51d7e6159c219053d41cb Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 23 Jan 2022 16:34:52 +0000 Subject: [PATCH 370/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 49747539d..468d450a8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Prefer custom encoder over defaults if specified in `jsonable_encoder`. PR [#2061](https://github.com/tiangolo/fastapi/pull/2061) by [@viveksunder](https://github.com/viveksunder). * 🐛 Prefer custom encoder over defaults if specified in `jsonable_encoder`. PR [#4467](https://github.com/tiangolo/fastapi/pull/4467) by [@tiangolo](https://github.com/tiangolo). * 🐛 Fix docs dependencies cache, to get the latest Material for MkDocs. PR [#4466](https://github.com/tiangolo/fastapi/pull/4466) by [@tiangolo](https://github.com/tiangolo). * ✨ Allow hiding from OpenAPI (and Swagger UI) `Query`, `Cookie`, `Header`, and `Path` parameters. PR [#3144](https://github.com/tiangolo/fastapi/pull/3144) by [@astraldawn](https://github.com/astraldawn). From 0f8349fcb7c57921d28e78296a7dc8d0504459e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 23 Jan 2022 18:03:42 +0100 Subject: [PATCH 371/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 468d450a8..54017ceb3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -3,7 +3,7 @@ ## Latest Changes * 🐛 Prefer custom encoder over defaults if specified in `jsonable_encoder`. PR [#2061](https://github.com/tiangolo/fastapi/pull/2061) by [@viveksunder](https://github.com/viveksunder). -* 🐛 Prefer custom encoder over defaults if specified in `jsonable_encoder`. PR [#4467](https://github.com/tiangolo/fastapi/pull/4467) by [@tiangolo](https://github.com/tiangolo). + * 💚 Duplicate PR to trigger CI. PR [#4467](https://github.com/tiangolo/fastapi/pull/4467) by [@tiangolo](https://github.com/tiangolo). * 🐛 Fix docs dependencies cache, to get the latest Material for MkDocs. PR [#4466](https://github.com/tiangolo/fastapi/pull/4466) by [@tiangolo](https://github.com/tiangolo). * ✨ Allow hiding from OpenAPI (and Swagger UI) `Query`, `Cookie`, `Header`, and `Path` parameters. PR [#3144](https://github.com/tiangolo/fastapi/pull/3144) by [@astraldawn](https://github.com/astraldawn). * 🔧 Add sponsor Dropbase. PR [#4465](https://github.com/tiangolo/fastapi/pull/4465) by [@tiangolo](https://github.com/tiangolo). From 569afb4378c80e0bff5dc4a45f26d012e498eda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 23 Jan 2022 18:43:04 +0100 Subject: [PATCH 372/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20tags?= =?UTF-8?q?=20with=20Enums=20(#4468)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tutorial/path-operation-configuration.md | 12 ++++ .../tutorial002b.py | 20 +++++++ fastapi/applications.py | 23 ++++---- fastapi/routing.py | 32 +++++------ .../test_tutorial002b.py | 56 +++++++++++++++++++ 5 files changed, 116 insertions(+), 27 deletions(-) create mode 100644 docs_src/path_operation_configuration/tutorial002b.py create mode 100644 tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py diff --git a/docs/en/docs/tutorial/path-operation-configuration.md b/docs/en/docs/tutorial/path-operation-configuration.md index 1ff448e76..884a762e2 100644 --- a/docs/en/docs/tutorial/path-operation-configuration.md +++ b/docs/en/docs/tutorial/path-operation-configuration.md @@ -64,6 +64,18 @@ They will be added to the OpenAPI schema and used by the automatic documentation +### Tags with Enums + +If you have a big application, you might end up accumulating **several tags**, and you would want to make sure you always use the **same tag** for related *path operations*. + +In these cases, it could make sense to store the tags in an `Enum`. + +**FastAPI** supports that the same way as with plain strings: + +```Python hl_lines="1 8-10 13 18" +{!../../../docs_src/path_operation_configuration/tutorial002b.py!} +``` + ## Summary and description You can add a `summary` and `description`: diff --git a/docs_src/path_operation_configuration/tutorial002b.py b/docs_src/path_operation_configuration/tutorial002b.py new file mode 100644 index 000000000..d53b4d817 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial002b.py @@ -0,0 +1,20 @@ +from enum import Enum + +from fastapi import FastAPI + +app = FastAPI() + + +class Tags(Enum): + items = "items" + users = "users" + + +@app.get("/items/", tags=[Tags.items]) +async def get_items(): + return ["Portal gun", "Plumbus"] + + +@app.get("/users/", tags=[Tags.users]) +async def read_users(): + return ["Rick", "Morty"] diff --git a/fastapi/applications.py b/fastapi/applications.py index d71d4190a..dbfd76fb9 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -1,3 +1,4 @@ +from enum import Enum from typing import Any, Callable, Coroutine, Dict, List, Optional, Sequence, Type, Union from fastapi import routing @@ -219,7 +220,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -273,7 +274,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -342,7 +343,7 @@ class FastAPI(Starlette): router: routing.APIRouter, *, prefix: str = "", - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, deprecated: Optional[bool] = None, @@ -368,7 +369,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -419,7 +420,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -470,7 +471,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -521,7 +522,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -572,7 +573,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -623,7 +624,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -674,7 +675,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -725,7 +726,7 @@ class FastAPI(Starlette): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, diff --git a/fastapi/routing.py b/fastapi/routing.py index 63ad72964..f6d5370d6 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -1,9 +1,9 @@ import asyncio import dataclasses import email.message -import enum import inspect import json +from enum import Enum, IntEnum from typing import ( Any, Callable, @@ -305,7 +305,7 @@ class APIRoute(routing.Route): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -330,7 +330,7 @@ class APIRoute(routing.Route): openapi_extra: Optional[Dict[str, Any]] = None, ) -> None: # normalise enums e.g. http.HTTPStatus - if isinstance(status_code, enum.IntEnum): + if isinstance(status_code, IntEnum): status_code = int(status_code) self.path = path self.endpoint = endpoint @@ -438,7 +438,7 @@ class APIRouter(routing.Router): self, *, prefix: str = "", - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, default_response_class: Type[Response] = Default(JSONResponse), responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, @@ -466,7 +466,7 @@ class APIRouter(routing.Router): "/" ), "A path prefix must not end with '/', as the routes will start with '/'" self.prefix = prefix - self.tags: List[str] = tags or [] + self.tags: List[Union[str, Enum]] = tags or [] self.dependencies = list(dependencies or []) or [] self.deprecated = deprecated self.include_in_schema = include_in_schema @@ -483,7 +483,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -557,7 +557,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -634,7 +634,7 @@ class APIRouter(routing.Router): router: "APIRouter", *, prefix: str = "", - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, default_response_class: Type[Response] = Default(JSONResponse), responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, @@ -738,7 +738,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -790,7 +790,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -842,7 +842,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -894,7 +894,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -946,7 +946,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -998,7 +998,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -1050,7 +1050,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, @@ -1102,7 +1102,7 @@ class APIRouter(routing.Router): *, response_model: Optional[Type[Any]] = None, status_code: Optional[int] = None, - tags: Optional[List[str]] = None, + tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py new file mode 100644 index 000000000..be9f2afec --- /dev/null +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py @@ -0,0 +1,56 @@ +from fastapi.testclient import TestClient + +from docs_src.path_operation_configuration.tutorial002b import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "tags": ["items"], + "summary": "Get Items", + "operationId": "get_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + }, + "/users/": { + "get": { + "tags": ["users"], + "summary": "Read Users", + "operationId": "read_users_users__get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + }, + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_get_items(): + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == ["Portal gun", "Plumbus"] + + +def test_get_users(): + response = client.get("/users/") + assert response.status_code == 200, response.text + assert response.json() == ["Rick", "Morty"] From 59b1f353b3fe77cf801242e3d120372ad8519710 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 23 Jan 2022 17:43:36 +0000 Subject: [PATCH 373/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 54017ceb3..7026d0eb1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for tags with Enums. PR [#4468](https://github.com/tiangolo/fastapi/pull/4468) by [@tiangolo](https://github.com/tiangolo). * 🐛 Prefer custom encoder over defaults if specified in `jsonable_encoder`. PR [#2061](https://github.com/tiangolo/fastapi/pull/2061) by [@viveksunder](https://github.com/viveksunder). * 💚 Duplicate PR to trigger CI. PR [#4467](https://github.com/tiangolo/fastapi/pull/4467) by [@tiangolo](https://github.com/tiangolo). * 🐛 Fix docs dependencies cache, to get the latest Material for MkDocs. PR [#4466](https://github.com/tiangolo/fastapi/pull/4466) by [@tiangolo](https://github.com/tiangolo). From 1bf55200a90b04229f665cd2ee83edde91e936e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 23 Jan 2022 20:14:13 +0100 Subject: [PATCH 374/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20decla?= =?UTF-8?q?ring=20`UploadFile`=20parameters=20without=20explicit=20`File()?= =?UTF-8?q?`=20(#4469)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/tutorial/request-files.md | 47 +++- docs_src/request_files/tutorial001.py | 2 +- docs_src/request_files/tutorial001_02.py | 21 ++ .../request_files/tutorial001_02_py310.py | 19 ++ docs_src/request_files/tutorial001_03.py | 15 ++ docs_src/request_files/tutorial002.py | 2 +- docs_src/request_files/tutorial002_py39.py | 2 +- docs_src/request_files/tutorial003.py | 37 +++ docs_src/request_files/tutorial003_py39.py | 35 +++ fastapi/datastructures.py | 6 +- fastapi/dependencies/utils.py | 28 +-- .../test_request_files/test_tutorial001_02.py | 157 ++++++++++++ .../test_tutorial001_02_py310.py | 169 +++++++++++++ .../test_request_files/test_tutorial001_03.py | 159 +++++++++++++ .../test_request_files/test_tutorial003.py | 194 +++++++++++++++ .../test_tutorial003_py39.py | 223 ++++++++++++++++++ 16 files changed, 1086 insertions(+), 30 deletions(-) create mode 100644 docs_src/request_files/tutorial001_02.py create mode 100644 docs_src/request_files/tutorial001_02_py310.py create mode 100644 docs_src/request_files/tutorial001_03.py create mode 100644 docs_src/request_files/tutorial003.py create mode 100644 docs_src/request_files/tutorial003_py39.py create mode 100644 tests/test_tutorial/test_request_files/test_tutorial001_02.py create mode 100644 tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py create mode 100644 tests/test_tutorial/test_request_files/test_tutorial001_03.py create mode 100644 tests/test_tutorial/test_request_files/test_tutorial003.py create mode 100644 tests/test_tutorial/test_request_files/test_tutorial003_py39.py diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md index b7257c7eb..ed2c8b6af 100644 --- a/docs/en/docs/tutorial/request-files.md +++ b/docs/en/docs/tutorial/request-files.md @@ -17,7 +17,7 @@ Import `File` and `UploadFile` from `fastapi`: {!../../../docs_src/request_files/tutorial001.py!} ``` -## Define `File` parameters +## Define `File` Parameters Create file parameters the same way you would for `Body` or `Form`: @@ -41,7 +41,7 @@ Have in mind that this means that the whole contents will be stored in memory. T But there are several cases in which you might benefit from using `UploadFile`. -## `File` parameters with `UploadFile` +## `File` Parameters with `UploadFile` Define a `File` parameter with a type of `UploadFile`: @@ -51,6 +51,7 @@ Define a `File` parameter with a type of `UploadFile`: Using `UploadFile` has several advantages over `bytes`: +* You don't have to use `File()` in the default value. * It uses a "spooled" file: * A file stored in memory up to a maximum size limit, and after passing this limit it will be stored in disk. * This means that it will work well for large files like images, videos, large binaries, etc. without consuming all the memory. @@ -113,7 +114,31 @@ The way HTML forms (`
`) sends the data to the server normally uses This is not a limitation of **FastAPI**, it's part of the HTTP protocol. -## Multiple file uploads +## Optional File Upload + +You can make a file optional by using standard type annotations: + +=== "Python 3.6 and above" + + ```Python hl_lines="9 17" + {!> ../../../docs_src/request_files/tutorial001_02.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="7 14" + {!> ../../../docs_src/request_files/tutorial001_02_py310.py!} + ``` + +## `UploadFile` with Additional Metadata + +You can also use `File()` with `UploadFile` to set additional parameters in `File()`, for example additional metadata: + +```Python hl_lines="13" +{!../../../docs_src/request_files/tutorial001_03.py!} +``` + +## Multiple File Uploads It's possible to upload several files at the same time. @@ -140,6 +165,22 @@ You will receive, as declared, a `list` of `bytes` or `UploadFile`s. **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette. +### Multiple File Uploads with Additional Metadata + +And the same way as before, you can use `File()` to set additional parameters, even for `UploadFile`: + +=== "Python 3.6 and above" + + ```Python hl_lines="18" + {!> ../../../docs_src/request_files/tutorial003.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="16" + {!> ../../../docs_src/request_files/tutorial003_py39.py!} + ``` + ## Recap Use `File` to declare files to be uploaded as input parameters (as form data). diff --git a/docs_src/request_files/tutorial001.py b/docs_src/request_files/tutorial001.py index fffb56af8..0fb1dd571 100644 --- a/docs_src/request_files/tutorial001.py +++ b/docs_src/request_files/tutorial001.py @@ -9,5 +9,5 @@ async def create_file(file: bytes = File(...)): @app.post("/uploadfile/") -async def create_upload_file(file: UploadFile = File(...)): +async def create_upload_file(file: UploadFile): return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_02.py b/docs_src/request_files/tutorial001_02.py new file mode 100644 index 000000000..26a4c9cbf --- /dev/null +++ b/docs_src/request_files/tutorial001_02.py @@ -0,0 +1,21 @@ +from typing import Optional + +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: Optional[bytes] = File(None)): + if not file: + return {"message": "No file sent"} + else: + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file(file: Optional[UploadFile] = None): + if not file: + return {"message": "No upload file sent"} + else: + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_02_py310.py b/docs_src/request_files/tutorial001_02_py310.py new file mode 100644 index 000000000..0e576251b --- /dev/null +++ b/docs_src/request_files/tutorial001_02_py310.py @@ -0,0 +1,19 @@ +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: bytes | None = File(None)): + if not file: + return {"message": "No file sent"} + else: + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file(file: UploadFile | None = None): + if not file: + return {"message": "No upload file sent"} + else: + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_03.py b/docs_src/request_files/tutorial001_03.py new file mode 100644 index 000000000..abcac9e4c --- /dev/null +++ b/docs_src/request_files/tutorial001_03.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: bytes = File(..., description="A file read as bytes")): + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file( + file: UploadFile = File(..., description="A file read as UploadFile") +): + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial002.py b/docs_src/request_files/tutorial002.py index 6fdf16a75..94abb7c6c 100644 --- a/docs_src/request_files/tutorial002.py +++ b/docs_src/request_files/tutorial002.py @@ -12,7 +12,7 @@ async def create_files(files: List[bytes] = File(...)): @app.post("/uploadfiles/") -async def create_upload_files(files: List[UploadFile] = File(...)): +async def create_upload_files(files: List[UploadFile]): return {"filenames": [file.filename for file in files]} diff --git a/docs_src/request_files/tutorial002_py39.py b/docs_src/request_files/tutorial002_py39.py index 26cd56769..2779618bd 100644 --- a/docs_src/request_files/tutorial002_py39.py +++ b/docs_src/request_files/tutorial002_py39.py @@ -10,7 +10,7 @@ async def create_files(files: list[bytes] = File(...)): @app.post("/uploadfiles/") -async def create_upload_files(files: list[UploadFile] = File(...)): +async def create_upload_files(files: list[UploadFile]): return {"filenames": [file.filename for file in files]} diff --git a/docs_src/request_files/tutorial003.py b/docs_src/request_files/tutorial003.py new file mode 100644 index 000000000..4a91b7a8b --- /dev/null +++ b/docs_src/request_files/tutorial003.py @@ -0,0 +1,37 @@ +from typing import List + +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files( + files: List[bytes] = File(..., description="Multiple files as bytes") +): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files( + files: List[UploadFile] = File(..., description="Multiple files as UploadFile") +): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial003_py39.py b/docs_src/request_files/tutorial003_py39.py new file mode 100644 index 000000000..d853f48d1 --- /dev/null +++ b/docs_src/request_files/tutorial003_py39.py @@ -0,0 +1,35 @@ +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files( + files: list[bytes] = File(..., description="Multiple files as bytes") +): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files( + files: list[UploadFile] = File(..., description="Multiple files as UploadFile") +): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py index b13171287..b20a25ab6 100644 --- a/fastapi/datastructures.py +++ b/fastapi/datastructures.py @@ -1,4 +1,4 @@ -from typing import Any, Callable, Iterable, Type, TypeVar +from typing import Any, Callable, Dict, Iterable, Type, TypeVar from starlette.datastructures import URL as URL # noqa: F401 from starlette.datastructures import Address as Address # noqa: F401 @@ -20,6 +20,10 @@ class UploadFile(StarletteUploadFile): raise ValueError(f"Expected UploadFile, received: {type(v)}") return v + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update({"type": "string", "format": "binary"}) + class DefaultPlaceholder: """ diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 35ba44aab..d4028d067 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -390,6 +390,8 @@ def get_param_field( field.required = required if not had_schema and not is_scalar_field(field=field): field.field_info = params.Body(field_info.default) + if not had_schema and lenient_issubclass(field.type_, UploadFile): + field.field_info = params.File(field_info.default) return field @@ -701,25 +703,6 @@ def get_missing_field_error(loc: Tuple[str, ...]) -> ErrorWrapper: return missing_field_error -def get_schema_compatible_field(*, field: ModelField) -> ModelField: - out_field = field - if lenient_issubclass(field.type_, UploadFile): - use_type: type = bytes - if field.shape in sequence_shapes: - use_type = List[bytes] - out_field = create_response_field( - name=field.name, - type_=use_type, - class_validators=field.class_validators, - model_config=field.model_config, - default=field.default, - required=field.required, - alias=field.alias, - field_info=field.field_info, - ) - return out_field - - def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]: flat_dependant = get_flat_dependant(dependant) if not flat_dependant.body_params: @@ -729,9 +712,8 @@ def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]: embed = getattr(field_info, "embed", None) body_param_names_set = {param.name for param in flat_dependant.body_params} if len(body_param_names_set) == 1 and not embed: - final_field = get_schema_compatible_field(field=first_param) - check_file_field(final_field) - return final_field + check_file_field(first_param) + return first_param # If one field requires to embed, all have to be embedded # in case a sub-dependency is evaluated with a single unique body field # That is combined (embedded) with other body fields @@ -740,7 +722,7 @@ def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]: model_name = "Body_" + name BodyModel: Type[BaseModel] = create_model(model_name) for f in flat_dependant.body_params: - BodyModel.__fields__[f.name] = get_schema_compatible_field(field=f) + BodyModel.__fields__[f.name] = f required = any(True for f in flat_dependant.body_params if f.required) BodyFieldInfo_kwargs: Dict[str, Any] = dict(default=None) diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02.py b/tests/test_tutorial/test_request_files/test_tutorial001_02.py new file mode 100644 index 000000000..e852a1b31 --- /dev/null +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02.py @@ -0,0 +1,157 @@ +from fastapi.testclient import TestClient + +from docs_src.request_files.tutorial001_02 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/files/": { + "post": { + "summary": "Create File", + "operationId": "create_file_files__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_file_files__post" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/uploadfile/": { + "post": { + "summary": "Create Upload File", + "operationId": "create_upload_file_uploadfile__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_create_file_files__post": { + "title": "Body_create_file_files__post", + "type": "object", + "properties": { + "file": {"title": "File", "type": "string", "format": "binary"} + }, + }, + "Body_create_upload_file_uploadfile__post": { + "title": "Body_create_upload_file_uploadfile__post", + "type": "object", + "properties": { + "file": {"title": "File", "type": "string", "format": "binary"} + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_post_form_no_body(): + response = client.post("/files/") + assert response.status_code == 200, response.text + assert response.json() == {"message": "No file sent"} + + +def test_post_uploadfile_no_body(): + response = client.post("/uploadfile/") + assert response.status_code == 200, response.text + assert response.json() == {"message": "No upload file sent"} + + +def test_post_file(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file: + response = client.post("/files/", files={"file": file}) + assert response.status_code == 200, response.text + assert response.json() == {"file_size": 14} + + +def test_post_upload_file(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file: + response = client.post("/uploadfile/", files={"file": file}) + assert response.status_code == 200, response.text + assert response.json() == {"filename": "test.txt"} diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py new file mode 100644 index 000000000..62e9f98d0 --- /dev/null +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py @@ -0,0 +1,169 @@ +from pathlib import Path + +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/files/": { + "post": { + "summary": "Create File", + "operationId": "create_file_files__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_file_files__post" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/uploadfile/": { + "post": { + "summary": "Create Upload File", + "operationId": "create_upload_file_uploadfile__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_create_file_files__post": { + "title": "Body_create_file_files__post", + "type": "object", + "properties": { + "file": {"title": "File", "type": "string", "format": "binary"} + }, + }, + "Body_create_upload_file_uploadfile__post": { + "title": "Body_create_upload_file_uploadfile__post", + "type": "object", + "properties": { + "file": {"title": "File", "type": "string", "format": "binary"} + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.request_files.tutorial001_02_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_openapi_schema(client: TestClient): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +@needs_py310 +def test_post_form_no_body(client: TestClient): + response = client.post("/files/") + assert response.status_code == 200, response.text + assert response.json() == {"message": "No file sent"} + + +@needs_py310 +def test_post_uploadfile_no_body(client: TestClient): + response = client.post("/uploadfile/") + assert response.status_code == 200, response.text + assert response.json() == {"message": "No upload file sent"} + + +@needs_py310 +def test_post_file(tmp_path: Path, client: TestClient): + path = tmp_path / "test.txt" + path.write_bytes(b"") + + with path.open("rb") as file: + response = client.post("/files/", files={"file": file}) + assert response.status_code == 200, response.text + assert response.json() == {"file_size": 14} + + +@needs_py310 +def test_post_upload_file(tmp_path: Path, client: TestClient): + path = tmp_path / "test.txt" + path.write_bytes(b"") + + with path.open("rb") as file: + response = client.post("/uploadfile/", files={"file": file}) + assert response.status_code == 200, response.text + assert response.json() == {"filename": "test.txt"} diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03.py b/tests/test_tutorial/test_request_files/test_tutorial001_03.py new file mode 100644 index 000000000..ec7509ea2 --- /dev/null +++ b/tests/test_tutorial/test_request_files/test_tutorial001_03.py @@ -0,0 +1,159 @@ +from fastapi.testclient import TestClient + +from docs_src.request_files.tutorial001_03 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/files/": { + "post": { + "summary": "Create File", + "operationId": "create_file_files__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_file_files__post" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/uploadfile/": { + "post": { + "summary": "Create Upload File", + "operationId": "create_upload_file_uploadfile__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_create_file_files__post": { + "title": "Body_create_file_files__post", + "required": ["file"], + "type": "object", + "properties": { + "file": { + "title": "File", + "type": "string", + "description": "A file read as bytes", + "format": "binary", + } + }, + }, + "Body_create_upload_file_uploadfile__post": { + "title": "Body_create_upload_file_uploadfile__post", + "required": ["file"], + "type": "object", + "properties": { + "file": { + "title": "File", + "type": "string", + "description": "A file read as UploadFile", + "format": "binary", + } + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_post_file(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file: + response = client.post("/files/", files={"file": file}) + assert response.status_code == 200, response.text + assert response.json() == {"file_size": 14} + + +def test_post_upload_file(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file: + response = client.post("/uploadfile/", files={"file": file}) + assert response.status_code == 200, response.text + assert response.json() == {"filename": "test.txt"} diff --git a/tests/test_tutorial/test_request_files/test_tutorial003.py b/tests/test_tutorial/test_request_files/test_tutorial003.py new file mode 100644 index 000000000..943b235ab --- /dev/null +++ b/tests/test_tutorial/test_request_files/test_tutorial003.py @@ -0,0 +1,194 @@ +from fastapi.testclient import TestClient + +from docs_src.request_files.tutorial003 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/files/": { + "post": { + "summary": "Create Files", + "operationId": "create_files_files__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_files_files__post" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/uploadfiles/": { + "post": { + "summary": "Create Upload Files", + "operationId": "create_upload_files_uploadfiles__post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_create_upload_files_uploadfiles__post" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/": { + "get": { + "summary": "Main", + "operationId": "main__get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + }, + }, + "components": { + "schemas": { + "Body_create_files_files__post": { + "title": "Body_create_files_files__post", + "required": ["files"], + "type": "object", + "properties": { + "files": { + "title": "Files", + "type": "array", + "items": {"type": "string", "format": "binary"}, + "description": "Multiple files as bytes", + } + }, + }, + "Body_create_upload_files_uploadfiles__post": { + "title": "Body_create_upload_files_uploadfiles__post", + "required": ["files"], + "type": "object", + "properties": { + "files": { + "title": "Files", + "type": "array", + "items": {"type": "string", "format": "binary"}, + "description": "Multiple files as UploadFile", + } + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_post_files(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") + path2 = tmp_path / "test2.txt" + path2.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file, path2.open("rb") as file2: + response = client.post( + "/files/", + files=( + ("files", ("test.txt", file)), + ("files", ("test2.txt", file2)), + ), + ) + assert response.status_code == 200, response.text + assert response.json() == {"file_sizes": [14, 15]} + + +def test_post_upload_file(tmp_path): + path = tmp_path / "test.txt" + path.write_bytes(b"") + path2 = tmp_path / "test2.txt" + path2.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file, path2.open("rb") as file2: + response = client.post( + "/uploadfiles/", + files=( + ("files", ("test.txt", file)), + ("files", ("test2.txt", file2)), + ), + ) + assert response.status_code == 200, response.text + assert response.json() == {"filenames": ["test.txt", "test2.txt"]} + + +def test_get_root(): + client = TestClient(app) + response = client.get("/") + assert response.status_code == 200, response.text + assert b"") + path2 = tmp_path / "test2.txt" + path2.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file, path2.open("rb") as file2: + response = client.post( + "/files/", + files=( + ("files", ("test.txt", file)), + ("files", ("test2.txt", file2)), + ), + ) + assert response.status_code == 200, response.text + assert response.json() == {"file_sizes": [14, 15]} + + +@needs_py39 +def test_post_upload_file(tmp_path, app: FastAPI): + path = tmp_path / "test.txt" + path.write_bytes(b"") + path2 = tmp_path / "test2.txt" + path2.write_bytes(b"") + + client = TestClient(app) + with path.open("rb") as file, path2.open("rb") as file2: + response = client.post( + "/uploadfiles/", + files=( + ("files", ("test.txt", file)), + ("files", ("test2.txt", file2)), + ), + ) + assert response.status_code == 200, response.text + assert response.json() == {"filenames": ["test.txt", "test2.txt"]} + + +@needs_py39 +def test_get_root(app: FastAPI): + client = TestClient(app) + response = client.get("/") + assert response.status_code == 200, response.text + assert b" Date: Sun, 23 Jan 2022 19:14:47 +0000 Subject: [PATCH 375/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7026d0eb1..b7593ee3c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for declaring `UploadFile` parameters without explicit `File()`. PR [#4469](https://github.com/tiangolo/fastapi/pull/4469) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for tags with Enums. PR [#4468](https://github.com/tiangolo/fastapi/pull/4468) by [@tiangolo](https://github.com/tiangolo). * 🐛 Prefer custom encoder over defaults if specified in `jsonable_encoder`. PR [#2061](https://github.com/tiangolo/fastapi/pull/2061) by [@viveksunder](https://github.com/viveksunder). * 💚 Duplicate PR to trigger CI. PR [#4467](https://github.com/tiangolo/fastapi/pull/4467) by [@tiangolo](https://github.com/tiangolo). From f8d4d040155a58ecfdbc2ed58f0739b07e417516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 23 Jan 2022 22:30:35 +0100 Subject: [PATCH 376/814] =?UTF-8?q?=F0=9F=93=9D=20Tweak=20and=20improve=20?= =?UTF-8?q?docs=20for=20Request=20Files=20(#4470)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/tutorial/request-files.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md index ed2c8b6af..3ca471a91 100644 --- a/docs/en/docs/tutorial/request-files.md +++ b/docs/en/docs/tutorial/request-files.md @@ -41,9 +41,9 @@ Have in mind that this means that the whole contents will be stored in memory. T But there are several cases in which you might benefit from using `UploadFile`. -## `File` Parameters with `UploadFile` +## File Parameters with `UploadFile` -Define a `File` parameter with a type of `UploadFile`: +Define a file parameter with a type of `UploadFile`: ```Python hl_lines="12" {!../../../docs_src/request_files/tutorial001.py!} @@ -51,7 +51,7 @@ Define a `File` parameter with a type of `UploadFile`: Using `UploadFile` has several advantages over `bytes`: -* You don't have to use `File()` in the default value. +* You don't have to use `File()` in the default value of the parameter. * It uses a "spooled" file: * A file stored in memory up to a maximum size limit, and after passing this limit it will be stored in disk. * This means that it will work well for large files like images, videos, large binaries, etc. without consuming all the memory. @@ -116,7 +116,7 @@ The way HTML forms (`
`) sends the data to the server normally uses ## Optional File Upload -You can make a file optional by using standard type annotations: +You can make a file optional by using standard type annotations and setting a default value of `None`: === "Python 3.6 and above" @@ -132,7 +132,7 @@ You can make a file optional by using standard type annotations: ## `UploadFile` with Additional Metadata -You can also use `File()` with `UploadFile` to set additional parameters in `File()`, for example additional metadata: +You can also use `File()` with `UploadFile`, for example, to set additional metadata: ```Python hl_lines="13" {!../../../docs_src/request_files/tutorial001_03.py!} @@ -183,4 +183,4 @@ And the same way as before, you can use `File()` to set additional parameters, e ## Recap -Use `File` to declare files to be uploaded as input parameters (as form data). +Use `File`, `bytes`, and `UploadFile` to declare files to be uploaded in the request, sent as form data. From dba9ea81208078bdd91fbfff4fdbfe203dcc303f Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 23 Jan 2022 21:31:08 +0000 Subject: [PATCH 377/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b7593ee3c..84908dda5 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Tweak and improve docs for Request Files. PR [#4470](https://github.com/tiangolo/fastapi/pull/4470) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for declaring `UploadFile` parameters without explicit `File()`. PR [#4469](https://github.com/tiangolo/fastapi/pull/4469) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for tags with Enums. PR [#4468](https://github.com/tiangolo/fastapi/pull/4468) by [@tiangolo](https://github.com/tiangolo). * 🐛 Prefer custom encoder over defaults if specified in `jsonable_encoder`. PR [#2061](https://github.com/tiangolo/fastapi/pull/2061) by [@viveksunder](https://github.com/viveksunder). From a698908ed65d887a17245a580ecbf3bf3c848406 Mon Sep 17 00:00:00 2001 From: Victor Benichoux Date: Sun, 23 Jan 2022 23:13:55 +0100 Subject: [PATCH 378/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20bug=20preventing?= =?UTF-8?q?=20to=20use=20OpenAPI=20when=20using=20tuples=20(#3874)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/openapi/models.py | 2 +- tests/test_tuples.py | 267 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 tests/test_tuples.py diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 361c75005..9c6598d2d 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -123,7 +123,7 @@ class Schema(BaseModel): oneOf: Optional[List["Schema"]] = None anyOf: Optional[List["Schema"]] = None not_: Optional["Schema"] = Field(None, alias="not") - items: Optional["Schema"] = None + items: Optional[Union["Schema", List["Schema"]]] = None properties: Optional[Dict[str, "Schema"]] = None additionalProperties: Optional[Union["Schema", Reference, bool]] = None description: Optional[str] = None diff --git a/tests/test_tuples.py b/tests/test_tuples.py new file mode 100644 index 000000000..4cd5ee3af --- /dev/null +++ b/tests/test_tuples.py @@ -0,0 +1,267 @@ +from typing import List, Tuple + +from fastapi import FastAPI, Form +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + + +class ItemGroup(BaseModel): + items: List[Tuple[str, str]] + + +class Coordinate(BaseModel): + x: float + y: float + + +@app.post("/model-with-tuple/") +def post_model_with_tuple(item_group: ItemGroup): + return item_group + + +@app.post("/tuple-of-models/") +def post_tuple_of_models(square: Tuple[Coordinate, Coordinate]): + return square + + +@app.post("/tuple-form/") +def hello(values: Tuple[int, int] = Form(...)): + return values + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/model-with-tuple/": { + "post": { + "summary": "Post Model With Tuple", + "operationId": "post_model_with_tuple_model_with_tuple__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/ItemGroup"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/tuple-of-models/": { + "post": { + "summary": "Post Tuple Of Models", + "operationId": "post_tuple_of_models_tuple_of_models__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "title": "Square", + "maxItems": 2, + "minItems": 2, + "type": "array", + "items": [ + {"$ref": "#/components/schemas/Coordinate"}, + {"$ref": "#/components/schemas/Coordinate"}, + ], + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/tuple-form/": { + "post": { + "summary": "Hello", + "operationId": "hello_tuple_form__post", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Body_hello_tuple_form__post" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_hello_tuple_form__post": { + "title": "Body_hello_tuple_form__post", + "required": ["values"], + "type": "object", + "properties": { + "values": { + "title": "Values", + "maxItems": 2, + "minItems": 2, + "type": "array", + "items": [{"type": "integer"}, {"type": "integer"}], + } + }, + }, + "Coordinate": { + "title": "Coordinate", + "required": ["x", "y"], + "type": "object", + "properties": { + "x": {"title": "X", "type": "number"}, + "y": {"title": "Y", "type": "number"}, + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "ItemGroup": { + "title": "ItemGroup", + "required": ["items"], + "type": "object", + "properties": { + "items": { + "title": "Items", + "type": "array", + "items": { + "maxItems": 2, + "minItems": 2, + "type": "array", + "items": [{"type": "string"}, {"type": "string"}], + }, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_model_with_tuple_valid(): + data = {"items": [["foo", "bar"], ["baz", "whatelse"]]} + response = client.post("/model-with-tuple/", json=data) + assert response.status_code == 200, response.text + assert response.json() == data + + +def test_model_with_tuple_invalid(): + data = {"items": [["foo", "bar"], ["baz", "whatelse", "too", "much"]]} + response = client.post("/model-with-tuple/", json=data) + assert response.status_code == 422, response.text + + data = {"items": [["foo", "bar"], ["baz"]]} + response = client.post("/model-with-tuple/", json=data) + assert response.status_code == 422, response.text + + +def test_tuple_with_model_valid(): + data = [{"x": 1, "y": 2}, {"x": 3, "y": 4}] + response = client.post("/tuple-of-models/", json=data) + assert response.status_code == 200, response.text + assert response.json() == data + + +def test_tuple_with_model_invalid(): + data = [{"x": 1, "y": 2}, {"x": 3, "y": 4}, {"x": 5, "y": 6}] + response = client.post("/tuple-of-models/", json=data) + assert response.status_code == 422, response.text + + data = [{"x": 1, "y": 2}] + response = client.post("/tuple-of-models/", json=data) + assert response.status_code == 422, response.text + + +def test_tuple_form_valid(): + response = client.post("/tuple-form/", data=[("values", "1"), ("values", "2")]) + assert response.status_code == 200, response.text + assert response.json() == [1, 2] + + +def test_tuple_form_invalid(): + response = client.post( + "/tuple-form/", data=[("values", "1"), ("values", "2"), ("values", "3")] + ) + assert response.status_code == 422, response.text + + response = client.post("/tuple-form/", data=[("values", "1")]) + assert response.status_code == 422, response.text From af18d5c49fde32e79e4dfd7a82819a2c642c6c17 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 23 Jan 2022 22:14:28 +0000 Subject: [PATCH 379/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 84908dda5..f9f3aabde 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix bug preventing to use OpenAPI when using tuples. PR [#3874](https://github.com/tiangolo/fastapi/pull/3874) by [@victorbenichoux](https://github.com/victorbenichoux). * 📝 Tweak and improve docs for Request Files. PR [#4470](https://github.com/tiangolo/fastapi/pull/4470) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for declaring `UploadFile` parameters without explicit `File()`. PR [#4469](https://github.com/tiangolo/fastapi/pull/4469) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for tags with Enums. PR [#4468](https://github.com/tiangolo/fastapi/pull/4468) by [@tiangolo](https://github.com/tiangolo). From cbe8d552c1eee5b48f8ab0eab6b517e98ae8523b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 23 Jan 2022 23:37:48 +0100 Subject: [PATCH 380/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f9f3aabde..e75d46706 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,14 +2,25 @@ ## Latest Changes -* 🐛 Fix bug preventing to use OpenAPI when using tuples. PR [#3874](https://github.com/tiangolo/fastapi/pull/3874) by [@victorbenichoux](https://github.com/victorbenichoux). +### Features + +* ✨ Add support for declaring `UploadFile` parameters without explicit `File()`. PR [#4469](https://github.com/tiangolo/fastapi/pull/4469) by [@tiangolo](https://github.com/tiangolo). New docs: [Request Files - File Parameters with UploadFile](https://fastapi.tiangolo.com/tutorial/request-files/#file-parameters-with-uploadfile). +* ✨ Add support for tags with Enums. PR [#4468](https://github.com/tiangolo/fastapi/pull/4468) by [@tiangolo](https://github.com/tiangolo). New docs: [Path Operation Configuration - Tags with Enums](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags-with-enums). +* ✨ Allow hiding from OpenAPI (and Swagger UI) `Query`, `Cookie`, `Header`, and `Path` parameters. PR [#3144](https://github.com/tiangolo/fastapi/pull/3144) by [@astraldawn](https://github.com/astraldawn). New docs: [Query Parameters and String Validations - Exclude from OpenAPI](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + +### Docs + * 📝 Tweak and improve docs for Request Files. PR [#4470](https://github.com/tiangolo/fastapi/pull/4470) by [@tiangolo](https://github.com/tiangolo). -* ✨ Add support for declaring `UploadFile` parameters without explicit `File()`. PR [#4469](https://github.com/tiangolo/fastapi/pull/4469) by [@tiangolo](https://github.com/tiangolo). -* ✨ Add support for tags with Enums. PR [#4468](https://github.com/tiangolo/fastapi/pull/4468) by [@tiangolo](https://github.com/tiangolo). + +### Fixes + +* 🐛 Fix bug preventing to use OpenAPI when using tuples. PR [#3874](https://github.com/tiangolo/fastapi/pull/3874) by [@victorbenichoux](https://github.com/victorbenichoux). * 🐛 Prefer custom encoder over defaults if specified in `jsonable_encoder`. PR [#2061](https://github.com/tiangolo/fastapi/pull/2061) by [@viveksunder](https://github.com/viveksunder). * 💚 Duplicate PR to trigger CI. PR [#4467](https://github.com/tiangolo/fastapi/pull/4467) by [@tiangolo](https://github.com/tiangolo). + +### Internal + * 🐛 Fix docs dependencies cache, to get the latest Material for MkDocs. PR [#4466](https://github.com/tiangolo/fastapi/pull/4466) by [@tiangolo](https://github.com/tiangolo). -* ✨ Allow hiding from OpenAPI (and Swagger UI) `Query`, `Cookie`, `Header`, and `Path` parameters. PR [#3144](https://github.com/tiangolo/fastapi/pull/3144) by [@astraldawn](https://github.com/astraldawn). * 🔧 Add sponsor Dropbase. PR [#4465](https://github.com/tiangolo/fastapi/pull/4465) by [@tiangolo](https://github.com/tiangolo). ## 0.72.0 From 291180bf2d8c39e84860c2426b1d58b6c80f6fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 23 Jan 2022 23:38:51 +0100 Subject: [PATCH 381/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.73?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 ++ fastapi/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e75d46706..68b75e702 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,8 @@ ## Latest Changes +## 0.73.0 + ### Features * ✨ Add support for declaring `UploadFile` parameters without explicit `File()`. PR [#4469](https://github.com/tiangolo/fastapi/pull/4469) by [@tiangolo](https://github.com/tiangolo). New docs: [Request Files - File Parameters with UploadFile](https://fastapi.tiangolo.com/tutorial/request-files/#file-parameters-with-uploadfile). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index d83fe6fbd..8718788fa 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.72.0" +__version__ = "0.73.0" from starlette import status as status From 618c99d77444e383e7b95ebe32ededbd95155c43 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 15:27:34 +0100 Subject: [PATCH 382/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#4502)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/people.yml | 192 ++++++++++++++++++++++------------------ 1 file changed, 106 insertions(+), 86 deletions(-) diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index df088f39f..ebbe446ee 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,12 +1,12 @@ maintainers: - login: tiangolo - answers: 1230 - prs: 269 + answers: 1237 + prs: 280 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=5cad72c846b7aba2e960546af490edc7375dafc4&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 316 + count: 319 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 url: https://github.com/Kludex - login: dmontagu @@ -14,7 +14,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu - login: ycd - count: 219 + count: 221 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: Mause @@ -34,7 +34,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik - login: raphaelauv - count: 67 + count: 68 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv - login: falkben @@ -57,18 +57,22 @@ experts: count: 38 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 url: https://github.com/includeamin +- login: STeveShary + count: 37 + avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 + url: https://github.com/STeveShary - login: prostomarkeloff count: 33 avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4 url: https://github.com/prostomarkeloff -- login: STeveShary - count: 32 - avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 - url: https://github.com/STeveShary - login: krishnardt count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 url: https://github.com/krishnardt +- login: adriangb + count: 30 + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 + url: https://github.com/adriangb - login: wshayes count: 29 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 @@ -77,10 +81,10 @@ experts: count: 29 avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 url: https://github.com/frankie567 -- login: adriangb - count: 28 - avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 - url: https://github.com/adriangb +- login: chbndrhnns + count: 25 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: ghandic count: 25 avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 @@ -89,18 +93,14 @@ experts: count: 25 avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4 url: https://github.com/dbanty -- login: chbndrhnns - count: 24 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns +- login: panla + count: 25 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla - login: SirTelemak count: 24 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak -- login: panla - count: 23 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 - url: https://github.com/panla - login: acnebs count: 22 avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4 @@ -129,22 +129,34 @@ experts: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4 url: https://github.com/nkhitrov +- login: acidjunk + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 + url: https://github.com/acidjunk - login: waynerv count: 16 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 url: https://github.com/waynerv -- login: acidjunk - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 - url: https://github.com/acidjunk - login: dstlny - count: 14 + count: 16 avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 url: https://github.com/dstlny +- login: jgould22 + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 + url: https://github.com/jgould22 +- login: harunyasar + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 + url: https://github.com/harunyasar - login: haizaar count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar +- login: hellocoldworld + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/47581948?v=4 + url: https://github.com/hellocoldworld - login: David-Lor count: 12 avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4 @@ -173,39 +185,47 @@ experts: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4 url: https://github.com/stefanondisponibile -- login: hellocoldworld - count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/47581948?v=4 - url: https://github.com/hellocoldworld - login: oligond count: 10 avatarUrl: https://avatars.githubusercontent.com/u/2858306?u=1bb1182a5944e93624b7fb26585f22c8f7a9d76e&v=4 url: https://github.com/oligond last_month_active: -- login: insomnes - count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 - url: https://github.com/insomnes -- login: raphaelauv - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 - url: https://github.com/raphaelauv -- login: jgould22 - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 - url: https://github.com/jgould22 - login: harunyasar - count: 4 + count: 10 avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 url: https://github.com/harunyasar +- login: jgould22 + count: 10 + avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 + url: https://github.com/jgould22 +- login: rafsaf + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 + url: https://github.com/rafsaf +- login: STeveShary + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 + url: https://github.com/STeveShary +- login: ahnaf-zamil + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/57180217?u=849128b146771ace47beca5b5ff68eb82905dd6d&v=4 + url: https://github.com/ahnaf-zamil +- login: lucastosetto + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/89307132?u=56326696423df7126c9e7c702ee58f294db69a2a&v=4 + url: https://github.com/lucastosetto +- login: blokje + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/851418?v=4 + url: https://github.com/blokje +- login: MatthijsKok + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/7658129?u=1243e32d57e13abc45e3f5235ed5b9197e0d2b41&v=4 + url: https://github.com/MatthijsKok - login: Kludex count: 3 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 url: https://github.com/Kludex -- login: panla - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 - url: https://github.com/panla top_contributors: - login: waynerv count: 25 @@ -219,14 +239,14 @@ top_contributors: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu +- login: jaystone776 + count: 15 + avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 + url: https://github.com/jaystone776 - login: euri10 count: 13 avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4 url: https://github.com/euri10 -- login: jaystone776 - count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 - url: https://github.com/jaystone776 - login: mariacamilagl count: 12 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 @@ -285,7 +305,7 @@ top_contributors: url: https://github.com/NinaHwang top_reviewers: - login: Kludex - count: 91 + count: 93 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 url: https://github.com/Kludex - login: waynerv @@ -301,7 +321,7 @@ top_reviewers: avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 url: https://github.com/tokusumi - login: ycd - count: 44 + count: 45 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: AdrianDeAnda @@ -312,12 +332,16 @@ top_reviewers: count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik +- login: cikay + count: 24 + avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 + url: https://github.com/cikay - login: dmontagu count: 23 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu - login: cassiobotaro - count: 22 + count: 23 avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 url: https://github.com/cassiobotaro - login: komtaki @@ -336,6 +360,10 @@ top_reviewers: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/21978760?v=4 url: https://github.com/yanever +- login: lsglucas + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 + url: https://github.com/lsglucas - login: SwftAlpc count: 16 avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4 @@ -356,26 +384,22 @@ top_reviewers: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4 url: https://github.com/delhi09 -- login: lsglucas - count: 14 - avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 - url: https://github.com/lsglucas - login: rjNemo - count: 13 + count: 14 avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 url: https://github.com/rjNemo - login: RunningIkkyu count: 12 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 url: https://github.com/RunningIkkyu +- login: yezz123 + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 + url: https://github.com/yezz123 - login: sh0nk count: 12 avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4 url: https://github.com/sh0nk -- login: yezz123 - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 - url: https://github.com/yezz123 - login: mariacamilagl count: 10 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 @@ -400,6 +424,10 @@ top_reviewers: count: 9 avatarUrl: https://avatars.githubusercontent.com/u/49435654?v=4 url: https://github.com/kty4119 +- login: zy7y + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4 + url: https://github.com/zy7y - login: bezaca count: 9 avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4 @@ -444,39 +472,31 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/34248814?v=4 url: https://github.com/krocdort +- login: dimaqq + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4 + url: https://github.com/dimaqq - login: jovicon count: 6 avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 url: https://github.com/jovicon +- login: NinaHwang + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 + url: https://github.com/NinaHwang - login: diogoduartec count: 5 avatarUrl: https://avatars.githubusercontent.com/u/31852339?u=b50fc11c531e9b77922e19edfc9e7233d4d7b92e&v=4 url: https://github.com/diogoduartec -- login: nimctl +- login: n25a count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4 - url: https://github.com/nimctl + avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=eb3c95338741c78fff7d9d5d7ace9617e53eee4a&v=4 + url: https://github.com/n25a +- login: izaguerreiro + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4 + url: https://github.com/izaguerreiro - login: israteneda count: 5 avatarUrl: https://avatars.githubusercontent.com/u/20668624?u=d7b2961d330aca65fbce5bdb26a0800a3d23ed2d&v=4 url: https://github.com/israteneda -- login: juntatalor - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4 - url: https://github.com/juntatalor -- login: SnkSynthesis - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/63564282?u=0078826509dbecb2fdb543f4e881c9cd06157893&v=4 - url: https://github.com/SnkSynthesis -- login: anthonycepeda - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 - url: https://github.com/anthonycepeda -- login: oandersonmagalhaes - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/83456692?v=4 - url: https://github.com/oandersonmagalhaes -- login: qysfblog - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/52229895?v=4 - url: https://github.com/qysfblog From b93f8a709ab3923d1268dbc845f41985c0302b33 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 1 Feb 2022 14:28:16 +0000 Subject: [PATCH 383/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 68b75e702..6d5ee8ea1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#4502](https://github.com/tiangolo/fastapi/pull/4502) by [@github-actions[bot]](https://github.com/apps/github-actions). ## 0.73.0 ### Features From 6034f80687302fa4f7da73cc3142750c3e239401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 13 Feb 2022 18:18:38 +0100 Subject: [PATCH 384/814] =?UTF-8?q?=F0=9F=92=9A=20Only=20build=20docs=20on?= =?UTF-8?q?=20push=20when=20on=20master=20to=20avoid=20duplicate=20runs=20?= =?UTF-8?q?from=20PRs=20(#4564)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-docs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index ccf964486..2482660f3 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -1,6 +1,8 @@ name: Build Docs on: push: + branches: + - master pull_request: types: [opened, synchronize] jobs: From 78b07cb809e97f400e196ff3d89862b9d5bd5dc2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 13 Feb 2022 17:19:09 +0000 Subject: [PATCH 385/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6d5ee8ea1..8c368e676 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 💚 Only build docs on push when on master to avoid duplicate runs from PRs. PR [#4564](https://github.com/tiangolo/fastapi/pull/4564) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#4502](https://github.com/tiangolo/fastapi/pull/4502) by [@github-actions[bot]](https://github.com/apps/github-actions). ## 0.73.0 From 9d56a3cb59d59896bc38293b9fa54ae69b7cd36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 17 Feb 2022 13:40:12 +0100 Subject: [PATCH 386/814] =?UTF-8?q?=E2=9C=A8=20Update=20internal=20`AsyncE?= =?UTF-8?q?xitStack`=20to=20fix=20context=20for=20dependencies=20with=20`y?= =?UTF-8?q?ield`=20(#4575)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dependencies/dependencies-with-yield.md | 10 +-- fastapi/applications.py | 61 +++++++++++++--- fastapi/middleware/asyncexitstack.py | 28 ++++++++ tests/test_dependency_contextmanager.py | 44 ++++++++++-- tests/test_dependency_contextvars.py | 51 +++++++++++++ tests/test_dependency_normal_exceptions.py | 71 +++++++++++++++++++ tests/test_exception_handlers.py | 23 ++++++ 7 files changed, 272 insertions(+), 16 deletions(-) create mode 100644 fastapi/middleware/asyncexitstack.py create mode 100644 tests/test_dependency_contextvars.py create mode 100644 tests/test_dependency_normal_exceptions.py diff --git a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md index 82553afae..ac2e9cb8c 100644 --- a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md @@ -99,7 +99,7 @@ You saw that you can use dependencies with `yield` and have `try` blocks that ca It might be tempting to raise an `HTTPException` or similar in the exit code, after the `yield`. But **it won't work**. -The exit code in dependencies with `yield` is executed *after* [Exception Handlers](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}. There's nothing catching exceptions thrown by your dependencies in the exit code (after the `yield`). +The exit code in dependencies with `yield` is executed *after* the response is sent, so [Exception Handlers](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} will have already run. There's nothing catching exceptions thrown by your dependencies in the exit code (after the `yield`). So, if you raise an `HTTPException` after the `yield`, the default (or any custom) exception handler that catches `HTTPException`s and returns an HTTP 400 response won't be there to catch that exception anymore. @@ -138,9 +138,11 @@ participant tasks as Background tasks end dep ->> operation: Run dependency, e.g. DB session opt raise - operation -->> handler: Raise HTTPException + operation -->> dep: Raise HTTPException + dep -->> handler: Auto forward exception handler -->> client: HTTP error response operation -->> dep: Raise other exception + dep -->> handler: Auto forward exception end operation ->> client: Return response to client Note over client,operation: Response is already sent, can't change it anymore @@ -162,9 +164,9 @@ participant tasks as Background tasks After one of those responses is sent, no other response can be sent. !!! tip - This diagram shows `HTTPException`, but you could also raise any other exception for which you create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}. And that exception would be handled by that custom exception handler instead of the dependency exit code. + This diagram shows `HTTPException`, but you could also raise any other exception for which you create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}. - But if you raise an exception that is not handled by the exception handlers, it will be handled by the exit code of the dependency. + If you raise any exception, it will be passed to the dependencies with yield, including `HTTPException`, and then **again** to the exception handlers. If there's no exception handler for that exception, it will then be handled by the default internal `ServerErrorMiddleware`, returning a 500 HTTP status code, to let the client know that there was an error in the server. ## Context Managers diff --git a/fastapi/applications.py b/fastapi/applications.py index dbfd76fb9..9fb78719c 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -2,7 +2,6 @@ from enum import Enum from typing import Any, Callable, Coroutine, Dict, List, Optional, Sequence, Type, Union from fastapi import routing -from fastapi.concurrency import AsyncExitStack from fastapi.datastructures import Default, DefaultPlaceholder from fastapi.encoders import DictIntStrAny, SetIntStr from fastapi.exception_handlers import ( @@ -11,6 +10,7 @@ from fastapi.exception_handlers import ( ) from fastapi.exceptions import RequestValidationError from fastapi.logger import logger +from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware from fastapi.openapi.docs import ( get_redoc_html, get_swagger_ui_html, @@ -21,8 +21,9 @@ from fastapi.params import Depends from fastapi.types import DecoratedCallable from starlette.applications import Starlette from starlette.datastructures import State -from starlette.exceptions import HTTPException +from starlette.exceptions import ExceptionMiddleware, HTTPException from starlette.middleware import Middleware +from starlette.middleware.errors import ServerErrorMiddleware from starlette.requests import Request from starlette.responses import HTMLResponse, JSONResponse, Response from starlette.routing import BaseRoute @@ -134,6 +135,55 @@ class FastAPI(Starlette): self.openapi_schema: Optional[Dict[str, Any]] = None self.setup() + def build_middleware_stack(self) -> ASGIApp: + # Duplicate/override from Starlette to add AsyncExitStackMiddleware + # inside of ExceptionMiddleware, inside of custom user middlewares + debug = self.debug + error_handler = None + exception_handlers = {} + + for key, value in self.exception_handlers.items(): + if key in (500, Exception): + error_handler = value + else: + exception_handlers[key] = value + + middleware = ( + [Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)] + + self.user_middleware + + [ + Middleware( + ExceptionMiddleware, handlers=exception_handlers, debug=debug + ), + # Add FastAPI-specific AsyncExitStackMiddleware for dependencies with + # contextvars. + # This needs to happen after user middlewares because those create a + # new contextvars context copy by using a new AnyIO task group. + # The initial part of dependencies with yield is executed in the + # FastAPI code, inside all the middlewares, but the teardown part + # (after yield) is executed in the AsyncExitStack in this middleware, + # if the AsyncExitStack lived outside of the custom middlewares and + # contextvars were set in a dependency with yield in that internal + # contextvars context, the values would not be available in the + # outside context of the AsyncExitStack. + # By putting the middleware and the AsyncExitStack here, inside all + # user middlewares, the code before and after yield in dependencies + # with yield is executed in the same contextvars context, so all values + # set in contextvars before yield is still available after yield as + # would be expected. + # Additionally, by having this AsyncExitStack here, after the + # ExceptionMiddleware, now dependencies can catch handled exceptions, + # e.g. HTTPException, to customize the teardown code (e.g. DB session + # rollback). + Middleware(AsyncExitStackMiddleware), + ] + ) + + app = self.router + for cls, options in reversed(middleware): + app = cls(app=app, **options) + return app + def openapi(self) -> Dict[str, Any]: if not self.openapi_schema: self.openapi_schema = get_openapi( @@ -206,12 +256,7 @@ class FastAPI(Starlette): async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if self.root_path: scope["root_path"] = self.root_path - if AsyncExitStack: - async with AsyncExitStack() as stack: - scope["fastapi_astack"] = stack - await super().__call__(scope, receive, send) - else: - await super().__call__(scope, receive, send) # pragma: no cover + await super().__call__(scope, receive, send) def add_api_route( self, diff --git a/fastapi/middleware/asyncexitstack.py b/fastapi/middleware/asyncexitstack.py new file mode 100644 index 000000000..503a68ac7 --- /dev/null +++ b/fastapi/middleware/asyncexitstack.py @@ -0,0 +1,28 @@ +from typing import Optional + +from fastapi.concurrency import AsyncExitStack +from starlette.types import ASGIApp, Receive, Scope, Send + + +class AsyncExitStackMiddleware: + def __init__(self, app: ASGIApp, context_name: str = "fastapi_astack") -> None: + self.app = app + self.context_name = context_name + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if AsyncExitStack: + dependency_exception: Optional[Exception] = None + async with AsyncExitStack() as stack: + scope[self.context_name] = stack + try: + await self.app(scope, receive, send) + except Exception as e: + dependency_exception = e + raise e + if dependency_exception: + # This exception was possibly handled by the dependency but it should + # still bubble up so that the ServerErrorMiddleware can return a 500 + # or the ExceptionMiddleware can catch and handle any other exceptions + raise dependency_exception + else: + await self.app(scope, receive, send) # pragma: no cover diff --git a/tests/test_dependency_contextmanager.py b/tests/test_dependency_contextmanager.py index 3e42b47f7..03ef56c4d 100644 --- a/tests/test_dependency_contextmanager.py +++ b/tests/test_dependency_contextmanager.py @@ -235,7 +235,16 @@ def test_sync_raise_other(): assert "/sync_raise" not in errors -def test_async_raise(): +def test_async_raise_raises(): + with pytest.raises(AsyncDependencyError): + client.get("/async_raise") + assert state["/async_raise"] == "asyncgen raise finalized" + assert "/async_raise" in errors + errors.clear() + + +def test_async_raise_server_error(): + client = TestClient(app, raise_server_exceptions=False) response = client.get("/async_raise") assert response.status_code == 500, response.text assert state["/async_raise"] == "asyncgen raise finalized" @@ -270,7 +279,16 @@ def test_background_tasks(): assert state["bg"] == "bg set - b: started b - a: started a" -def test_sync_raise(): +def test_sync_raise_raises(): + with pytest.raises(SyncDependencyError): + client.get("/sync_raise") + assert state["/sync_raise"] == "generator raise finalized" + assert "/sync_raise" in errors + errors.clear() + + +def test_sync_raise_server_error(): + client = TestClient(app, raise_server_exceptions=False) response = client.get("/sync_raise") assert response.status_code == 500, response.text assert state["/sync_raise"] == "generator raise finalized" @@ -306,7 +324,16 @@ def test_sync_sync_raise_other(): assert "/sync_raise" not in errors -def test_sync_async_raise(): +def test_sync_async_raise_raises(): + with pytest.raises(AsyncDependencyError): + client.get("/sync_async_raise") + assert state["/async_raise"] == "asyncgen raise finalized" + assert "/async_raise" in errors + errors.clear() + + +def test_sync_async_raise_server_error(): + client = TestClient(app, raise_server_exceptions=False) response = client.get("/sync_async_raise") assert response.status_code == 500, response.text assert state["/async_raise"] == "asyncgen raise finalized" @@ -314,7 +341,16 @@ def test_sync_async_raise(): errors.clear() -def test_sync_sync_raise(): +def test_sync_sync_raise_raises(): + with pytest.raises(SyncDependencyError): + client.get("/sync_sync_raise") + assert state["/sync_raise"] == "generator raise finalized" + assert "/sync_raise" in errors + errors.clear() + + +def test_sync_sync_raise_server_error(): + client = TestClient(app, raise_server_exceptions=False) response = client.get("/sync_sync_raise") assert response.status_code == 500, response.text assert state["/sync_raise"] == "generator raise finalized" diff --git a/tests/test_dependency_contextvars.py b/tests/test_dependency_contextvars.py new file mode 100644 index 000000000..076802df8 --- /dev/null +++ b/tests/test_dependency_contextvars.py @@ -0,0 +1,51 @@ +from contextvars import ContextVar +from typing import Any, Awaitable, Callable, Dict, Optional + +from fastapi import Depends, FastAPI, Request, Response +from fastapi.testclient import TestClient + +legacy_request_state_context_var: ContextVar[Optional[Dict[str, Any]]] = ContextVar( + "legacy_request_state_context_var", default=None +) + +app = FastAPI() + + +async def set_up_request_state_dependency(): + request_state = {"user": "deadpond"} + contextvar_token = legacy_request_state_context_var.set(request_state) + yield request_state + legacy_request_state_context_var.reset(contextvar_token) + + +@app.middleware("http") +async def custom_middleware( + request: Request, call_next: Callable[[Request], Awaitable[Response]] +): + response = await call_next(request) + response.headers["custom"] = "foo" + return response + + +@app.get("/user", dependencies=[Depends(set_up_request_state_dependency)]) +def get_user(): + request_state = legacy_request_state_context_var.get() + assert request_state + return request_state["user"] + + +client = TestClient(app) + + +def test_dependency_contextvars(): + """ + Check that custom middlewares don't affect the contextvar context for dependencies. + + The code before yield and the code after yield should be run in the same contextvar + context, so that request_state_context_var.reset(contextvar_token). + + If they are run in a different context, that raises an error. + """ + response = client.get("/user") + assert response.json() == "deadpond" + assert response.headers["custom"] == "foo" diff --git a/tests/test_dependency_normal_exceptions.py b/tests/test_dependency_normal_exceptions.py new file mode 100644 index 000000000..49a19f460 --- /dev/null +++ b/tests/test_dependency_normal_exceptions.py @@ -0,0 +1,71 @@ +import pytest +from fastapi import Body, Depends, FastAPI, HTTPException +from fastapi.testclient import TestClient + +initial_fake_database = {"rick": "Rick Sanchez"} + +fake_database = initial_fake_database.copy() + +initial_state = {"except": False, "finally": False} + +state = initial_state.copy() + +app = FastAPI() + + +async def get_database(): + temp_database = fake_database.copy() + try: + yield temp_database + fake_database.update(temp_database) + except HTTPException: + state["except"] = True + finally: + state["finally"] = True + + +@app.put("/invalid-user/{user_id}") +def put_invalid_user( + user_id: str, name: str = Body(...), db: dict = Depends(get_database) +): + db[user_id] = name + raise HTTPException(status_code=400, detail="Invalid user") + + +@app.put("/user/{user_id}") +def put_user(user_id: str, name: str = Body(...), db: dict = Depends(get_database)): + db[user_id] = name + return {"message": "OK"} + + +@pytest.fixture(autouse=True) +def reset_state_and_db(): + global fake_database + global state + fake_database = initial_fake_database.copy() + state = initial_state.copy() + + +client = TestClient(app) + + +def test_dependency_gets_exception(): + assert state["except"] is False + assert state["finally"] is False + response = client.put("/invalid-user/rick", json="Morty") + assert response.status_code == 400, response.text + assert response.json() == {"detail": "Invalid user"} + assert state["except"] is True + assert state["finally"] is True + assert fake_database["rick"] == "Rick Sanchez" + + +def test_dependency_no_exception(): + assert state["except"] is False + assert state["finally"] is False + response = client.put("/user/rick", json="Morty") + assert response.status_code == 200, response.text + assert response.json() == {"message": "OK"} + assert state["except"] is False + assert state["finally"] is True + assert fake_database["rick"] == "Morty" diff --git a/tests/test_exception_handlers.py b/tests/test_exception_handlers.py index 6153f7ab9..67a4becec 100644 --- a/tests/test_exception_handlers.py +++ b/tests/test_exception_handlers.py @@ -1,3 +1,4 @@ +import pytest from fastapi import FastAPI, HTTPException from fastapi.exceptions import RequestValidationError from fastapi.testclient import TestClient @@ -12,10 +13,15 @@ def request_validation_exception_handler(request, exception): return JSONResponse({"exception": "request-validation"}) +def server_error_exception_handler(request, exception): + return JSONResponse(status_code=500, content={"exception": "server-error"}) + + app = FastAPI( exception_handlers={ HTTPException: http_exception_handler, RequestValidationError: request_validation_exception_handler, + Exception: server_error_exception_handler, } ) @@ -32,6 +38,11 @@ def route_with_request_validation_exception(param: int): pass # pragma: no cover +@app.get("/server-error") +def route_with_server_error(): + raise RuntimeError("Oops!") + + def test_override_http_exception(): response = client.get("/http-exception") assert response.status_code == 200 @@ -42,3 +53,15 @@ def test_override_request_validation_exception(): response = client.get("/request-validation/invalid") assert response.status_code == 200 assert response.json() == {"exception": "request-validation"} + + +def test_override_server_error_exception_raises(): + with pytest.raises(RuntimeError): + client.get("/server-error") + + +def test_override_server_error_exception_response(): + client = TestClient(app, raise_server_exceptions=False) + response = client.get("/server-error") + assert response.status_code == 500 + assert response.json() == {"exception": "server-error"} From 4fcb00328c2b6c2ab5167359b7f62b1c481e1faf Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Feb 2022 12:40:46 +0000 Subject: [PATCH 387/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8c368e676..b23dc1b98 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Update internal `AsyncExitStack` to fix context for dependencies with `yield`. PR [#4575](https://github.com/tiangolo/fastapi/pull/4575) by [@tiangolo](https://github.com/tiangolo). * 💚 Only build docs on push when on master to avoid duplicate runs from PRs. PR [#4564](https://github.com/tiangolo/fastapi/pull/4564) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#4502](https://github.com/tiangolo/fastapi/pull/4502) by [@github-actions[bot]](https://github.com/apps/github-actions). ## 0.73.0 From 59e36481dc86673968c21cf9ea636eb3f379dc64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 17 Feb 2022 15:18:01 +0100 Subject: [PATCH 388/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20Striveworks=20spon?= =?UTF-8?q?sor=20(#4596)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/en/data/sponsors.yml | 3 +++ docs/en/data/sponsors_badge.yml | 1 + .../en/docs/img/sponsors/striveworks-banner.png | Bin 0 -> 9681 bytes docs/en/docs/img/sponsors/striveworks.png | Bin 0 -> 22639 bytes docs/en/overrides/main.html | 6 ++++++ 6 files changed, 11 insertions(+) create mode 100644 docs/en/docs/img/sponsors/striveworks-banner.png create mode 100644 docs/en/docs/img/sponsors/striveworks.png diff --git a/README.md b/README.md index c9c69d3e8..bec58aad1 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index b98e68b65..4d63a7288 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -8,6 +8,9 @@ gold: - url: https://www.dropbase.io/careers title: Dropbase - seamlessly collect, clean, and centralize data. img: https://fastapi.tiangolo.com/img/sponsors/dropbase.svg + - url: https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings + title: https://striveworks.us/careers + img: https://fastapi.tiangolo.com/img/sponsors/striveworks.png silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index 0c4e716d7..dbf69c1b3 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -8,3 +8,4 @@ logins: - deepset-ai - cryptapi - DropbaseHQ + - Striveworks diff --git a/docs/en/docs/img/sponsors/striveworks-banner.png b/docs/en/docs/img/sponsors/striveworks-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..5206744b7a6e45b8c541ea55941f47f84a63eaec GIT binary patch literal 9681 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/sponsors/striveworks.png b/docs/en/docs/img/sponsors/striveworks.png new file mode 100644 index 0000000000000000000000000000000000000000..435ac536c14eacdd5c4f578d56495281c53261d6 GIT binary patch literal 22639 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
+
{% endblock %} From 2d2f1dee5d0c2c03a3d1b7ba969896a1534b43ab Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Feb 2022 14:18:35 +0000 Subject: [PATCH 389/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b23dc1b98..e14b4cdfd 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add Striveworks sponsor. PR [#4596](https://github.com/tiangolo/fastapi/pull/4596) by [@tiangolo](https://github.com/tiangolo). * ✨ Update internal `AsyncExitStack` to fix context for dependencies with `yield`. PR [#4575](https://github.com/tiangolo/fastapi/pull/4575) by [@tiangolo](https://github.com/tiangolo). * 💚 Only build docs on push when on master to avoid duplicate runs from PRs. PR [#4564](https://github.com/tiangolo/fastapi/pull/4564) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#4502](https://github.com/tiangolo/fastapi/pull/4502) by [@github-actions[bot]](https://github.com/apps/github-actions). From 03d4d4c38e28464a5b3ad41d69548009b5c45289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 17 Feb 2022 17:05:38 +0100 Subject: [PATCH 390/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 66 ++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e14b4cdfd..3898eb62e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,10 +2,74 @@ ## Latest Changes -* 🔧 Add Striveworks sponsor. PR [#4596](https://github.com/tiangolo/fastapi/pull/4596) by [@tiangolo](https://github.com/tiangolo). +### Breaking Changes + * ✨ Update internal `AsyncExitStack` to fix context for dependencies with `yield`. PR [#4575](https://github.com/tiangolo/fastapi/pull/4575) by [@tiangolo](https://github.com/tiangolo). + +Dependencies with `yield` can now catch `HTTPException` and custom exceptions. For example: + +```Python +async def get_database(): + with Session() as session: + try: + yield session + except HTTPException: + session.rollback() + raise + finally: + session.close() +``` + +After the dependency with `yield` handles the exception (or not) the exception is raised again. So that any exception handlers can catch it, or ultimately the default internal `ServerErrorMiddleware`. + +If you depended on exceptions not being received by dependencies with `yield`, and receiving an exception breaks the code after `yield`, you can use a block with `try` and `finally`: + +```Python +async def do_something(): + try: + yield something + finally: + some_cleanup() +``` + +...that way the `finally` block is run regardless of any exception that might happen. + +### Features + +* The same PR [#4575](https://github.com/tiangolo/fastapi/pull/4575) from above also fixes the `contextvars` context for the code before and after `yield`. This was the main objective of that PR. + +This means that now, if you set a value in a context variable before `yield`, the value would still be available after `yield` (as you would intuitively expect). And it also means that you can reset the context variable with a token afterwards. + +For example, this works correctly now: + +```Python +from contextvars import ContextVar +from typing import Any, Dict, Optional + + +legacy_request_state_context_var: ContextVar[Optional[Dict[str, Any]]] = ContextVar( + "legacy_request_state_context_var", default=None +) + +async def set_up_request_state_dependency(): + request_state = {"user": "deadpond"} + contextvar_token = legacy_request_state_context_var.set(request_state) + yield request_state + legacy_request_state_context_var.reset(contextvar_token) +``` + +...before this change it would raise an error when resetting the context variable, because the `contextvars` context was different, because of the way it was implemented. + +**Note**: You probably don't need `contextvars`, and you should probably avoid using them. But they are powerful and useful in some advanced scenarios, for example, migrating from code that used Flask's `g` semi-global variable. + +**Technical Details**: If you want to know more of the technical details you can check out the PR description [#4575](https://github.com/tiangolo/fastapi/pull/4575). + +### Internal + +* 🔧 Add Striveworks sponsor. PR [#4596](https://github.com/tiangolo/fastapi/pull/4596) by [@tiangolo](https://github.com/tiangolo). * 💚 Only build docs on push when on master to avoid duplicate runs from PRs. PR [#4564](https://github.com/tiangolo/fastapi/pull/4564) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#4502](https://github.com/tiangolo/fastapi/pull/4502) by [@github-actions[bot]](https://github.com/apps/github-actions). + ## 0.73.0 ### Features From 1ce16c2f40a75a4d97233bf4e331ed563eda47cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 17 Feb 2022 17:08:23 +0100 Subject: [PATCH 391/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.74?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3898eb62e..64f9dde64 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.74.0 + ### Breaking Changes * ✨ Update internal `AsyncExitStack` to fix context for dependencies with `yield`. PR [#4575](https://github.com/tiangolo/fastapi/pull/4575) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 8718788fa..5772e7ec8 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.73.0" +__version__ = "0.74.0" from starlette import status as status From f5d7df3c6ce0b7184404a87195393a48e1c6d2c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 21 Feb 2022 16:51:26 +0100 Subject: [PATCH 392/814] =?UTF-8?q?=E2=9C=A8=20Include=20route=20in=20scop?= =?UTF-8?q?e=20to=20allow=20middleware=20and=20other=20tools=20to=20extrac?= =?UTF-8?q?t=20its=20information=20(#4603)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/routing.py | 17 +++++++++++-- tests/test_route_scope.py | 50 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 tests/test_route_scope.py diff --git a/fastapi/routing.py b/fastapi/routing.py index f6d5370d6..7dae04521 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -13,6 +13,7 @@ from typing import ( Optional, Sequence, Set, + Tuple, Type, Union, ) @@ -44,7 +45,7 @@ from starlette.concurrency import run_in_threadpool from starlette.exceptions import HTTPException from starlette.requests import Request from starlette.responses import JSONResponse, Response -from starlette.routing import BaseRoute +from starlette.routing import BaseRoute, Match from starlette.routing import Mount as Mount # noqa from starlette.routing import ( compile_path, @@ -53,7 +54,7 @@ from starlette.routing import ( websocket_session, ) from starlette.status import WS_1008_POLICY_VIOLATION -from starlette.types import ASGIApp +from starlette.types import ASGIApp, Scope from starlette.websockets import WebSocket @@ -296,6 +297,12 @@ class APIWebSocketRoute(routing.WebSocketRoute): ) self.path_regex, self.path_format, self.param_convertors = compile_path(path) + def matches(self, scope: Scope) -> Tuple[Match, Scope]: + match, child_scope = super().matches(scope) + if match != Match.NONE: + child_scope["route"] = self + return match, child_scope + class APIRoute(routing.Route): def __init__( @@ -432,6 +439,12 @@ class APIRoute(routing.Route): dependency_overrides_provider=self.dependency_overrides_provider, ) + def matches(self, scope: Scope) -> Tuple[Match, Scope]: + match, child_scope = super().matches(scope) + if match != Match.NONE: + child_scope["route"] = self + return match, child_scope + class APIRouter(routing.Router): def __init__( diff --git a/tests/test_route_scope.py b/tests/test_route_scope.py new file mode 100644 index 000000000..a188e9a5f --- /dev/null +++ b/tests/test_route_scope.py @@ -0,0 +1,50 @@ +import pytest +from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect +from fastapi.routing import APIRoute, APIWebSocketRoute +from fastapi.testclient import TestClient + +app = FastAPI() + + +@app.get("/users/{user_id}") +async def get_user(user_id: str, request: Request): + route: APIRoute = request.scope["route"] + return {"user_id": user_id, "path": route.path} + + +@app.websocket("/items/{item_id}") +async def websocket_item(item_id: str, websocket: WebSocket): + route: APIWebSocketRoute = websocket.scope["route"] + await websocket.accept() + await websocket.send_json({"item_id": item_id, "path": route.path}) + + +client = TestClient(app) + + +def test_get(): + response = client.get("/users/rick") + assert response.status_code == 200, response.text + assert response.json() == {"user_id": "rick", "path": "/users/{user_id}"} + + +def test_invalid_method_doesnt_match(): + response = client.post("/users/rick") + assert response.status_code == 405, response.text + + +def test_invalid_path_doesnt_match(): + response = client.post("/usersx/rick") + assert response.status_code == 404, response.text + + +def test_websocket(): + with client.websocket_connect("/items/portal-gun") as websocket: + data = websocket.receive_json() + assert data == {"item_id": "portal-gun", "path": "/items/{item_id}"} + + +def test_websocket_invalid_path_doesnt_match(): + with pytest.raises(WebSocketDisconnect): + with client.websocket_connect("/itemsx/portal-gun") as websocket: + websocket.receive_json() From e95305905406e447223e35ee748f61b32de135fb Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Feb 2022 15:52:03 +0000 Subject: [PATCH 393/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 64f9dde64..78265815e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Include route in scope to allow middleware and other tools to extract its information. PR [#4603](https://github.com/tiangolo/fastapi/pull/4603) by [@tiangolo](https://github.com/tiangolo). ## 0.74.0 From 440d2d2d1a72867b3f38b5c7359e021cccbfea8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 21 Feb 2022 16:54:18 +0100 Subject: [PATCH 394/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.74?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 5 +++++ fastapi/__init__.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 78265815e..c5ca7376d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,11 @@ ## Latest Changes + +## 0.74.1 + +### Features + * ✨ Include route in scope to allow middleware and other tools to extract its information. PR [#4603](https://github.com/tiangolo/fastapi/pull/4603) by [@tiangolo](https://github.com/tiangolo). ## 0.74.0 diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 5772e7ec8..dc265558a 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.74.0" +__version__ = "0.74.1" from starlette import status as status From 8a0d4c79c18e6bd219b965b9d50578c139e7efd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 4 Mar 2022 14:02:18 -0800 Subject: [PATCH 395/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20custo?= =?UTF-8?q?m=20`generate=5Funique=5Fid=5Ffunction`=20and=20docs=20for=20ge?= =?UTF-8?q?nerating=20clients=20(#4650)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/generate-clients.md | 267 +++ .../img/tutorial/generate-clients/image01.png | Bin 0 -> 78022 bytes .../img/tutorial/generate-clients/image02.png | Bin 0 -> 59828 bytes .../img/tutorial/generate-clients/image03.png | Bin 0 -> 61043 bytes .../img/tutorial/generate-clients/image04.png | Bin 0 -> 53853 bytes .../img/tutorial/generate-clients/image05.png | Bin 0 -> 31091 bytes .../img/tutorial/generate-clients/image06.png | Bin 0 -> 43434 bytes .../img/tutorial/generate-clients/image07.png | Bin 0 -> 49947 bytes .../img/tutorial/generate-clients/image08.png | Bin 0 -> 30019 bytes docs/en/mkdocs.yml | 1 + docs_src/generate_clients/tutorial001.py | 28 + docs_src/generate_clients/tutorial001_py39.py | 26 + docs_src/generate_clients/tutorial002.py | 38 + docs_src/generate_clients/tutorial002_py39.py | 36 + docs_src/generate_clients/tutorial003.py | 44 + docs_src/generate_clients/tutorial003_py39.py | 42 + docs_src/generate_clients/tutorial004.py | 15 + fastapi/applications.py | 114 +- fastapi/openapi/utils.py | 41 +- fastapi/routing.py | 117 +- fastapi/utils.py | 24 +- tests/test_generate_unique_id_function.py | 1617 +++++++++++++++++ .../test_include_router_defaults_overrides.py | 8 +- .../test_generate_clients/__init__.py | 0 .../test_generate_clients/test_tutorial003.py | 188 ++ 25 files changed, 2536 insertions(+), 70 deletions(-) create mode 100644 docs/en/docs/advanced/generate-clients.md create mode 100644 docs/en/docs/img/tutorial/generate-clients/image01.png create mode 100644 docs/en/docs/img/tutorial/generate-clients/image02.png create mode 100644 docs/en/docs/img/tutorial/generate-clients/image03.png create mode 100644 docs/en/docs/img/tutorial/generate-clients/image04.png create mode 100644 docs/en/docs/img/tutorial/generate-clients/image05.png create mode 100644 docs/en/docs/img/tutorial/generate-clients/image06.png create mode 100644 docs/en/docs/img/tutorial/generate-clients/image07.png create mode 100644 docs/en/docs/img/tutorial/generate-clients/image08.png create mode 100644 docs_src/generate_clients/tutorial001.py create mode 100644 docs_src/generate_clients/tutorial001_py39.py create mode 100644 docs_src/generate_clients/tutorial002.py create mode 100644 docs_src/generate_clients/tutorial002_py39.py create mode 100644 docs_src/generate_clients/tutorial003.py create mode 100644 docs_src/generate_clients/tutorial003_py39.py create mode 100644 docs_src/generate_clients/tutorial004.py create mode 100644 tests/test_generate_unique_id_function.py create mode 100644 tests/test_tutorial/test_generate_clients/__init__.py create mode 100644 tests/test_tutorial/test_generate_clients/test_tutorial003.py diff --git a/docs/en/docs/advanced/generate-clients.md b/docs/en/docs/advanced/generate-clients.md new file mode 100644 index 000000000..f31a248d0 --- /dev/null +++ b/docs/en/docs/advanced/generate-clients.md @@ -0,0 +1,267 @@ +# Generate Clients + +As **FastAPI** is based on the OpenAPI specification, you get automatic compatibility with many tools, including the automatic API docs (provided by Swagger UI). + +One particular advantage that is not necessarily obvious is that you can **generate clients** (sometimes called **SDKs** ) for your API, for many different **programming languages**. + +## OpenAPI Client Generators + +There are many tools to generate clients from **OpenAPI**. + +A common tool is OpenAPI Generator. + +If you are building a **frontend**, a very interesting alternative is openapi-typescript-codegen. + +## Generate a TypeScript Frontend Client + +Let's start with a simple FastAPI application: + +=== "Python 3.6 and above" + + ```Python hl_lines="9-11 14-15 18 19 23" + {!> ../../../docs_src/generate_clients/tutorial001.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="7-9 12-13 16-17 21" + {!> ../../../docs_src/generate_clients/tutorial001_py39.py!} + ``` + +Notice that the *path operations* define the models they use for request payload and response payload, using the models `Item` and `ResponseMessage`. + +### API Docs + +If you go to the API docs, you will see that it has the **schemas** for the data to be sent in requests and received in responses: + + + +You can see those schemas because they were declared with the models in the app. + +That information is available in the app's **OpenAPI schema**, and then shown in the API docs (by Swagger UI). + +And that same information from the models that is included in OpenAPI is what can be used to **generate the client code**. + +### Generate a TypeScript Client + +Now that we have the app with the models, we can generate the client code for the frontend. + +#### Install `openapi-typescript-codegen` + +You can install `openapi-typescript-codegen` in your frontend code with: + +
+ +```console +$ npm install openapi-typescript-codegen --save-dev + +---> 100% +``` + +
+ +#### Generate Client Code + +To generate the client code you can use the command line application `openapi` that would now be installed. + +Because it is installed in the local project, you probably wouldn't be able to call that command directly, but you would put it on your `package.json` file. + +It could look like this: + +```JSON hl_lines="7" +{ + "name": "frontend-app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios" + }, + "author": "", + "license": "", + "devDependencies": { + "openapi-typescript-codegen": "^0.20.1", + "typescript": "^4.6.2" + } +} +``` + +After having that NPM `generate-client` script there, you can run it with: + +
+ +```console +$ npm run generate-client + +frontend-app@1.0.0 generate-client /home/user/code/frontend-app +> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios +``` + +
+ +That command will generate code in `./src/client` and will use `axios` (the frontend HTTP library) internally. + +### Try Out the Client Code + +Now you can import and use the client code, it could look like this, notice that you get autocompletion for the methods: + + + +You will also get autocompletion for the payload to send: + + + +!!! tip + Notice the autocompletion for `name` and `price`, that was defined in the FastAPI application, in the `Item` model. + +You will have inline errors for the data that you send: + + + +The response object will also have autocompletion: + + + +## FastAPI App with Tags + +In many cases your FastAPI app will be bigger, and you will probably use tags to separate different groups of *path operations*. + +For example, you could have a section for **items** and another section for **users**, and they could be separated by tags: + + +=== "Python 3.6 and above" + + ```Python hl_lines="23 28 36" + {!> ../../../docs_src/generate_clients/tutorial002.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="21 26 34" + {!> ../../../docs_src/generate_clients/tutorial002_py39.py!} + ``` + +### Generate a TypeScript Client with Tags + +If you generate a client for a FastAPI app using tags, it will normally also separate the client code based on the tags. + +This way you will be able to have things ordered and grouped correctly for the client code: + + + +In this case you have: + +* `ItemsService` +* `UsersService` + +### Client Method Names + +Right now the generated method names like `createItemItemsPost` don't look very clean: + +```TypeScript +ItemsService.createItemItemsPost({name: "Plumbus", price: 5}) +``` + +...that's because the client generator uses the OpenAPI internal **operation ID** for each *path operation*. + +OpenAPI requires that each operation ID is unique across all the *path operations*, so FastAPI uses the **function name**, the **path**, and the **HTTP method/operation** to generate that operation ID, because that way it can make sure that the operation IDs are unique. + +But I'll show you how to improve that next. 🤓 + +## Custom Operation IDs and Better Method Names + +You can **modify** the way these operation IDs are **generated** to make them simpler and have **simpler method names** in the clients. + +In this case you will have to ensure that each operation ID is **unique** in some other way. + +For example, you could make sure that each *path operation* has a tag, and then generate the operation ID based on the **tag** and the *path operation* **name** (the function name). + +### Custom Generate Unique ID Function + +FastAPI uses a **unique ID** for each *path operation*, it is used for the **operation ID** and also for the names of any needed custom models, for requests or responses. + +You can customize that function. It takes an `APIRoute` and outputs a string. + +For example, here it is using the first tag (you will probably have only one tag) and the *path operation* name (the function name). + +You can then pass that custom function to **FastAPI** as the `generate_unique_id_function` parameter: + +=== "Python 3.6 and above" + + ```Python hl_lines="8-9 12" + {!> ../../../docs_src/generate_clients/tutorial003.py!} + ``` + +=== "Python 3.9 and above" + + ```Python hl_lines="6-7 10" + {!> ../../../docs_src/generate_clients/tutorial003_py39.py!} + ``` + +### Generate a TypeScript Client with Custom Operation IDs + +Now if you generate the client again, you will see that it has the improved method names: + + + +As you see, the method names now have the tag and then the function name, now they don't include information from the URL path and the HTTP operation. + +### Preprocess the OpenAPI Specification for the Client Generator + +The generated code still has some **duplicated information**. + +We already know that this method is related to the **items** because that word is in the `ItemsService` (taken from the tag), but we still have the tag name prefixed in the method name too. 😕 + +We will probably still want to keep it for OpenAPI in general, as that will ensure that the operation IDs are **unique**. + +But for the generated client we could **modify** the OpenAPI operation IDs right before generating the clients, just to make those method names nicer and **cleaner**. + +We could download the OpenAPI JSON to a file `openapi.json` and then we could **remove that prefixed tag** with a script like this: + +```Python +{!../../../docs_src/generate_clients/tutorial004.py!} +``` + +With that, the operation IDs would be renamed from things like `items-get_items` to just `get_items`, that way the client generator can generate simpler method names. + +### Generate a TypeScript Client with the Preprocessed OpenAPI + +Now as the end result is in a file `openapi.json`, you would modify the `package.json` to use that local file, for example: + +```JSON hl_lines="7" +{ + "name": "frontend-app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "generate-client": "openapi --input ./openapi.json --output ./src/client --client axios" + }, + "author": "", + "license": "", + "devDependencies": { + "openapi-typescript-codegen": "^0.20.1", + "typescript": "^4.6.2" + } +} +``` + +After generating the new client, you would now have **clean method names**, with all the **autocompletion**, **inline errors**, etc: + + + +## Benefits + +When using the automatically generated clients you would **autocompletion** for: + +* Methods. +* Request payloads in the body, query parameters, etc. +* Response payloads. + +You would also have **inline errors** for everything. + +And whenever you update the backend code, and **regenerate** the frontend, it would have any new *path operations* available as methods, the old ones removed, and any other change would be reflected on the generated code. 🤓 + +This also means that if something changed it will be **reflected** on the client code automatically. And if you **build** the client it will error out if you have any **mismatch** in the data used. + +So, you would **detect many errors** very early in the development cycle instead of having to wait for the errors to show up to your final users in production and then trying to debug where the problem is. ✨ diff --git a/docs/en/docs/img/tutorial/generate-clients/image01.png b/docs/en/docs/img/tutorial/generate-clients/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..f23d57773c8f4274b03750a231ca28700c17cd26 GIT binary patch literal 78022 zcmb5Vbx<5%&@K!K?g@n8gaiv7++BjZI|K>t4vPeLcMmR$FTo|~qQQc@yDp2~CBOH* z_rI^|qiUd-IdkSrpO&Y)p9xn|kitYGLW6^Y!<7Cit^x=5x(f~tffNM^b|!w3Vhi>M z!C6#V4F&e&gYqp5_CJn`gqDk{y}66Kv6C5`s->%oi&JlgvKX620zbyCgBt%N4@@6c*e&sIBVr#!5*Kc)EN6!jYv3|M!GKi>M z*c1*Ki%e+@wd;7%U9Da4`|-Q~x#+k*@tuQ&C!rM160XH%pKe|Ae{T9sHL!U-StP4D zL+($Cl{y{q?{PSyVX`XHJL^9_zoUh6UU;eD~BE z57xP8X~Vj@K9uoL5TQhC1W8ti0Ow3u5lxtDREH%%C z3lS0N4G|IbyZ>er=PAeY4|?@_a{u+urXQ9FS6;r$29+xC>H_zG=fffc)$K1<|HSxv z%SY;!18TO0lu?|vl}wlyV)&)gk*|#=j2wCw2X^g2T6LlLji^R0wD8s^_+>r2d<7w7fD7sV7~%oG z)3I(7&Q#RS(>A`)+Rgs++eAeT>-6i{PHlB{z@ei^K=#rSi5?S8sSyhiDkf&)E*knI zP7(&3axQYl-4n*Y4d7WV<9gS4rqLMOT)g7*=*sJQ@U=vtw(atSge>PA2kvEVg=`ZZ zAMSWALqNMRf{}#snFs$*N^%-{dR+DE!7w@|dc+^)VBBtOw)_{jD`+A$aA` zy8O+|47bzzJvpGwAD1TK(F~hC-NT{((+r*NVv}v!7gJtMJwKj+0O~(~{>-;qV8bS^ zl$0)bqNrZgiQDknmaux;YRl0i45q`?lw7eeUcLatM~QpKT+gNl;|5 zp0#Np!erEGFd9zMz1`ZxPIntv{`oVja&ngl18K$czVok*+e-Q+)30Bi;t~>X-;gmu zlnhNe3~G~ZZk%;OP|kTjsqHk`!XkQ2V$>o2C&o89}^ zIB(v>EZbRJAJ}_XjCp&s8^B3M5sW=Tmc=6RC$(%j@tNt|PoyJ~Phc ziq^iJBUHfq=9R2{nYX%yvG`xyMl-<}0LuyD3kfQ}m<%OX<6c%)>PnEv9fFP_YOt=UOM@)( zMg+Ps3(#Hs49Ln4=%?<8iST2F@WQ~`J$M8tblfC}v=M>jcZ1{LDh)UdyzMNzDFa~Y zk00XZqh8TI70F}Srk)SAQarwQ?6RqhG^}+zz_tgj6b5J@x!(h7fWdWY`-7PUfKj`?UtLQamzR|l5kg~p=1=@xy*zHRPo1pqg&G6&AC z11g#0v++gn-sa1q`$OQ+x2^5eC&^Yf+sE}Lx=XoCH)8i?o@mfYPVf09P4juk&;w+2 zUM|OnO?!SGgOD{X>xjgB+z&TfL)J?Gw87;9>^wJQz<&|%c_*jc62WYxwr<7A<2yh+ z)7CrXUw3q{AR87L4;TkvZP3yh{T@_?+x@ZDdfJ)`{~EdWsnyk~!#Te9R1A9zj@DVx z!Bxzm9l@yN(neTS{av)An3@_oTwsvc-fR`${`WFU8glv-k!jY`vIu(MQFl{S=5X6A z@YyJaOkjAjPzwGp=v1@1qXk=2-<9e`-u(O|Fr{e91=Rzd?YEh@XlMqWpZ?gj>`Tu2 zLIj{tjf=~wqm}khm|~r0!RfsniI)6SrPJpyr|+IOY5BL|bM>F=F9fe94qrb27G-RI zx3%%-cs~IjwxJf4tvupI6UJnA;!R0cVI>_2yO2jb7Xz)p%WZ>c=%b z#!r#SnQ1TGd%A;?v7@LUy)VvwV}o+-a;)~-q($1R*MuyV4(T|0Z~Z_vF%_bR_RG1a zdPlow8Xywa<8zu^2KTOtKM(|=r>(@ciwp33F1Tj{EiHtA0FhfCL3Sccm}Xx^O{-{1 zmornW<2>I%Dp`S^?FL?ulRg3WRq6Yi;|CGjXM5y_)A{BvFqIp3urO zWN&hFXn5@Ane;s<{d`W*1ZEpi#6l?&xxPKSxqu;J`={6kA9|QGlIiU5h3;h9|7uYr z*I;u;T_Zl9}4u%`~lE_%{(D}3Pj zw<&;^k40Tr7;aKo`9fDOyrpGeJ&;U?at-Yzh`hPq3o2NACo9UbhTTau^*dPoBCPNw zCd<*=4|Qq93PHd1dSE0>S~6UMM(wsikKVADUuY(0&B`|A$V+0TkQObe+9+6HI?%KJB$Huu3wB+7L&|L76LBQLfj}f%=8y4+qJa zFgFuv-@O@aHv%bH$v-O_wVT4P-)1eSI36_(y(-3$Z_~*{&Vn|d2_|*UGZfCH< zbJ@IX=eJN3pUY|U?I>;X;n@CpU@ZF_=9zm!qBENzIjxgcjaR3usqYOu!Y68!kg!Pn zN6mXpzTmzG{gS!H`-Vl=k+)V>)25zY@{{AXao!$>yt87Y;lal`8PqsxPD4p~n>E+l z+w(BROhpBGsMfBZ?Tm%r#fVauQqCN%j_9~M1>{`nNP|y(-ItY@)tIZg{<&V1@)brX zgra$29TYR}e$Z+L$_I4Jm{-)eg6h7%=Z8ZM{gIy~cP?}f`nFcll~f}zS&M>?5c#%1Jg;HGZFS^+F0x9Xz#v@ zN&P$uDid)-gASwVK+O7-;`{Ss&}uR)Mw5crjC*cb;hSMQ^W%ru4AVVK6S+Mv)RK3Z zzkAv)7jrmff@=I8vH5RGq?$Kl7Qdvwnui?vF?4tHLzdV)_{rQ(SHvVG&65v4^Y9P? z=fKGVUT2r%e8Z0qfH!FY|(;ltVqyodgQ8!`ALB+*2_w4ojtOq!in4KLwwa)+xQ*S1Jbamxf2_Tj6hsKh0A6`4H`nuO! zZ4>DQGxhZLp5qGvx#;K;{2uQT(mV(xl=n!8BbV(UAT=^>hqyPNLSWd8izyWyI2YM% z^nss03YY@qrpc=|s1J$%B;{Zhd$N1Hp+{U>o1MnHt>L%Qkv%fPz<|$|NUhLyczvg< z!N$rOzS@|1f6|`WXg#-n?KR(YY=Hp}FPG&ZP;Wk3?IbXNjOg>!mnxUd8=SSIheay0 z1;ehNXlVyKqsm7%-CChriNQY0qy#X$h$2UU;}>Wec>Q0$r!L@x78 zwcuHW_9Ct&z%8;Cb6`oq&u&=2!*G>xe&oYL8*Bbw8&qoQV%K!YtlH#b6SL!LyZaZn z5lc07DjJ&5YoP}&s+dG+-^L2=Jpv<2?3;D0Fa?jr(ce<};O2OXm_MV;@rgU0O zHaw(!Zd()iznyd~08px&r6oOTx#kXo*EIv16dykLOOg47)zm1#09$A*<@qhHV(LCp zhYxh_>I4=_=6rXt^9}*G@zzpNYpp7=HoS%c@FVGL@1qNh50Z3iwHPQVDPg|jf#O&B zr4RSBsgv_%8tXN_-LGxxN)37#daZcpKQ+ac_O#YJ;&BE~26#|@_39P3-va`3=Y^sM z(7;*Rmx4yFIe%%6dG>?Wi(%qK=VqOTsd$TJHj&bi8kc;ZGH*n)`#dx-I6Qpe9x6zj z#33#&4of%~d9xLo#9v#mrr(~2y1ocrtJO_EdiTwH4M|C_cRS@P$;0X6g4js_fP=no z$iIYcxdmtUqf^He!L;?o^u9}j?Ogm${N&co4&E|)rGK{(B|CdmS69JFUE}c`!@){T zzL*j_+V}7KS`6lPzo67GQ-UQ2z*+u{KYV0r%(uhm!Y?aM0Q8Yl!lm+eP_eKKlDmO3 znbtw;;m0K4zhCCwkdY~L%nS#-Mot%eTxShZQa2-;M4^>=jG1646naSzM9194#pd4~ z)T1}RqGh?x`@IBm+tPb*iq-jy63>T!LG)wdB`LfmU2b_i(c1!LKySq@sYX(P6v8w# zKoSe-MQoNIU@3AIGaT~ZnwluP)eMo5!sjP=sjAFR0VEhNb%x0`(VDE&uW;2@TiVPV zl;WR?fhQ7`2|cm!(g-T`1f7FrqQ_ql(BZi@^PUkCh~-y0|8 zGF!+T4hsW=l7U^%N-|9LD=b%{R?SoUS2_7{D>n5V53x!iRHLHTlD%LK+@&e17cpYa z76SKrOcdE5_I>PJ(1B`^$-m*h$!XxE*uT>?e)vuPLr^$YP?*W-#VSR^gs7v{{yp+# z9O}RL@J}2FMlY9NcA(%q4*Ag_5C(rwdPMb3M19DZ4Q3+84-+F^GW#Dm*P<1ZFvK=_ z;IjAn3SsZ{gyqjF`LA&J*CamZXh*Q{SoUAW?bz+%E7>ZWl{jQopA+{f+evfu&?& z+3N1@osXcfM4|G;{*|SxjtfzhO_I*VZ5zzNw~=9YY&12;=xe+F_Ypmcs7*S?SayECqwP zMZsJdVPSs+Bggg9@`%xl*s1N7GfgAPhZj&I%HD$G<0z=nZ4O$$_C!TvojYioIcB1q z_*O7+OwGZ82^ZPd)9h%vKVLzU&D-~kGRx%ZA0JPUL3|jHMtEl@-Od}-%&)F(Z_fJTo>}We5oTGIEm+iRlWpT8% z=V8v>q*g19)eKFwctys+!J+7MbbQ?6ynu?qpiL{#f%FRk0uI?55kEgccz7h#t^&Vz z_$`B@qqYscr~hg)zsY0E%YTG~sJ9+g4s3Q?qI_T$S|#^e&4!Tao0wKKW(9>}ec22^ zrb3ugN8u!>(PC)U3*K{yE_AMql3)1>;I5qYLGApvx{W||_H-2XbgL@^3FX1@aVhnR z6{M1KIyAaqJCM*rwcfRBV=uFC>R&C5>N}#yzK_IpSj~D&OLkm&8rGQxatrv3CI*#Y z#Een%C&(;-kjsyxLKFClmY(A%Bfr6RF(mObO=PG95MW*p%VgVwL&-9_Hx>E&N!=9+ zpZ%YH|Nb2p7bk3NOaaH1>zPrd+cbMnPl6Q+@KiTrC)nq6!1+|&8gtkmZ80%n>~gS_ z{-HkjYFdqdTN;OVdCNuUXE zqdZPjVLQq9D0%L078uE;JHao6BsQtBC#cM%c=YVe)mhG#cuvXe;YXNyJSbo7Pi2;t zepOLXn7yKnlAKh7t|-S2h{f^5RaPV|*o(`C{JBhorm>yCK9h^=DIx1RPeBFXB-yl$^c0Btg8f z8U=Vl$VNOKP?0c6Wen`d9Emw`K*p~XMG=w@PZ6`HgOAIRa9~;K;};ql4+s@0uRQ z{A@WZG^#hsXmWR8hxyE~`iP&c+pkNv@MtsG5J1>*qX|^Sz-!5=YWX98XdVbz-|IC~Fb9lPqSeqp=kKL3xOw4=O-Hw@@ zbBkwtRNeSS%Ppr`9X32t2?-Ie9PV%AT8vfFJ*~jUZkrX7kU(%N#AxZa^v|MVR=|+S z#f1}C4jUD9J4CmH#cqQV7L!AGjo2}Z<%S;OI@ojN)nUZFEL)qF)of!;}EpF_Lj%Q7i^y*5FuijSgjk#b9et6pJ zvqpq`UcYMDl;pL6CNan0tsMvk2)WB{Z%QlrA+BSc=Y#(aaw(xaUMFpQ?Y>bfx7U92@J`TdPjp=DN9Hr&M__8Wuv^q{{H-jr_y2 zV3J3vBv@IU+zxc#R@DV_*L^ttFi&Dq>u{K)3(h{B$QOr!)5^2!zkd~WQUU^&BpOw13 zb&NDDdK?);eT=$|xqh4|oQDfU&R%cBV#6#4H|5 z&P>Y#ixAQAQ=kC-a#uPV%XJ7Wa}?AKq*-M_g$1b=*VS6PW%undw#)RA{grm_>=P~Z znF@QMD9KNksSJXrZQvA!o&15^Jk3=}w=B#yB?onPpfto>-C@ z=o3qh6Nv3CKz$s4mR^r6_`U+{A8#E(<{afd3vEfpdixK+OURpEJ}^W34(LHE^p#vQ za);KEEP1YMJwefyS>KQJ9;kGWx|1u3)9&P$+y&_9=G>&V!4Tkpz@Xd%+I|`eYd)pW7Ez4>@3=Afr>qEEoD!?u_~WjJkc=pe04dD;thD9 ziK!_eOPE&!oR0J0?SqeAKUA2{41W(bi zy6oX-ROzW7dwHJBTM%&C5WIP_4l5bPkn)Wk%>yqt6^Vy;f`<~*&evXxgDgedH1MAv z<^Wo)H@a|kZN{u@=5jQwbP=XfvFEwZBOmQ9Q&>-PS=PPC{49|eb(>%vEyug*?<-!1 zw$Hn2MI_)(onhcTtkWU2v{ip`z3X}0 zkh&u;K+<%tghzgZiJnGkzuPRU7`d2h3KN+Lq`$09R|MD@xZ1IOO~ogTecY$dcDmE9 znXq?#mb#TwLV^zTON*W|mA;3_*)3PsyZZOp>`>rbB)Bf= zSA1A6I9x1O(Kh47NzyDQSzmEHe$Yna{!|c-R^zy{H80Z58e5_=(N4%HhZauJnCUmH z?eft!^5iSX-{yvFRIE=tvNn-$l|58I$Y(TO6qjPT+5|;nUqM3gwlVQnesrV&@oY`m zgj}m%5CNbtrYP5T?I+OkZq%0lC{|Z0YbKOpP`(MuA~bxLn#3QrIaa-XxBB^g1EO%3#6HaNE9{Q1tr^*c(370z6AN60ipv!*qKkivF~ zb+)8giJ$307BRZ+P{pymOy&dQ;%_6K#_*X{vyCtQQ^lV)79!?G(LGe@3}frI|Gah7 zhuPG!mu80#R{*Sa^~T|WMuU8$n{*}GI0%`AjyZgkxN|#dTrQPjj>XD@cL;oAWN)-B zU1hXd{W)1yfsE^axd6f+btQ4r>cVG`os~uyn=9>^sTEl3zDbjmbqsfgqQ)numK6A^ zpimsBCWfJqd2Ugdn3xQ=`RyrvY;`|9fA)rT)`sO2rKQ)8LA!D3$?7z_jXK%*p@o)f zLkih+WY^GZF7r7{flMihnLS_MyQ_5=er>z`117*kvdeYjd%j=I#3193I?5t}J83f| z8W+6BAot_Wg*E+gh=^oh4@>`k+QF3yYb&w(+;aHbuHP?tpFTcy@z^fdKCBw%?Dj&* zYt6tKa@4r>hM5urF{F?1Ai8bZaf?X&%Xtfl=x?w#p*qtP^i|EIW!L8SzXRnuh-;dL zfMl%WNF?8bza0Yf9Zv^sr#w!S;m9T9rHMV*t>(1(6#42oosU;s!Vijk-?{7%+!c<0J4&IDjtpqEv%}M@VPJer6MZY&*!3CF zjYRw{$P!S+1WOLQ8H&!YFDY0fzbZ@2Ha`h^0@k?`I zdeW)pnW?C9jbK(0)y9qAm2G=86`?J`(&Wg{snGWQkGew7_e6m#o@lqn;;dyF{H(rt!ev9RWs`BeEVp5ier!4Pt%qO;cT-FZ`azln?_g&A^ z_%yWa`%+gOvUtYA6D778*xk2_WoC~{vC-)DVKzg@?rt{inWC9_Ex39i+Z4rk7693Gv>Ik@*+C?Io_KFe|c(?~*_j zvLS51jbfBXI?j_7pBNF~EdgV7?#Gb1gHpySEw9X((!*<-dsV)qwr zH8T+&Jrz~3cD+GimvSQwmD+Zj25<_h>kmuILT2_MiWU|=K8Dr8a4u?Upi_YhE z%&ua2$A++&opcNHw;)e+ovM@p@_XFK_sqr`W&G<-?=&h%-VKcn@0_jo&d{lD?@Q99(c;;;GtuT19kSee2U5+NN&C0$!NOEr-KAed_JGS>7)e>R!lAd<06+*qb}= zU=-h2O66ZK?OQ-l*=+5-Q&LZf`rk2%PHgc_60_TUQ9H-KE=+G0WB5@z>jRZ zzHp z*>^^3bRKV~E+cs$p$ ze?U0Gi#U8tRn+&__JgTcQ@*wXP6RkuvShQl$?vee&8up}bFNBBwd$Jt`N9f9th{WS zzec@!B7*x(9NPolA^;sU`$GhM`a;w}KeeRJx3!v}KGtz$p`_DT7?G&2BykXOT2tz@N{zcR4vEjU&W>a)z*te|W zERd{NyVN+|;)Hp?o%ncl12>pwgk?L{8Z2U?CAoXg2tw`rNV~|->*w}wzhbt=0DL@T zXM`5F3z|_OZQCe=k-MYPbLXSikjuR*WawG3uJ+}i{?euMxwN&JX5&b$9LaQG^SY}h&VmBdHI-)(xp#9#d_uVqj*^EjD2GJl}A+O2w{@Mbc=Qn~Iz<^Wm{OQMVQBXa(MGxCG|};6IgY!qy6Mc z!lS9adgH<;F$PxlL%9^XOY70?sBxw-kO zVsw0lD-hgVqfYcI+xq!5=$0H74b@BS#~|~O&bY zg8%A65E4e7=jBf0qLIu@W>dt;{;}NGcP-(eKYrYu5?1FFFl%-Nw3E1kiY->_g=9)h zTiEi#Lw^cLO_F?FD{bY_ytZ{c`M3c3M9r0h{rpHpd~;;B8xxepvr8$MXH~?b$fM`q zpWGME46Ce}+HaKoE{@9PO+uLou2+hsXx^X?8e7|8=irte7g}6OO3Vlsv-rsUHR#JB zy9L^)cq2a_uW=%0Ji<fr#sb@sZPci z5;QL5cN*G|K%$tD8xc1y~*e9 zbFNQQRIUnoZ9j0Q9uXZ%S-nR#osq;bU`o-mK}|zbG7Ugf`wOlA&b>ay_E5Kt^O-RH z+fVbPD?F)ld?V-mnjhJx>626t4{ryr#yyPP6YK3NS+i@6W7i57fiXtS=!5bCBkgf; zNkB?Tn{O)b15A^hjuR??VD%AdVizw<^ zr}e6e7{3zOZEHe{1)qBfJV{YerCbgcc{=abT3yTJb$3zAcgLIm%7VcTXmhL*-7?UpSq2E-%?Y`?NZO9Vw z$e*?WG;e2vtaAbZh02{VjNO!p_u7qLT%K%4rX4(KK}}{Tvp`J;{(Z{N`KG^) z=Q9T%C;}R~n0_GAat}kZa-HayHMcy6WChNCVj)06E|G?BPE zEFMp#yO}elk7ndS_hmJ-_>zba?`Ve*m-oLkyiZ?@O{l^yGJMt&y?pz12$HX^^4EQEj|QP_;T1 zAV(8CnqfTsxu_Vjev-f0ED23V2u=SR;QKw@J*-G7d(SsCoX?E|gh@Kk*m6v{(=v&4 zSVKcXMb&`m`$?U(?zlN>G#vHM=CI4!B`5#O$wpfJ z_g{x9%I(>ocMA@nvsHE1O4H8ZqMsyXZu;s32#21~8LZ;>dHlia+oy{wI%EoBE&B3` z0~D-n<~rAhvc%p6&)ypIFII3neE}K5jlTV&CmPmYpucyZ3Gp(Pq7h#5D^xE_ciIfI=|gnN@E{ z^tFm%upO84if`<|(-kclF!Uu+$(u8+pP%nAMSk`^w1tIG)Qc)8tS}gB9fE1PH$lO# z#IKPsYG<+Dqxfq#rxjNC-02Dky4ssuUS-uIzV}-mPx~@g3uB7G%C-ivsiV40Ss*!e z)R(enw8mT>WSjT1z8HG<`;QMPm5^5F71JFy#h0SmuZ;+>_R|a+zh3O%Km4j7fTSYdUUnthKsOLN1$>1dPmfdv9&VgmgiDkIfWE0`2%RI@ zJIwhbpDVwU`}@lW*Z$QsoXYN;3v~NaJ^6|%`?I~Joi@MT=ks%4NeAsA8J>QbiruVn z=sthpwDt6n40t_qe{7J(&cqz|6E~am$_?RoM+*|@z-+z}l=g5D#4mK}<+6|JlYWay zFT)XLEkFac>%(@Cw+~tU`yQ9cX^g~p6twtN9j@)~W{0svmxE+XhOj#@Im*`>YGpqZ z#@U!@7kePADJzI7Z6T$u=8)KaLf_GVX=-^IFNgML({a8wTTmfIQ=(gb_U;`6DQl8- zNK8@dtgPLzedV1adWnz3siHn8%SvCSRt>WE0Nh#-MiT~zeCp#i85A-i#WbA?$B97ISOCOLX6q(SVo0-n3ud zRLmRzjz`L-+O&M^&!#`CK3-~9X<$*M9G}=U>dc?D4&cueK~^%QU|k@{vO6|p#hDAL zK~LWHOtI*GWc2h9TeEn~&;1Bb=6OpILoPJ-ddeaRbqm&ndM#17e$skM$xZoV_2xMQ zR{lS%Saw{C=31ew^K>=XYm+-Qh=~sEb@P1{i-k zhTi*XEnbSu1acz4pndV{`HhtP$B)g|v%1X}!(<~F9GPOq?`LM%L- zA3B|=2YB>&_TC-M9$5NyNi-fD)+OxLce*w{E;v4C2((c$n>xJyA@xIb&uMPxV)ogA zlPj9Q02G^CHFdN9hp}64Ychvf?KZeza`I-y4LQ+1O}rESaUWI*;mnNw`IGYIWO)D< ze&>v>n*)akz6KN?Ky)5j+_6J(-|o$T$g_Ffshe(T-t+^%?ivl)Pb$lc{r_(qNa3d6p1 z^YhxJ<%)Eh*gY$4LfCTO$IF5v|Hf@6*A2I*l};=r6Q7ccv^x3CbBs}T__@nt=77ET zlS<6D<#v;536+yNvFKM8rMKD>ix9O?D9VY1@i5od*VTy-&?9sLd~kB4WNSKataO(hEZ?S_J`APHe$sjVvD|`6kqtA2{6?;ReC&kZI?;&oR{JqBsmQf z*nd6z0HX$Na2LHa+u!0CmCoMtlVKx?!OcGS=miJEn!Y<@nTPhM)#Wg0rayIEA(8tL zqX%{S_nGu>I~7hz!?+lgd9aeq^8bE(LWJlXN2q$(jFj;;UO*pqby`z_qc^>sK=em{YUQ@kl+Qt7|D@+fkSv&G+<|M z0ormIC8aoki>0IS-nG}qj~`*q#s80Gi$H2|;^^O7L?onw8LQg)%3GiJ=0*(a%1V?7 z|L8{S8D|xA!-xQ-NR2{@L7Q$Pmg#xcYaP<^@)wpOHnx~Dd-L)M>$7J&E3a4;C|e`a z0LXlqTVDRRlGDY@w~#dQ>#H-W9wQbb76J!eQan8FGp|F4Oxmlre*YK|M3LwuevLY$ z0o1sXiDfw&QX)X?uH&1H%Xb3a8YNREEJPFgE_>`c^E-`O=bkW!aLaGdX21;l-bkWQ zWOcBGUly+8H(@k&lq9ZTZfuX}dl**+xEMKbm^?uJA6>@_rH}{)jA6Ccb_GRY|NP-t z?sD`ZA@Je(`ZeB0!l+8BF2N|3i--tpoic@!c)`YUDun+LKv3W))2a_&NV` zmVy%QpKM-EM~7DHf~r-}|MwD;XGD2cbWgYi1PuI&g5XD|HnUK3P01GT>XDH=sB%}>gL|5tE-o> zzNp;4)xxMLe$lJ+jQ^Ll^#5x$n2`$Q!t9)(Smd9!UFb^2e>(GWyw(-zM!dIiR{FsB zG4sv4`J}YHuO@s=RoASzY#mgiH^c+Z8`6!rJ^PM^ajstuuEdcV^W?P@GcsEz%l2LC zod4S-*$jRpX?CJ{9#4ixFVdkBRbshx9SJF?%^%7?LW9-r+xKS;wLQ;(S+ylxVXon5 zR{hud2KnjRPV@8sUQIkmJ#*j#%xt53#soUgM7BPflTLsmA5;gNQ8dyXv=mfK<)7u{Z7ui zGxVDETUI~mbQ->#e}Zh@f@uS$j++9RH6Y9y&rJVbj0Cp!CSs5 zbunRl7YYK4GJle@KrkfJxM#x3^+)1Xz#ket!(hd^KR(m0OG_L?rYE1VvfWHrQ1+X!>;JQKy>L*cz>-Qyq=Vi&+r%t1p{7>xaEjpGtTmurtBez`=X35wlxT z0KzC#oO?FSTen$;X;)%et%jTUKYMW;YPO6O;k_E)UwRZfmg*D`xK*TluqEgh+L(>Z z9Uo=WbX0-*ve@*T@tj^jwDj9;vDJYz{B55{bsFi4`WBKd zS#oLAu~()5lkW3R+)5(2U+=5QSsM4%uTETWJ5L^xRAnZIJwEp1RA|=Z8VsHnL;f(D zuvaCnP?a@*3SDIX;YN*!mQrUj-bz^}C@ki3zuU|?7_D0}K>QcA{!@;swqeajWAyom zaC$G_aRgaS9VA45uzvAKc1BE!q0E1>la9k*i~J2;L=yA{z&o!Pc0HWNtX1B;U7~zw z*vvXZ&x;$nJAHf5_z#;8RowK>)I3~8kX@bD?_G@35CY162;KKeyP-9UX zk7${do;9rAO(1hf-MQM>{tc)**5-=((`#(?aFui+Y6l6Cm5oO~uV8J>C4;nP;%9o9 zNh#qEtpnq?;eO%tFlx{scrtir!Z-_Za5;GK>7F2Gw zb_2h&XzE~Cn0DM#D!gOCD7JTD7;PZx8rc5{I2-EFt^^NDS=`5Ow?6-V5X&6WP`laz z?-?QRBXfUeu51|j&y};A^Oglh=KI@{w~zC+qQiadpv!Xn#HR*)x0u{j&Pe!9!R@!L z5x6k*%bKXZw4;U7*<)&2981u+A&GPaua^0Rr;b0PIJ|`2*GX_uNTf=f zBc5$5bbuz#LE#Vn0|ABH!ruH6kS8M1XkoubaJG&^%g8E{Dt#dQ(RtSGa@B1{52eEU zQWq>M=~5Bw8&RK@Y8Pxw#5t9l-FfbeCPb;<+zS#-QmN0xWNPfeLYI%Vu(O2XtqSC< z?TP5EzCsok9lM~!)%x)hZf|%IXT(J04zQUHV&fVOC)HEtD3g1U*?%Fi;7cNGw<*|i zT<=L5b^EKUY{o9txp`QuX$+rr9J)2-!@YBncW7pZ>SSJ7n5ruOq9?Os%CmA^JVIKq zey7Jn%u`T)Tc?q@rT#@+PZs$(Pgjst;UOK=v^reZYhO!aO5=HF=Mv_Zf+`@i(|@*B z5B?OrRY}fcC)3ir$T{wMD8n4Onr!}`3!_cvLX!HK`X0xqLG5T;oa8E>IW$Jk8gN7x| z?g*;e3*o40Xe(748(UjeX!~-A*-6&&xEd(VWk0-bI`mEf#H)|@3I@vB(Sl{*DB%5d z!ln#b&yMOBY2hZ)X%EgSC9GNC$n<_SU8c11D~n8$j0>$lw@&z_`P|`uI#htE93L<45SY00wLt7$ zjahusZZ9#ONT|c72>R5*{hLca17UGC9fSkN?IK53t{_#nWDWTY9MaObjhcy;Uxb6Z zaxI5#+f0g?X9i}kYB((zLzh(dNj*LlF8Ga0Nnzh3cUvv)OY_nTj}f`?EZt%}?!B>k zWsf#AfBy)Hy2sGpCt1pHi?2dK;P&ElQyUhUcr(X?SD8AM(K|B-yMO^v~4r`UoL>3-t{M92-(LkJkfHk z#Hj^h@9|_VHEe&GtSQ+MtOEZ`M#_TkZRv$77yFxn26&P(LK;0h@A5umfUKnNtJ?_$ z4~QfiKv|b7ra*x~TWc_YU!g*uoYnC*^hy5DesC<**3&-)_(lVz+4yjH-hCD}z?l8u0CXQ^^dalQQq#^2wU>y9USKCf$LCW-m zTND9lM89K(EpbfVu~3LNGd8vDqshvGV@MS;+x{GVi1HLQuC7tBEgNRmL$s|$TXNHi zrrOEQPIXsZ{d)o*Dd_pcM_!lq=&)JxOUwGlZ#?>YK`oQ)T_`8|zo~p>TMA4fvV`do z+vZQt`kuI-{k07?;fk+)lW&YS!)H#+EM}4F7O+Zur-?^UR))_5UDV`dGlH*sendu% zHzZns<=@HF zS4VGNhsLIO&gWz+@G51ZEd4Uo&EN?CAi!4f5KEn!+j*B#a~`z6T)<(=uQB%9-grMm zwJ*pdIY(Res}0wk3&TveU?rk&kBC3_OTcU7HTb$0FA^_*Q##YEy^XkeAovX;h%80uQQ-ciuGrK0QG9tS?k zaiiNR#KY*Hm?_5szl(ieH5cE2W&ViDwb{F7?M*)d->NkBSwj3#hL;X7T$Vw-88>?o zGleS!U7J$X%7W>O_r!LR+E+v% z@MJ?>7Mu>!nrvO! zW)6E=k8DpuBVK-c`D5l5gYnNJHZN;xYLclWCMNdcMOtI_eKgaAn2pVS1DxWB68h$8 zS^`DOQ6R_NvQmPaY}N*6GIZ8}XiU?)p){}5YO0(i9MrVPwTSD`$(tf-{qxmNH;?Vr zfcA&}i;sI^!$wCZt-CJ}8i_kjT;BpZ4;hIWgo5lmj~dW{-cqz_Xy(<{;9ke|_9`uH zRtsgbwVzkZ{9-10&1S!?lFO)D)yd_h5qRS@8wDXLjqh_0GU_&64oD(K%uGkSvK?A< z%$Jlw2b*g@VcRTb3pDd*j+OklI|zvb*{q%6Gxt|YR*U|$&~Zkf70!NKl-CS`tydsj z(MO-gboVPkf2G!Aq1!zUhmYtqHubk{xyEzBvh8e+6VNzQmh^saKYQ#MorgRk<`ikh+}}lx#;k z+6J^rZBlY4x8{YZsi`vK87F>!>P2Y zGIOV-R{}GF2sIDqTeEN4!Vc%tC0ymf7G59U2f`JT>xQQ63QomTyqBo20=8A|iQ-oC0{D1NP&?zv7{j5GHRUN7t$^aFRYhg;<>Jj*N= z&=EIbZl}l5 zaRjkzWp@26!XuNZKT#CyZ4hP>4VI%q9;b1{7TG_*|Ncj=et}p13R!Shm0H6I&7~TR zrsM;Jnp;gzf&f))Sb?XsED2FgP?2wsEvBtzcO;8d3P*Jl!TWt)$_6L%+iQVr@JMOq zy+!DEKjVdlcU1`j54q`LHhe@yQn z=~Dk)Oxs}cqJn&_hSzMmyZIC>m z5H!2h#-Mry(Xj*2hsW~+&Uj6BH;~v;Sh~%*TD<2tw){r~-XquhZtCL2A{3EUECZ?R z9Thi%TZzAq`x~6SDK5HiVAJ@~GX2T&<4;Gq^vr;f=IvDErgAw6NFoR*k&W-m zGFy1%?yY?Z3P`>?e{1`aSiN#Hxjuak;2}hOZK~FU6~UBA%jPqvpfC38hu?x2zafj$ z#&Y798Xs?1KW0i| z!gPTgaG`FGFOSC1Jnp8Cyevg1!Vb@lvRqc*cy+1XyPY>wyzNmld#+C4)13FqH|pg( z@&y%AJ2N>h7h4g3v<2F%MAL$*BmcsC?cfQ3k~<<3ewD`vINnJ|l0oUHg$tnT7INts zYDKOqWn`h@5?^-*a~}_54L0o!4|cTki271-cTZ~ziAdA&n$WRr+naP;_viy;&kH%< z3}j|&{M&@pBn5drM7ut=t;zbnQHb^~v)Gg6dNjWpc%d&q_tbhdeK0!K7jPRUNZy$Md|m}V)@Bs6b3eB#K~Bu z&Jv;lw@%eXw=)?dQW{-fwc`7ZL;&+1JeKqt0{I&?!FOLjVpt~V4;ZfTzabCpsWg=@ zY3%X=r=BylLWzfTYMq3L)C;5{wJ!E`+AC&_z}tPVy)K{owqF2rSPaW+IbQOCM@pXM zy1}PYTPLnA5*8znVW~AppBFb~!~|vFAZK5XL%j;{)K{?0fwB-YjQ&y+*Y`QX#xM^nw`5|P=(wY*Eh-Jq#vY<~SdrN&5+~ zBc-4R_@yg)rG7Iu%fAD9$HH?2+bG%FQ{|{4{eHwMr3GTIh!p?AGrBq5s{zpa(?&bS zjb1_9QIiye;p{;Mp`S8W> zPPx6A;TVV?Zi3fhTy=a8S9qbIBjkGB!r$eSX2K3jXA~dQ$$+vL>YNHD@Dd%+^KlO^+Szgm2CNo3zex6 zw~0Za*0xTn>W_2T01FzFZAE+a-@0z55yk2f(*(v2E`LzaJ$_k&`)<-d%0avw~j z$5FH9>1s%WD`yg`?Uuq;TjMorwqXQpiG6wYfB!UfV+|L)U-r+`dXPMojv0dZj0^9S zFAWxChS8XA#UHSeaSs_@Q|PNQqh;90{rK=aRv&}ms{Rh3ZwxTcCgT5V z;@|qd{fESfLvyN_Dft-5Nyd85rr~3qNaWH^$=2Op9i(zBsCf{A%nsb^5WlAyy+HlK z)W%x&3BR=b`|&@b!P#quL6|GSeOzimfm_yDT4@8G(0KA)S3QJHqC0U%Bz!hjBSo8U zpWLboJASww?+X(h!8d8PGDn%ay^gcvc~MFD3+AQ?RHw-seM<+M2K^`sJpuxGCng$O`ORt`#6!N0qs{K3$2jy#Gio27 zm+vP?mNwrQSyZHF>LI&fRE+*sEY14s)Z@e{Z|N5W@`Ncc{IsoO69vB$%}kb7>eCt~ zC+t>uA2`=alWBJjFo2ibp}gWQ>J3$w;A$&mi%2$kiA=JP)VUmn6r)4jeIMu2)ScRA zLwxq>>e$3EN30Sv%4p;Dy2|SJZtp@A2n5hl@(qoxd}xU{7oy)3@pQ+NOw~~*zT(Rl zbvtX;_3evj(e_SGc0}?+;`>&|rp4DC>U=ZC;3y?w++Cw9SS%Bh^WUiS_|UTR{#8K|K@SIp2s|Ram zx0o>2>##Z``(}nR4mKry>)kyr;Z}MNKjC&&)@WGAJ}pJRqe@4doHvBw^{hXmc2a=7 zgRPpVtR@$Qf#v;KPPd0hhk$Up66JEEQ1rU$H|Ihq3xv#3X4KM+#n1DG*k3&U))&E) z%t)QKqIcaGJ5jSAAo4Y@*~a-mGk(0@W{U=ovsw)%2%g1XTq^!;%QlITOBTL=u$13z zG6|dD)JMkv^?#*jbiPf03nDiPvjANwqS1H`G-|zQAfiPpm*7XQi3o?Unk^jWOc$?0 zoCp`5VmzzaZdCEKd;hfveT2wG|K>J5k@|&5V$o z6#jMpgS;ctImWv-OWDJuPGn&I>5dK-22t>d3XuJsV_P3|3mx2@Oi7}Z21^fR+g8T& z$lYQ_>o7B-JfME~g1Kf)*|AC6XB;>UBb+BB_s%=~u8YVtxmnH;@O!FHCN}14fo=&` zZPcog7n{j`Hp%tx9duiH-W1NCtRv+}J3H{+tq=WY!&Gb^6iH+vg!67SPy#22HZ~;; zex`jqkyUmt*u_>h%eTKq(l0>J>>s}P4&OsLcSJj4^?N|y@b4l(Vr$htE&Xje6cCYE zyrq>(pnf1Ua5(EGqlW?437eVB6RNcGCu>J!3@>Q|n7!1=K0S~+W7c6W&c)QRG+Uph z_$NOQD|?tIuRFwKsBclSb%>Le!hQ(7aX6st3K!=8l*A`HYOYp+e^O)7M_EJdW1(S- zW!qpqW@;Ru30{6UP;R=K1#J8{G^VHP51&TqRPw#2FZZAK(CeV_abjia^4{Ahgkk<` zXwK~TM|e8q)e49%M4nE*4T>)LiW3+o7qA=Ths~Ph>OZ{*fe^=HRTz-((~_9{lA*uL z-M;QOJqz>qxb?h1ahV#M$SK4rHUi>uGvldO%VOoXX^gWa^0>b7qEE6 z<9sqBEVjy|{K5te>yUHY#=($KP|#_oHY?27BZPtw|8~4Umc=%cuG2X+eKdA#0`?^0 z#oD%>@7l@cJgYp}ogrH`!5Zqx`g*`R_Ycnc!GDZo4Pk*rn)z00zN!7GH$I!LaxVWx z*1Nrf_}x^pjvZLa#HFt8dkZh76f)^&6EB~ik+Jcn=f7G1d#2pC*%*MW*Zwi8BdO2Y zRDz1Q_G-syCgEXe^UPGjrZoK79nA~pcS?WzkM$+_@L$tL;J?=Wf5)`(&kXgSW|aTo zU;nG*`fv68+u;94Qv6Rc|F??&S0(;`BVhl0uUh_??;i05VPhl}e1<5gyXBQJI;2m? zC9c|ls?x7Dxc-iFz+usTYQHxH3v8_Df6At(udbIN67uM2_N=j^oiN^S%I>}^jg3)M zb04%Y^2f>~<^25P{QQN-BCIpo0o?awsCM0%*Shkp{%?QYj{y)4wQiB{W3)dyN{Fqb zJL50A+&vExTz{rQ{~$t$B%ImUP*by4I@gts`q=W@Xv>1<`@Q)PWRSSYd_6d8DCVTV z19ICb9~ozP_2+H^l2GQ)@d{m`g?cMVHMJzvExRH(o(@Es;jCdHG1l$twp0^B$|(!N zp=~Gu8jqjHEvw@U+j=fzghrzWn{+CoJN)}^mbjmenL?a=8ntec%9@WLi%kxOmd)iy z@nnUIH1^tQ4o`KU=7m)lR4G07L^iYX?Z(WoJWwk;sc*0ZU(PbEx{kk2q(Z&b(@{ngV0`@2wq9FI*88dy|>3OYpTK(zL`W3ziK4A*ht`~_dBmM55t{?pM zy@CgT<~~j0_vK@2Q=1%5q#T#~X}O2BLy+4vzHoCLQ}!jQ01tHCV6er+W`}@?TSJZhWI#V}ep$T@AymSrZK1!_S0}Edo2&6S6lnulmwH zB2e(;@ZdUWv}ZA28J_vcCj~`1%b1Vn`s}FD>XVf(yj@dFq1P;%FOFzRA-RmfN_F1hv^Kq)a>A~~d$lZT|?zv0tj+4H;o!{o#=c<5r{r}8Phx<;XxacCWjEtup% z-}cr65vyXb??QUX8kf8Jl06oYIBA+L+9D?Sx0#>=L1G~h9pu` z4Y%#5G8eiqy;nfeQcWd$obkkzog%R6Q{REQYTYmSqm#Ek+!6K;BfV<^utoI$c9Y}x z?#g#3^923_lmgw_w{J?sP4@g%LsercqGOsbrTmtT3QHxZw{2AE?FyTkvs){;``dOTJM<*~OnDAqrG*|d3o({&3-rX2{Cs4k} zvngeTV)jxM7`ha#bvy>btv3#CM4?6c6@(X$EO&3L17*tz_EVq(+|aE0^ev7AQFtuVFb#)+FV+Nn0Lv`_U=B`{DMr$M$04VbL%o!6L>crQ)o<;dJQ6(^!1(lUFKiV-cRTi3N6t0c;0&?9j%I+?6)A zd&xxa+gE1Iv{p_bEXidgAxYQP5KaQmJhZaet6l@$ZjL^U*~|41QJK;PY&xwowMVus zAKv>ll^cyQA>0FR#d7B^X!X&Bipr2ByX}qzh%AYn8YiCyJH0W>>Gg^JcD7tzMHWr) zqt;vo7;)+F?nI#1L(<*?1MO5yZmUfW+aiej8U;^bE$(rwz1a$KGcu2mg&(L?$|5r8 z?LhJDj`c8`U(DB&cji7=CAVK3>I}AyiFW&p`E~tzSl1Ca6Q=s~Mie81e`qT3R-Zc@ zpUpBdMpFkZgA-&-M*6^?oAs0jHCWnuBa69$sK%hEd9_*O>h6?{5n z6_m-`PvvjF;^G%l+o6%KxL~O($iw7PQcJqN5mC@y(c5WylkXXi-dsvgYr8di#PS6Z!mi z>zJc?-vUB%nMIQhZu6imvCQEvDCNG(uleVD`2Cy3Q;tq6tQ@U#c^$_mWm&(wHw(xF ziK5B8#@U;frK7nP1I=@AR9~jAiS(XMq(gYaw+lFu#|0*obgB$FoNckyUiM0IJr?I& zl#_p~!jNqxpVrFgD@xW|D_?=qsuR&tie_g3WOz+6!Cg-xKJX9w!Ry9&$6R@~#)7jL zQ_9ac&}Z0gZaEjS*Ut*{hLXOpY5E`x{l>*z!X_eI;cpWqMiEgvo*&T9f1G|OX8r8_ z|G!N9TOZZ`Fp<5i?)Psj0M&oUMxS})Ol}Vu+R(Ir zeC>XL&MQ08Ic~Yc_P+yG>a{6B2o#eJteidQ;U1YFe=boh*m->t(_>WpS^TCB$pA`i z361lIavYtyLpjy+VKu~`5!tO_%=XYHt9mVHJoTJ4FO)|S@6+_IuGa!wl|>qq4i36= zhA>n%iKMEQf4cKZ7*YROzLKBPKg6^5>DsKCUR+;78Qo;8f?xZ8f-iqNDf(&?A{=RbT!kWMSAdUd?fAYmMEFVi(*7rNR z3HT4C&5E1r|H{k&^GS856~Y9D(l|r_mrffS#Ht*Lvi+`T^(z*4$|J^>`sgSDV!8L3uZvwK^A9_03Mr+_>4D zA*eeVqv=D`t;6xF2Tc9XiK^_!US>Ntzt2$eq$ps~ZskadViqhC8D$titbsvVVnE zf~lZdzXsc?RbbWx_6@a1Qk}6E;edZQ!K0PGZxg;LP3Nx+TW6GKglLA&W$26kA|jJw zKC3YVrpv;VaTjgA=K&nbGj9CoLqKn6E;o1fAZVI9nMUWm5EZ=9w|fr?&~bjPa{HVgzzP(ld1geu&`sIS7M# z_W-wxkY@{a76Z6Am--J?LAzkG>K?w*46sh@XGI<)D)%^X4zg(V8x&io)iOutsm?{1zF zWT}RAuC{fS+Uibf=g;PAZtpRtjK|@iN>q{cWUA=$so7vxohzh3?nvYOs@B8rkz+9} zM9hVVH^(A4`KOQ2H#YWD1c~2NZ%F)i_jB?O%*K2&y;ik)#JfK#s-Vk-Ps}$vFuw9# zmB0T~c_uZqaS3--Zd$DwYQU8)62Gz;RkiSof9aQ9$}s)`+s5VS;|7SHSpk)AnQBMNP%#2uJp-WLv{o8w+%w9h4AB zwI#$=HZYT|uN@EOteUN?^hVBXMV{Q5mZ+x>9NKrx^(vtk`_8mj%kvR}bk-iGxNHzC zqqnzqzmCM-*4Po-0&_{z+q1eW;P0f-!JY7%kM9d%`0mWx$3Ct0#i5aKzANI}kk0~C zDK)c+{+ai-4mtKKyi!Gs-?X(hnBQi6sIw&2EET$?hlx=kmUidY54E;qX<{S%{dYzvF*XuO_%X~*q zg`Ig#FY(B?QXy>bDJUIWbLeacZVa5yUegB?5}zaJ` z`u0%Ghz3r`IZqz3?^GM;buU&~lsK%=DoJaeV%$T zg?PW3>7#KQ5D_ZY6hF5qO!l>U_VlLX5`BcI_weZ;+K`Ux?(0+akNF3{wG4C42kBuS zduA*j^6uH>*>2=HAY)=dW%Oo?f6#F217?=HnE$N4Pnyz|iP;iI8kQPHzExqA_n89~ zspxG=TpZpZBk&A(tyWcSM=dyi*(d(zfm!3eBpSSEj%YS9AZKl^vde#GKYt?R12%g1 z?)_{3QmRQf7a#PF?uvT~%)+Em3}ziXBiIty*!Yd@o-OJTPvf-tn`TYOPr-y;L#d4P z_o|Q`^7}-Ti0}Q!u6*6O%!Orsl|IKv8#QeP{^nq>NL`(!;Dw|(ME|FXk;4Lhm~>Ym z@c>LX_@fke6jXccHRm<nwet$z{QmLteQAP6rQFpI@*D9CxVufc8X|OnoU^`>QhXtL%f;01O^5# z#V?EAGV=%}>R2I+$Ei(ladD95sGKX9A5CpL6HEmpDd`ekI;%gZ{+Se%UWn3n9YYm6 zhW(_TFdw$*BM*~^6^TW38W?UBN{0SZwBu{BDsYhbw6D1ALdAG3Q6#$fL8Lf8Gg}VR zKvC+fVT6XferbQ0ev#jk30cvZ9}dod(c-HwgDZbbr0jZgn3dE@ebU#~nVJ))Dn4ME z!)C<~Ie(=cDAmXLEHIW}Jiy_>@?nJOgq~uUf|>`7p+elX_riGisbvkp(a$>$Csm%^ zslVT?=J-gc+4erpiNR6gH|NtaeibcWrnfnq*oq5RtqgF);Uy7?JP|fJKZ$9V0QL@p z?Sg^hmcZpr-Od&MvBAQYfH(J!&y|4D7omGRF!9uG!iwJ?x1^Ye^2Qnq2-1P!1z_tN z1Xg~%&7s@E1B!V`Q>_Y7mKyS>w;*;Y1@Wp+A>YJ`1XD=9Za-}Xo*remb3%zAX6R;= z1zTzfvEQ=CT5@mfkLj71Ao}RD?C8-w_V{96zvDeET=`b*%~|IEpv_lparC)B?(XXi z%PS9GCAaprrmHwFGQLbZSKOE0=c*aUcK2=P^uaTvKLzTXQHVcs7nHa0Yaj)O;=s7W zGsmJ3bOwha{yv#;^JuGmsuo%}zaAWeh5-BL;!ulvCmBlW2cfhoY;j>P#|?dS+v23~ z8*&qV*h=@FI%N4cTl?1&1lhh2#fJv!Z|k(~MZCgN3Koy}h*$BZnDGK(sza$9>AjV} zNpV#ITs3lV!d>wo6w+{7aZbWTn!F2d?~@%kcjG7N;fbP5)yyML9M>7Q`GRBFX$dyD z-CC7NCT{AVtMbR%ITX$@o>z9QvUEez3l*zhaNY?_2X9u4_K^R62rHKCBAdS#_Q3H9 z6tW-sk>cmr_$Ae-o?E4f}48U7rr zlX;FH4r4Jh8)+M7DHUqVlHYgRMUiyp=>&S91DXrQ=w737KtCPl3Eyy z25xtOt%vt!h-}Nc{@Czqb281UGR$<|>!3gL5{?@5Rgr7z2L)GzFdqp4f6^jbnGysB z;Kp$*!V{`)IYrm$L=4om6{Ki1qSe)cDUld@>`a9X9TzC zFH&C{?cE;|x&Cl+3~@gDyy05-Jq>Bb{{>OKO^=HYv3*{E6D`=#*^6~IwST`njK*fZ z!?iJLjVMaMZr87=Q1V4ePkmk~-H2(Zf|G44phudKPeGB|bLpHwi`Z9D20E;d>pYJxF6%S_2OFRsVviZ%Y1G& zXYud>?`Hc}-*;tekMmrBn^O;n_0Nz6nY}<74Ld}YfUfMl zhZq|%?*TZFMVoynSGqU8duESI8(t_IYb(|x=Bnet*3J`zf9$Iv5C8o)4Ti4t)DM)R z*m#}`pvUqeStcV6x6>ZK-V^Z-Y*8Y=?$xwcjc-n*Q@Y{Z{Q4^&`Zz%=@@XKozb+DP zlSx24;W8TZz&|MIxiLX6qnMez{OMMqgM&lj3LS4lQ)TUuPMgwbw-XH1bhMjS8jzAp z_GgEdaXwvbz#H<&d!2|V>E%++D%@lptd~_ln8KT5@eA}d?%%CHzY66?M(%w1M?IkN zYX;BX|0%IHh|)mVLi|SPZ2@C*sC~tiNl@Zz_a+LmuWt7=g6Ut7cH}B%VJ; zcLzIq8UoSb*mcR)Kd=3&9w2(qpYk;oU~h_Gpp*l9%F8CI;r}dOrBoYk{iVnDp)^|1 zmxY+XP4T|_m1sItf%Ja^Y@kKRq%`Gc{nG#> z%Mk>tiX!6wbe2R{4l|zV(Rx6_HbAcynTNUazaX3ZtXq41{g}S);iY9~jG}=ko<+ug z(H0Jl_M9b+TGC~BD-ISn^?yMdo+(ih|H7@q9J?<*B0T@xL!&a*Q+6nf?Z0pvsNgE+ zOn?9W+|zRtQq#mxDl-B$9=CZ0QR19BEi#ez+*eUeTCh&_&WOx*=&FaDq}&Q#5^4Dm zzEnvUvUH&u-YI=XW#T3)-pE;42`S5OjpV5UvPmnU=*{67$wqnEGQS+#=1;HUx6eZ+ zdNa}j?m^D>J2+%e{_js)hgco+dWHX&>u0(D&oG{238efsqZ|zgIdD4(d!1G{( zt5VTz_mkbo3Yc}62MImRTp_CsZ$v1xZy)Ht8rwY>epvUYXga|p(^fA^|7!^yqpOQw zAfRfTE`N5tZCINbA|k7uB3?;h1#QRLSiB_-g?+68N3Ox0$;fmjEmhf9ubVsCUs{KI zWN_xDJz(ig%ja@ZdLsDT9M~pH$2udQ(yU)eUXyZqPf{5bn` z?&N5@IVy+daV-0$Ab8um^$qa>Z6gQ66u+5=(x%?hgUWz#w<KG3V)0ode*)AClVdHY?T@>T5$lmO7lViWWxX zO8fqLY%^D1nSW~kWtO`cgUwNo*O0zQIuGD`LnnLI zK)f%#h$n@D8;0mQh26;Vu%sKH7eM#E`FOf@kLb13`idO$(+yXaH$_ zW#QzNUB#Yb7wk<6miuQCG4I;+A>;?V*5;~H>;Qf4XaL5~&?AIBL z-t87|*b=t5wWD&jcY`}j&haLx$(BHKz++aa? z4uj5wATXNpvzne|vsHic^r9sTtt9#QC0M_fRW41ddMCfi)Xx`D`wnNiic+q`L!i!% z&kIdf7YoxC+3o-_=xY9Vc1DOe^Hyg5_LrMd;x`n$j<>BW!y*9I$XW{mA3|-A2%Z;QBhb@Xh#Hx*B^w9L&(n4*6vETQHeKssW>n$#^OG$;dGwE}=mT zcvucACeQBP#MZ-{g?EhD%!aa? z4qcyz`}y7G_f%7IM8UV0H*HtU+@DUvxfasI<9b8OdW}e9-2QpMXU8F{t9;f726O(M zAc+^EZnrSVx1=cV&3G-|CQQGp5()nV4}IgbeISyaqBa6_Zd29#bi-aq8H1#5uBZrO z%!N9C#L@YpP`gb7>XvqbSoxaN$BpCByuCa7kUD95_SIi9u;4{f0J(~0uG#Uu+S7-$ z>~Pif7NcWxlaTZsi7RzJ3!`3aD=<@T7Ht&V(v}13EzuFK=ibNNS7OFiJ?0d`yB*JW9|@h#kZcv z@B`!U1JEHdlcYOYUBc-k;#AnDiizBhFF0gJTrJusqYwB+vhl8BV;qf-Q`qSRSFiKK z(8E2Uf}%DUSc*K<+vN{`2_)U~#6E8&&q%q2Dsnr*7)|tGTL{>T~{3SDFK(5K%Zl}jhcwk)nzBK^>O6v?Qvv%^RD9_hiN|$ zuWMr2fy>;B7tYuOyB)ve75#(!p$AUC((#aofwP?X*?>an<+qV4q_;UD{Yj%u2ut!j z1=UJIx77T^2Ou7m^Ij%hG5bX~GmY3-gnpDiP-Fa~p#)QibD5e>`#`z|E_vsgl{OBX zyN~6>@y~)o{pL6c_%2(Y@5OAGIRPki(_f}J!hgbB^abAl7Zmc3-Dt0jtroN7VUg&j zi}d)gwbQTa>VqtTU#Tw3d^Br#H2O22WYDf(_aTanx7ZN3T<>?rp!rf!iUt_MBgJPX zy3FW3H7mg%e(66yI$nd+91FzX@Ea1}xG|%!ABR}>%`8^pFSsI)v&m+<89rbpM z_8eor`$E+7)PM`pM_t6&UMI#p>6$%&0!vvvtuwVZ%2ka`8T47rk-Vm9yF?@=+v=rK zk>9ole0iQ`An76GumO0Sm?p4&mEx|5!3hSZ$al?o~ZLp4xYleTgTgXKH3nfe%KGGG@f!q0#y8CeO+E3RyY?S zj=pbU*60MpO7l=^G46$B`yrVq0tbdd*h>+lM?z3t!0mllAME8{NR_zc< z>M`Xh6SIwRL60rPv(I%O;h>}cFt=dVExXkUoKq0DsJNux*+;%vJA?b)U~PJywk@09 z5)wQjcCyh`;q4?{PJO2<789n@I&Glk64AwD$5C2oBVq0}e=ge5HEXs` zaz^Hj=;Y^3EJ!<^qi{3u%oKYzDvk&>pknmhnwy0G>PUOm*=M+`1h_#j@OQG}ig`0mRIl^54ON4VJNGmp-t>8%Y|JJ@F(djYGgx0YiK&H_m|b_d}x<~d~C@AprK%N`kW+wgs- zW6eWL^T=F5h6F>AB6N32J_`L>R3E+tOXVbfmSNPa35jKR$4GnEe%#wW!cK4ysd+ps z0u=lB4i^}^e&^e^W4g2AG$t_SG}@eX>@n&gABd5CA8-SEwOc-{j~68(5SJikNiP}@ z@x-6)x4@2+w1u$o`ElF(k2-DzU;<}D*N`tAcS9Yq%MOfC^+_O^x4sIBV~tdk5h7i! z($zGJ@C>{5YZO_RcS#(-QGbz}ytm}<5s6@L`J$%xO-z9^%jA0WqhW;jMyk(!hS^GJ zkgl%V47CT}>hMzc*DAa^wrz)QJ&DD63~!DTdQAA4PxN729ZB9Pnj$Nv#iTET-b|G0 zFEfozj%f2EH1^>416%|v0acL{Y(il%q9flxsOyfn>wD&8hCTf@zaID#uF$*(vgRq) zmp-uOzmr{7-!=12qxv@%Ku2tmr4sls=lBu$Ae3!}MWx;V;~hU%V>gB<+a0vg^S(kB zGza{)m;UO+dL|a>$#H9gJDbXxi+S|JD#9;Z9uGg6oBAyHSRPABnrnB04RQn!o zCztbZj=U$(uqg*Rj{*6<8&X_;P!{!RASYh+$)0^2gZ#0S{Xyiul~|ovMhaDOtq2AJ z?;cpV2r^2AS>OT(Hjje3UyqGD-KDsFAzjWKSYz)H?n7HN!+!lawE=dXF_94lxmZU= za479nI)Ssb*n#lzlNaqPzs#|&2u!jg)k_)wwyZdkq0?_chpi>XlN8XP2TVu2CfxMo zywZZ}qQxXKFXhx~GxENl(KyH?Bd4Hws@0DogkZ54X)g7e2Ltp%g`nx7?ECev7P?Gq zvGzj;*=a%OQ9(ATD~On6sd zE!X!(7S5=4wsot&+CAy>Zi0B90Urr#D{otWYg6CslmH`ud?CjdHk42=>w8WlsVM3s zx1GSf9(kab^X~B6dhYJI+7t3mQS?dfk=8csNp1(h%wK(d@!KcP@?sNUwn>v^4hSnV z|Lf6TL586)V}4npj5wb&Vyz4OdJS7oxx6Z~FgwJgrpN)O-Av<#5sZL5`Mu86R@}E#2*bzmH&0RIo97q}np}jnVP3bD{!0S8 zFX?}@6{@egKg6s4*be9i_BrC^KP0vu&$7`26J73TrU8G8NqsaYK<)5j8u?o5tbWAs zEC*qR&t?&Nef#yr%P*7Mou-y-&j6kWcGK`hMj?#%IqE;)5i&K5InA{wO!~iQ5Eg>+ z|M>3zy|&jpd{fgvU{C^ zojo=@kqL(g@9HE65vPhA}~cxv~-^0904 z^#2R@Z8bFOu+Eg}!N1Mv`dX}2{suN6pd{sPI5mYJiAA?J>)Q*pN-ep^--^(1o%h=0 z`>=R_+8(!Plt#yz95Goa53BfL{kr`%Hi1;4r7A4H+Z8iw@<9$5Q4Quf=MxixP$tv^ zeC>N|R!n`M`&NL{=|gEg{pZj-l)=L zNVV>9&wEDgv_dT^?!IvTm&XL;82o-02qOKR=&pR}q|43aIsJfVW7k|N?S=LEYl|Sd zGfl>H-X^${BaYKt`&2lDg-(w>1ms3i14zHyJm@Ae6~oaalHJc)$SRuNY7F=9?Xtq? zKMW?USEq1OBywptzKk>2&~M`Yz)74ELhKPp`s684ES~S)Vq9Dr2tCKpMyxyk(5=zi z;b69kWjZf~w;t}~iF&?}T>%69K58hYLFNWxtmWGh%>pc^K0Bo!aH0z&ga*xAV1)A9 zxUZ3`g)~&U6lhin{pl5}GeRd+(axg5IB(HQc0^IKp*17?Id&sv>ZGH!6GVLQe0R~z zCGD*`dKY_c>g78H(J=J<>%PRf(|L5YEcx!IYFF}D$cLM4f2)qv z#_JR>jPkFt*Shi!D?ImDa&8l2wGaI8o}SY~4k7fV>{9J^j{7;toeBOjbQ`j>k%ay zO3oLa6cahu%_3+Gn!9Bhwv#{ef5ATCjWe3ik5c?Fv2JIZofB zewD_Iekb2!H4C6g`zmfyEdP9%TJZ;KrP=_7f15S+%8_0?oEhAr*n@vN@Q}XTOb7`u zlW~&bf_}so2;E*LH+#31qTt~*?yJL-U7(+hSvTsL1{zRsCmI=Op)MitqCaNa_r_4n#1>qsH?m~+wFDijp)?Y$Y0 z=DvBmD6fEk=&gvScYUO8d;XW%ZAK!5!YbpL!aCB10Bs8gJ)dx-<3 z&5+kxK-=#nsc17u8IJ_v+b;w;1ate1`T9pNWW{$cnspKRIqgU#sjh4901+ExYcP=r zSY!`}@VB5(V%<)3Wk_v$r5_aMWrEEcVx7*7)L2)>(t@Px1}yua$BD-?vv{5uy%v-I zb+}RNp=6C(Hq?S&vI%5Mt=BcHzFHGCinJeP)##t$?q6)7E@!$mRCz&TG_4)^;6kab z?UJXK`WC62KZH;#AS4mhAWFM0dFZF~MI|)ej)&3o-Ped#4Q?Z9Wxk%zxl2(qivwx> zPX74KOsYRU_h6uu4Kn%41MWx=%S!w|<^nk!p5KCTc#+yuaoN^D8nd9F?@d9u{s>(z zv#Qbc$zqm-k<)CRsV`FsUv~1|i=WQXnohW|syEUtB1t^Ma0}y2;L*FK&v+(7l^#oix>lK@bkEJ$!L@O} z)@cNI+7`ZN`1$slBE+)I5&JXGbHOWZ^(S*ZeBNXhM@TVHkf%t+HKJ00x3}Dlm?F9b z2@A)^I8pTEom`5G-ZF$L%L$LM?p)qRRC*l$4p3GEe>|}HKX`lVsJNPKUlc+D!AWq3 z;DO*y10f{11b6q~PSenkU?I3WBtVehPUG&9K!UrwJKgka$hXh9_l|q^c>BCD9{&_w zwN|Z?SyfYhb5{P_=2-Ljrr33aTY4L-zt8frIw%``SQ7gmB5Z>YXnw-DIIArkRQZhh zr;;1g?y<2in={aV2C@&>(WLtgy&SBhm>*qu948Na!xB6Fh_QaoMTKo@01D&Ui*&OI zU`AT>WkilIP>+61Zaj62{z@XEApw2VuH9peSnTS`3K742b3JNCm2X^VqxtUH_^6=> z?&P{WGZNM*-s-|#EX1nv{mr@Omd?+lPP4_8{hDJxo!YF~b@zH`+5GH&@a~oeWJXf> zJl~Nks%YVuehPf*L`Ho^LVf1=`bYz<_>cHwL3q+R>QV7EhS55EZ!Gm>h21E-M=3Oe zt4Q-0R2G#IFM;~_!Q=taU~zD$H@Y5F`sJO_cRpyR$v)ja;R=En_Yb@NaalY)ugrs9 zgSeIKnV&3)FikVX=b?ZMNFVQ}I{BO-JuAf1`-<^OZmpA*J=k>mizNd1L;SsZ^ zmAv7OfxjZ$*;2&9p?KiG zr~o$asB;`fAU+jf_Hq1Crytg~JC;?@{q<3SAre%->u^^3@K2ejpd8$C#8Ng*VbkWI zG;>uaD~zO(L)CK%t6t??KDr*)&t*;-vc8}W9}iYRY7xMKzkc+wJ|m3eGA;Bn8$xk( z+2wMBHRv}lQG)6x`dnWOdF_bTsp}o5*@cTKF1%+iY(a2{$Luw>y$t_?~XR49S&>>S$L9lfNl=pbzoA4042y4Z&g<5Wi10U2Iv~2cf!gnx*b3W2| z-rpm`{oSWmqQAPzRPcAaNlCtaBjDGHuHVo@jf~2HhSosceqqbBued$(@RAs_W8Jw8x1dZsC34yG%s#+-gKi+U1Mfp-6mp#yS>0iwr*F0@Av$2 zVMwV>FbodBN`H%E50~-Jr(%n4G0_|Iq?7y#pyqoH96(U{yWmYdrs{l$waPE}#Oxk2 zgN=qr;81_B_Qigg-Q8e9j>n0IUz*82>w9PyS&y$+Ojb@4%ek9T%K=s7?Yf6w7CRw& zjgk3a)TvH%4Q=xWG?Zv3h`dlS&}`ra5`zGyGO~*Rho|1Uc#uFbEF4f zvOfDN#P#G5NQ^jd{2VPU;#wPp@h)CPjS=4t&Tv*HR>WXBI5=pt;d)XR`~y0G8Z8fe zs6iO75y8hXS}w0^D-p%Mhh_gN-o=BKU%s@Aw`cfA@XB^V{C62;bunyW36-@k0hvo` zn{_k?s6YEFUA_KQgYod+|Hbno_M`b{kbgd*bqB9KE8=`c{9O|tAUHg!&ws7ZKu+^= zAJ0RO|0~oOVpAD;#pVN(X^ft~^<9edz({}clWP@3IzJ9Nv@#;G-u-ny zFb}*+%iL!p!qg7OI;YqIEuz@f7*|bKPd-SXpUvGS!ud*1{9@l?&!he0o^qK?6+r*D z{(ni9|Em@HZ^?g@^B;P?_{?JQd`TIt%NgP6)FyB=Jk7i_n6*c{Zv*&X2RnMjZ6Dw_=1}*;k_p0#fwK%RO#7MEGO#j&+~kS z`%n+ZS<7xC0!}Ki3dW;vC9(1DZ*}B^U2(Xe)}(KODW#L(0{_vF)=sxmh=J1 z3_IgRMv`($if5#w$eWSw9RK#!BMFgMnYJIa=DYb?u+tuIn*wei$A@ z*5LGjj}&lhlph~GVQ;v8u3E@7?>+fFni4P(k>73|=b&i7mW(g4_JrvUTjZ!Ghw0jT zNEIiu;k8SJ)R}J)ZO|SPIz^U1(DI_=M%y((xZQQZ*`BLgVQko`+2Y!|j&wOW_3>4z zT$5-a9bv3erNi0V9*)^woqX)FpRv_jcL40u2D31|&bA5hxbyW63bN*Cx>4UYPm64l z^KCaouNBjmB_>|1d*x|?eprnsoIZ?I>@ncI?1rg~Z^Liba`P(=iiUQE(Zsb*gs4rt$#?8{j;gtKeY1`ha+((W&69`K2L{2W)BiY-2pj6NWy zWwA%)dS3bJuD3$rAUUakwvz-X7_pbJ@a-@sQ!uS%1R6@oVkJBcUw@A(O}w&>ZgdQb z%Hl5H6Jo@^`f@%pi0PSOx{bjU(Lynj>v(Rl9bcFgCmp??a>0a#87x zcvv*dNbov+uh`9LD=&a0asW8;&i3nkb81ipE#O>V$7P0gn29)ICZ5iES6I`~^YADE zNCxq0vfzUHBUFF9r5R~g5oto^{-EZhWZqg4<;NhD%s_Qk<>g#8JCXfIZEo`GZZSIm z4QAGb1&3rQ5_={rD=!3It~}sRE3-TG@v3!K3~Q2oJ}IO?Pn;UZ{{=z?%=5HRGt-#I z_jqaik5yJtZ;Uew*SNPzUoDj|%woNxQ{XB58A1WBe9RxgoH&i-(?5GA z`@v{#V2-jdd5X(v#V8+ry$ZOxnkeVf6goeQ-$Rawk=66*q}j&h59m1GRB#vnt)U|d`{w*_yY@9+Pp7MD%oANWcdPm#(kE`X zkne_Fij#<63<(X}H34}GB3@c^FJ$ep0#nkMPl4O|xCi$-h5~LClAutl300hBsnujq z{FyPC=QG>FqDOU|xQBzgR^E-voPei&XPXpz4%=|D4I!LNIYtW~KeDJ+kBlf#2J)Ly z;IKD;s@gH}^z{c3G9xW1xEe7HmO^LJ*W!gFqx0`?Zg1GU4$WptN97T2yetNdsC-|n z8h-#D)&OE-gWG@m0C+cf?RfkvcldV!iUZu#knzIyPRThn*#QZ?nEC{rjzeQDzyyXE zM48s8i*21r1xL@@)6+Ke8m~)WLWPFQGE%k}D1wOiZn36nb#axhz-7AM z^zS@65slWX&xQg|Z@MV2cju_>2SOGn*0zEbi?y2*A+THS3NS}c^Vw(bj}N;XeJ7Ac znuq&1|HGvvfzBCU4i1wcaGpm?)1~X3>(y9RlE|#mJLkEh{Pz>&T0#3`q}iizAy~JW zmCOLeTmDmmXCbjqy_=TT<-fGMFX7#)4X2fAt$Yliz+jdt`T=3T%hiI3Vsjf+?GHwJL$0v7tS=@2o^J70gRvIFgyi_teImJHktEE4*d=p}Lb_K?@ zO5ZktId!qHTjJ2X{$J?6&f3GJ+O~IfaB;P<{!B}OE;$iJ82`3g-5Vg3{x*a|Xn=R4 zGih-CEOvn)%M_3RVv?MVT()i^EUSD)3RPfcd|xB4HsL3j$gZr=##&8b@9ml21T#Zz zIwi{T8w+_cIXtLwfZm`%)l)EHaMjf3-enMl-5*P9p*(rg!iR(SS?wbyA{X}sFjUoHhAH9;9Clyqs+)YODvn@D=*TaCE+ z`HB2X^y(H)tU5Y7KcZbdxBkoE#1ygoWzG;Pxc0o4^^m~chLcq@eIV*T!Bouk|55$^ zd;IFZfwumiMgP6V_unXk|4mU$NXmYzc7aXm58&TE0ozcVQp4Chl>bY&pR_UXz6hku z@sVEV z5q`O>;xA4XIk8p;qW*HLeFo8qi9G`vw$}%ZLT{y{Vxpr9j|~2jEwo=0t|6kWb&V)iP*%%i}#Zu ze|7q6k=%-LzkjP+j-+G1{{Cg%`c{GUjSE_l%iDvBoZjqYZhO=s&9c=rM=OA~9tvBSa+X9ncBkgV|s$5^brvnpag- zwUoE*-C8SlI}-XadhYk{|4`A~HXhpxVSdEJ4pwN2bD<@>MN_qRegeC*M81*x`_n(} zW1I0+zI)r7huR){n>Lt3;&a4Us-US6{Lgtl=-UQ}*oV*wo%o`>WZdKNyqa4%#=$9b?;c zPQ(6Xrr*3DrN31EFqu7-r}$ArnnqsJ`tDKTvQGK_9Xcc1lTps6vg5UX=l^xmYpW*g z#HPrP?rCZbe`GZ0+hYdptrCCcOYwa1Oz!#!w`vKdgDuh#f0dM0l^kiS2EN~Wrz(Bs zfAvH=iK4d_DE4-0XUe!Geo{xf{*49vXYPEIJX@Kpaom@S3;4&zPxb_ zxxJfgy*|=dSK@Bpm9lyY<(w~@iEK}hp`1D!y^)^_{I+@@+rS})=Qam$4$bkj13QyX zR`C5%2?<5HybY1hSH+z6Pd6<)ts5b%Q&^#}bs z7p@^|%jTbPqfri42N&u)n&oC;3nTTTOh@Cj%u1x-HTFq=G2hhVt#v261HCqXiE$mE zFzI3W%O+LU2-?m>mmlqVc3YGqBc38ZEiAa-iKljL$rd(!{TCKMwRTXnwv2njoW#Jg zMS4~t(NA0I5n2oR=%%=x`C*~gSQEQ`Vy7MKI2hitrNymLrDd0 zogDH^&S8u{?V*QzLXHee6%$Q=^2OfmZ?8L18gx#nELJ+{5#(dzKI-VO8LPqH$GFZz z>#lkh4)=Pz=qM7#^OZAVCfFb}Ya*A@XTlDNXV~-%dO)cQ%qzQ070UqHhsmZy^>A0m zZ!Y?=G;VefnYZoOYhwhPrtss-iQ`I4oAiV2q(?eK?YAX}oq$&+TyZ9YCUy?LoCKdi z;U)o_Ff&7RCkL+LbNUi_l8GTyyM^EyV@^9UK zzk=U%GqxHCBCRi@ketU&bZK!AK`l>2XT^0MILfykRKl_|BoRNQKW)5N&gq+L`k4<1 z$se)MP{62#CT!1KKB2;e?#}xi?6ze8@(;2rn#*X0vF4UZc0HGhlr;)@8zOE(n3a1e z&)4TDz&TW9Mg_O2vC*LkNFZ6S^$Db(c zSS{~|5C3-_LIuvK60^Cf!zMD~d(QmIk%l-eKVp!JuV22Mt+l69%TovpEHJor6eYMsO7k+g92H;?v<2_^AD!jGOmp^7O++B35AvO zUxQOgIT#$x6A@w>C_)v+yap|Eh{%WyO}Y#MNEek6UUeYF4hNUKpL8B{Ih*>~Z>oaT zM|M`aR?wRO7JfH65mmOp*4cc8`OLSGJ^Ned<~EfFdY#FJhdi_|v1N?cf6^+jJe-^O0fW%)=y;YB zB%qGf%j+UhbyDui-}BRGOwz@)GSUrkc!&SwR9xsza*VJ#P(h1oxq1$JdFyPs&D)?b zl?l#Xa8S;2=*RUzgpSNCtIkc|CzxdfkMxS*Ba7rw7H@FnDTw#cQ3{Wjxj2lyNIcrG zYJKjG2^pqp{&KlU);pJjBL|ocw)*1jv{iQuxV+Xi{is&ex;9K*hetY*JPG2>RUZ=r zQvp&PP4&&oW>YPJbI9Z-io)E`&`*9Tt^0f43x|B+jvkE9ewSm5k|ogZesmA_gV8Zk zDWmMwPq*!SG4JW?&egP)IejEXzo*mhU%@Kln8JVu+~QR_q&cyG*}5)NI=qDSmKhtp zXJ}{|OIb)j5xkrAYKV|8lis{3+v3_n1BVSut@GP&tF!y76ao%UbHQ; z9!0?q#2KdGul_u0-^@(?Wxt8WmU`b8_x(p3l*)7!a;}E<+Eku$%e5ACWu@>8V7~3K z>6%MoSN&&}sc=U_P^>;IOSddNj`HswBU!B8_xo}^4f(bfQj zQR_whwru`7O+EexUR9hU27%6wbFMU4)NW(jmtyuXq_r1V`nCL&LPNy$kdZRZy?S5k z%k-vdE#ITixT!NvyWIK_0yIT4#{7|b32Eii%klhiv%pk5qUMA@M*Ayu>$fE8Y`8cG z{H@IGCa|)YI#F75y4Dh}%Cp#F`nmydi@SN8vkC9|@fKgYD6;9&jwDzoJ^Gugwq*pv zn7`dOjqPhW_fK+KU*B3{3e~-`I3Eir7EOPlm3sCbH$05G-YbEl32Ps`sDyR0B#JwNiQWGee})M+>!F~84LZh1(BL!!a5 zF5F*QK+nE5puB}W;3T%gYlU^hs-L-2gSo2L$o6hG{RN*M&K#t#GKDpi8^C;iV%wxS zfgd1e9tIBbe4)whJg64mGKX$Mf2ERRzsk30(yqm@ z$lo)E2{@i!d4kv2RO83^K8%<4?fXX1TcLk*;>S!j4i1bR4Mf>A6_mmNKT|>2w;4_h zQ^c74sCv)?Q54Dp2^q5>pJ7S)%B(je?ye*2OA~*JJv4KU zew3v1KPoWTd^YDkhhP-@43v2?@=KJp=WJ^`2;kL0!ThR){glDVR#s(kx(3Z60) z{aKoRgM)R-+!)EU%6;;_^tE@=$_U*E_Ewl?E<}gB{27h7&Fk!STst#nwpyOfae?Ojp!jrdO6Y1~ToNE`7I>9cGlt zb1%+PKlBlpc7JaA^L4)~_GA+)g4_pp&W^OuknhS))qx1wki1UrSpk~-0G_K&rLMhP zNdhMvwM3jO7~&}^!gX7BR2}ed`HZf#;Jv0~5MZSe$tu&kqru?j^aXIRyhM$SPM>!# zsuO3#dsT7RTj_6z*~zWTB2rkY(MgkKAM?j;n4qC|;5)obgVo`>IT<>1dKrz2UBe}3 z7JbJ!ak=iAkD*@tJm0;~^Fhc)ILah_{@BOx%C+tN>fgH#kW&b>ZrgInL*v>`B}6dx zLu{S#2ze51E?HJ&fA^=wqzcnhgbUdOw_mUB#@^NlN7>yt4Qp*$HQ{>e({_wj&jl0^ zuG2=3y-nP>T;A|FX+4`S=c6orA#`3^p#}PK8RRcSEU(K&Kbm)9Hzs}5Lm*KVWg-Ad zYwJZmxDKN6V$6Rm5C)moFJtmYP>e-E(UhA8eqa??C%5WohOu;R(DM=zgo@2%==#7Q z^-5R9p!K7o)~ntX={iJ9wf_635NA5iWn-Fz&!0QB^28zgconDw z!wF~{@YgO=SWQY)CR#o>bv9$AXF&Z|^3A&Ob&M64y@%Sa0Brbx28+ec*9WPZ&SmtO zDpsF<4HefnqCo)SD&NK*c5( z@+4Y(SA71l9g|k+YnlYQkVqq(<`}5p5@o|#T3_m_^fdMAi|Ks4;SYo_=%+rO&Xt7N z;|sVD4xr~&dXC1hmPzjmDx@Pn36Ly}Up`DntX<~Lq^9;12a5brsVZ1KVkBmGmU5I+ z_|CD(u61Q*t3wqN?Ffdq+f1dZ9E?=GNg;iulAD~zUu9YpW}Y1e;LVlj2{gFx<{g2E zr>K5^N|AEV^(^UW5+JIuSmRAh+>tns<+F)*rCk*m&4wot>7r6uPF%e!9@dEp%`u_@ z^<(@#((CKasPfuf<<-5Rv>cf^og5Mn1aL&Y%NK$T6Jxn2bkta*tKiVUZUd_Qw1ZtY z-Wx*2V!t+&*l5jAgU%Rhnd+U0Fle!yTu-}9I<67u9)@z9KdA{VE}^4*R_u06S9h@G zdM#{YcvH|@QhpaLR`~+-+M9?1zEym1+Ub+#k|?$Dnxqt0oVXQ(*|lF ze~qiB>8Rb3y9;h>SwwEzI&=rV@T+Gb8A?;ilh_&hT zA<9qbB4m}$P)M}RZ1AE3Qk6+h1I@HgI|Ubx3VL$T5;?&J1pNsg@Q6rWN9TW}bHL@< zEL~fPSxmv-4N3zB7w`>EYgXedIAoG^mD_F*X&lPmRXT9 z_M}(~{P?NT;isnG%;I>Sm`oUvtCi+VfT;7}!>pTS%mx_VyNj6;>sxE0J*K*Hy7nL* zHi7G7I=#Vx$E}Ugik;#cryB`cD$vQUqVQjUV~HC;>1eZ{W7qA={EviH)tfvSX}p6Gto z1%&*%=d{)dn$B1u^kb~*W58k_ z;_k}vgSEoTM|67Yvbd#p>p)v;PhBFH&A!XH>!T2RdZMC%T}h*SpeE*0ubFS-u|hjr zvL5ltdIwMZ_6-4p9qI(Zrp6)=tX`@|5rS^j`D2W`RYN))v0u*d>FfX$%Z}{K=c@uo z^Bp_te5u83b<_7sC80<2!K}^gR)f5`&1NFwtvdZ+X^#Q7gMN`GcNFsj7FTNd?n3N$ zylLBdrpK&?A+)|b&%H2rm#}^e__vR$h)Yw5Fe#Y~CB8ioTZlO>(`a8*iMML}llwML zu-1n!h(&gN8>YfUw(b^PzJr#xublllj){4HQ%be#Ib)gNc~Voxj!~k3_@3P9BShp> zlb6(^vl6B;y<0F7$J8fxuH$o@qvhf!09hT^+^BUI6v)iQ5==PAY4M0sQjBUuy6T0@ zt5ZSAMQfRI^oz=U(u*Ga-_GLQpSX;;Jm%j$DiZBX#!XdK*ShUT8R1ksEj`@$-|-01 z&QhFJuWr+KP_&$C`}OR=LeOus5|L5hg#6YhdbPT5L$)PVi?=rLc}HR_4tROe7F8Gqg|k|DYK%GuQ2A2-l?8OKwvfwd{?L z9YbW#I7ZuMgw!7{>AFl=`^*rYToWOP0_6t&c=Pt|GqpWUy*Qn=upQtwTKTP9LI z7zV$*x23F!#Z`j{#rFXrqL(>mw)zT$2&+8wFjsTGzvG=Kb%V>M&oMqxOTj(|Lfdqy zGQ~QXnIc}-x_!$C{(WPLQA3q2d~AEch?#1$hzHU5Zy^zL$tEOT-g)AwTU!;(8lU_8 zwxY~_j*qWqhL08hjRT2mfHacIhvd&PZiz<<)K7SELLIb-_<TBpGB+>p zWcSm%^hhB|7nd(DrPrujJv|Y%(wy)7{^|o6o7(sI3yF>qA@#TCCvRzKQ7=&qjg2B= zVqgeDOsm4U`jgPPPP1PK7{ta#a8wkon3xzMZsWh+>PO@s97GOVcFxY;%3Wz75kcyZ zucGkm>SimZ?X*iKLK>6^{_1W^gNzYj80Hpu6vUPnp% zg|q+P0#y8;TKt$08YEkS*AI%*7&J-LLC?!OE*YYLK1{CM?|Fuo0Kq3_e+zH3LQP1t z?fJ_Q#@gY2WE3`3oDh^rcigvH(7#&t{-?(RqO&?|MCIniR=$h3RK`V5(uVVzr4S^7 zfaBy;Sr(gozl)>)uqF0SD*rVp4f;Tjnf6KUE5^o zWbP#qoLW!@SB=YZTYpf38gMlrW+>%|NRgXVcvu*nYee3koC>a|ge6dAZZ!=LT|K~FXnBgNB&r&ua{VvNNrVP^2zcfn^300 zbN)(R-;c!8K$?4qTllR5?_$G##T}t=tA|-TCnDJF+Ut7P3jNKVG z-GZ&mh`ZXh_;H(2o-3k3_lw_$yPhE^ zs@U`>`MZ8oL<9E_ozLY63HbA{WSa8AQcZRR^ln+3D7_VC8#C^M@jhot))JRwc+a9y z&|6GM^syB}WG~Os9${KlQeBQ)R>%~K-ekWU(sPaa?su_Al}K#e`Lj%#yU>7tLdifW z9@!==|7Zc#Pgs$py}lm>D7I{6*a#(^8=G?J%Fqm0Fzy1KI}ec!Yk`M>R(&*LrJE~h zLXAjMA{N{{F16-;XQL@%)z83-;LfITcFG61{R`Yev>#|w=ethAFmH{iv%)^|MbGbF z=#n+d#726wHjYQql-Ps$%(TPij6WUXi>9bgb{*^oY3Wm#(D5Iyw&VMAASG3b52!_j zsL`7XsA)lmesR|Tn@mlV4$?={sYjmswm$}pu~w<#rxFZ=GB}D3D9*Q6?}G##2%tP} zv2CS`9?m1rr0R&Gp06Yf#C2~}ny(6bc;bBT)0iG#XIA*53LaXl4cZ@h8R$6IMJ3Ol z`g`P^%Ls)JXAzEvBgfpZnmR^ie{9?@3IQ7UtBHi!kFSaWF~Q1JsJ}S~zNASre0h~R z$RT1@csaFy9+P^d=G+D{zusor7@-<1rX`j^e<{!#PRbNY)p^u zpI^wRyr%hzC%5(S^;7g{yS^sB$InV{@XNe?Wiv;GGOPLzh7N{2JC3Jq+`^+mf)?Ma zR|qkAl%dno3zRDFH=Uc~TXY7xeOh%e&+0-d=#uEI{d!e%sO{|X3Tek+1%DM5v%0jzMny~Hoa6$Jp7nMifhN;s5#y3aelo3*D3=zzP}`te7ZV_ zkNk4780)pE9H2ZwF=%}`|b}(@S>;q z<$?z;@unj!KZ|qk@-Mue-a{V>YU=50lBr`sxx2(SwGkvkq&Xhx;uKQThBYE-o=}p| zsJ(RJ*U+etXf)@?CeM(9w()@**XV3Rm>-$bCJ2Ah>`*t;%f^}`B|VxQ({*b5*y`iH zwv}7w1*Xl_P+kg2GPKmMlNV}wLu5wn9Wh$FKUhP@vEH}B0Vy0+^MM+*zo>2I}CH3bmS*i7%uq845e7yuV9g$;0=cAP`qKt5I>Ej-+QTnk+!c(N6 zQEKYNH@5=Wd)+=2^qDA^MU8ZFafKimN2R+p`CztwCa#J{5MbIBSBcrlL>0YmjAg5E z@6%9?=LJ4jB>>MeKc7s_0RhlaimCR%u4ij!2XfuXQo9Cv2Vs-<$a|tIfqMc<(D}YY zu@rbVN_u+H+X%Z{{)FA-ptLzH-D19e=UczN(Bd|nG7>GFA4~qWpA{?g6`T3#3>ITl zdS9&9XQQ-!-0N1j{?wK1;ZaxDv=8ixq=g-$aPm80@;GIl%#{F z9%(JiB}C_|G@G!?6hWA6rXTQSnkPVO%G~IpjHt5*0aH&(=xpdO<6gV4y1r@^l;-#7 zw3AvCP5-u7{N1?s@MNr)+tTLA3}4xsF)-y;t<&?Yk~!2hZdgmZ{^h}mQHGIB-~?JN z{bd!04&IZ`l?SWDqyUfWOuqsrR$$P2p-!`0e-gft@5ouY4+duQVl0A&)HM@IXK9Av z=~kPEcST#W?l$o}pSbjP$Kg;a^&-N~YdFbh`mdb&!=rZnUu9_HRIpFa1d6}wzHaQ7J+5<3*75?wtjx|_nyqpH8r$4H-+H8Q+HR8g@am!HNJ3eV zx&sgoF8qDGjKYoL+xfFw756c1u=Pxe}0I0S>N4%e%LSR@V}~^%q|-0B)CF zR6bxvgPHxxJq_HYp>eD7oApotryXA}j^L--#pZ!E=0FJ)rPgx_eq3OjRat7!MQ$qZ zz8_UD9~5?p!*1>ULcq{)Xnb_8bGmNrH69ut*|^OTq5c#gk$Jv;CENnw)cw7QFyeiM zFNedy?Bm3d>+=G!YU(;Gz%bpW{@ZH2FT01Mt)(TH1p7L0RK+d#5B3N@U{!X7Lb-D~ z<>kE`V&}-;}B-c0RB=8#s+1Ole#;2V}9E%J@!L+}uR zfxdm;obM)Qnq*BNA1HRT8f)onx$BleOvg;&P5LuC>#2~guD35@o=V_B*AG+D()7ld zt1S1AdG}}Q(B!6Rf8I|VJ&X)R`(XwdyC4{M^&L0TE^sF4#2t&XBP&F)EJ)-MN&fx; zEaUs1|9OJU_VC`{M70o4OP9!eM@!9XzdNZq9R0u{=sWFI(3xosq|2;(dP_ z3(wGwPAmrJQyFCcsLqu93kwiS-;c1#A*W|0ZB9J2$U|)#_kZisfE*GrnvGlYEuYxc z2VtJP*3l&**~q5*N)x!8Elg+y`1X3HMak7HZq)Rzw({AAk2D{;hS)&gTqme9;}%~# zJRjeD<^CHncl3o=FY!ZOGsV7sgttZ{vU1;a#Dhw-p}hMG>0|`48O`m_k`S4>+&|Q* z9~r#Adw)RY$wvxhtY)$4I9)ofe9WvKk1@`gGzC`yOZk zSznhhw#trHC=&88JhFy_a(-FyZwK<}>#6Q@NZVdEzlmkOJbH2l+<#0a{YdNceKyL~ zVP)-~Cr#XDsC1w|G_C8(QS!5!IF>jCs13V;m$mcz75CM^m`60ewo1OHnpL76a4p3^WXYl)!CN({eMA?rL_(*^#LR$U z0o&2ZokJmIt1FY6<*#HA#w$;!)%I5f1~tzsAVoSS{c&?{qqpHAP|d`-T3mUegdEv~ z1Rs8mV9AC$RrXcd^)tHaq!TVzzP%Z52?SjPEm(%?WXn_cX7i(eI?$oBRYje@Ix0*ATh+ zTX_#!j@Bk|fppE3b9^m)j{@nMPws5>$Jlwpa|0J&_zGMdIdJUNLY+o@xPR1UD-Jwo zq&g+SoM*cyB+@o`M*OX4ub$Syups#tqYzO_nV+ z-+77?2^WHRetY_ z)h?D!p<06wCsJ`X=(U;ur$FtMP+Emo%Jd+Xl*?cmqo&x$ zopHL==~YqkXwPxKFXj}E`QDX5M^iUjN>X>~D(+1J5<9(Z7cpCA;+yNZR8=N~RH|B7 z>xkiupd^=b&`?z2Xkwl6dRxZ09m8S3G~3kicxlu~&VQj#PJPY7=I6}^L_$ZW|NY~gg+GjABSM+|&L((PwSWw@&C$T(N3>9q zyH%^W^Yw>T@fc;1%ayNGXfDQ4DBCSy?8U`9#<;wV{bRsM(t0`Uvc*|jM#AJ*B;RA& zia>O9^&cd7{R?j$3}x&TaD=A2qgOnb|29f*EuAykwy}oZ@@98V?8Eb-)U)-4j~U2v zk1i+8%NWrL#9-?!hVadQ!Lf*)fAIn@s=T+ z@Jyp%TR!J^)jNx++iLj-&yV5c654GOpQ5claEHnwcfTVnOeZ^?UBtXUOUG~)P`8zd zrky`K-3?3+>DGpJ;b6-w#7*g+JUJYiePoZj8qR+EzEy%;n0gw)uFNIbgWS^QVqN{I zf#%Fwds)zYw!wx~ZxT-&CQF zzEdaafLiQfC0oU`E)ql#y8>5JkZ$@^;BUCu%va8kYaRhr^+GCx0|e7@N%ijbORM8) zhU?ILcp6v0XsOue#{wFNAuAkm#y!enJI?9#`l{#7E_Q>nAnb;{I5gkKc(DX-UdAwN zyz~BH{GQ9!y>pLStzKrMXy%y8+Q%6a4L$bnLId87`s$3Hh5WhLs6%r z*eJtAWIfogD>t>b68_PC+EWRYwCLsdOPkRoCOH6lTkWSe0_yio#=_{}gbw1q!0wE; z=9L43#aQH}V*Xr&i@V=Rdu|`dByx45^I4yK5XZqKK5Dn2F6X|{OLGP!l#+E{sfBr! zc#0p4a(+TkvHFD%ufgV|Qp>JP2mN-h{kaTe9FEO?pPOa%3uXbFd za>6aYc(L0+p#XRN5zFKFD$SNJUvXcsV^pi0@n&{$IZ%SIp{`Ks*VVUhZS{KTP4)ZJ z@1+5j@jl;x{Rjh-yV1_2gA(M^qZ7*^s?7ZkQk|1Xw zfQ_hF7Q}-4@s7MJaPYd^(@G2qhr0G?7Wc37smjbWq{x~C!qmp`~F)P@+sYr@)xAG`R#V5rm0EbwA_&Q?M6V&1n#h$AKN|B}l zri^k6Bm{0<#mpVIorW73K&vi?#BM%NweFFm5_4=0{yIFCwZy`n(L`G*^l10R5~>hg zw`v`9byPG{3p1Sao(!tSp)EBgHKPXln>dbsw@&J9G}N~p{086XXUbZ;bH$zOl+0Nz zprS^ujUm(vHI(IIxSUaBR-XTPn)r8I0grFA-ty=3fYrVG&F-6A%oXJVFVL|Iv+bRe zpq$Egckk1#IK75OQ7?T0^}-3VkvXl{9EV|<9fmNW>JH^o4B54ZOFf-u!v`6XpkyTVNhRkV4_amwepaAuh$0l%$G8p~L2Zbm~RZ-c|9Nd6^f; z1R?5*rR@^yCn@S!U8ryOjP8j9)oD7m*@X`Yv#M$um40FxcC>;muepEyD)JNk2XzJi zPkcV`&cyl5mpG~g$po**B<60~dmGhHQGetm284Gkru(i>a#*%b`i+he#wkDLLQb&- zFQwCTh^J}J8b#H>ZaL`>(D|M1ry=7+j$X_$F!S$c2v(41&;_UGab zX8QOX37^;61j?Nf1#q2^f^=jvrL4t#A;i<^T>|surFgs<{7>pDR$}hueYUUB*tkaB-N%#1hndpj z@MxE}u3B-&e+C(d^KQaEx!rE?0m}J1uK&aeF|%3PT(|@SG4J_iSx_MjR%a{JYl0Ii zR4Qj}b2F~eoIuBZ^h#~h&n@WyKAw>1x|74!aD!wy?}fDqPG8r&f6u1u=vREG-wyQ0 zC~13eu&<1Q0{!z)yvKg9R#Q+p~?zw^?ivU9yjU_>x87UxDu>J^<~i_2|}- z8N;+(W`(=&D$8ns3 zwa@>^95;{G;?6q(J>X+ep)NHpmcQ~7La^cGFsFTj^p?W;zK@7KqHM~&s2_Q(f$H_V z%u>NWZwqS}o;;Hj*MB=_GI=txc3I!-`|e+&4!1LT?yx(KS=(|1i@+_m1KAyp>&Cj! z$v=$}3v%CyBchHzK4uoX;U8DI7uyh@b$iL!LLZ2U@%OtgpUl)b!W;8h@Hdh2C(0DD zF<6+{+*o4}&)$o8hsf+~es}_Yyy0A13`s4`ToSG$C!f z9|6P$^*>Ag>P`@+{KM=2X=46Yv+_Sp{+&h!;lJtEn-*-cmHIGA2`5Mkh6-}IpKKq5 z`wNfRu*)A&x8kCYg|Q@=Jr2w62O$BYd)d%E&~a$7;?u*Fe5dojWQ5-$T|ghsikFmc z{{QOXKV6e+tsg7LtANDSL#aEHZ>WWgC}i`Lc430{OFHSl3z~8s2oJGL@M0APm4*w5 zK7QpKNaVvz;j*Q;G^~i}N-Ev#>uUQ)0pfM2^}d3k`4I9&vNJX-z=9tDIjZ&v4VMe&>f@uBE-}C zP8NX+Bc9Bd4Qhz-uMh1MTDv&56IsWg!e->&3z#-X?dLrZ`AjRa@vQEKoXYp;omg7) zC--;G>ULw1_@k6uYnCBO?z0f2@n0X+GiCs0tGH-+{? z;obx&2RGqtG!8KOgO>GoVpB7p$Jtvxr;ScW#XE|xeAzWJS3&BMmeZW67XU)uD6_Zz zz(wmSF_}=4thXA`q!}1sLgm?lgbo$`j^Sb78|HGyOyTinhEb)CFv@MjAazBMw|5rV zy80Zl|7O)5h31Fw_#AtD`hRG9>!`NAwp$cRaV-=p?gfgw)6(M70>xd6yL)MIcTe$B z++B)$3c=kSfk;&s8k_?sJxW`Dx0vZ)1@pZWm%vn1~T`84x5MjhCPP)R7_S z^x{LW2BNf^v&)y2cZN4{evngy1B8NEi=)jIXV&%NY9l^>po!Nh-}4@%;guInx)-^k zXJt%o5xHhzLTIjUbz1H^;YH7#KS)>fw#EVYK8W4$W0FFCtDY0+oP&MX*QbWLddX)4 z*_c*`(#}k8J&l;|PSOU3ouOQ(4Lo}!(pC>W9#~m*A?cX>l0CNmTDp?FC9j|!$HVb_ z!%lNS6nm}J;chFmf~1Dc^e91!LRZf|ywusppC6NA9?ZhJtUd`V05y)L)zZflDb+uG1n)xYR zh(}a0W^!0V-m!|GF#7|&{8z6eTHl#fT?yF;D&}l_N1NxaD8GQ+yF)zccVii!1IaNk zFwujh$wB%24goOio2%myI=%x?-hEJ(<77N<^sb8T-^u3=yfIm1q3jX^C&8Z@z8KHW zIv;F&GtOLKqKeRZbid?$DikGHIAmX%>wK@({e#jHCm^f=;5$4wP4TKZ69 z>?hg$ySI2M^jy@hM~%Juby%ooLQBETnZ*5~Lu-DCa(ed^1n%=bnQfeYyO6r{3(b#s zl8{%^%!ZxJW312V%MIS&^(V{@?3kY)M;yOon97q{7SmqV9n`7&>V}PDv8E(&zQ@XO zz7p7={(5jLA3OuI`e#|qmGrFit2loSbfR1vjbd-63Bk<8!Gd8@!sODG!ho~U#{A}o zGZN+UhHn$VsLexRnKKx{uIfeREUD`zQ<;MwNh-x+$}n=eqF!}+cf_%kJ{`(T%BYCb z{mYP*Pu~OhM>pC%Qt(uhbHp;$vhW71#145*mLXW35cECmSia2xPIntw=gNSi3A?n7 zn$FGek&sh=NW&#KfU}(T!<(#{2)no3cA#HX_p$83|7>7|Dg_rMdJ7g90%Onw5t-|) zKujH%@%Gt|u(imx#}ghboME-vo(U{cSAGgw#6ErH-QNn4UZ?d#Se*{!iyI?q^;VWB zIOJXEt-Utai0w^{OIVbCPA_Z-tS2B}-!9GMi6UTgw5Nxv0(QQ60rXDCdV|Y>4ipI~Nxh9zl|84kC=z#5622(xvq8$J_OfR@}5pIt$+; z0g?Vz?E&u;t{qN4rzdrZBiQN8$`2IhT8#^KQNqZDQjBsLP5m7TY z{Kpk=+mERUICp<4cDa^0yxF^|M&=>$ww3U{_RA;@BQDg@o6LUIEw|DWF`j8wkhMRzM`HiR+ug) zYxwR5{uoDlibza}%rm^Wu_KX_oqjnUukA=aSFskN>daKm>u^mkn_*ltdvv*9i)rrd zQ0~1`X?g@a^W_1$=H2gdZ^k%e#-x;YlD^zhfg3|gR78Q11OZ0cyfI0PP)Atd?iny- zTYkF#)1P0c?aH>#y5^apHba7dJnKU@S}<3`SKpgqoCl>jv3$D90TFV62w zSlC))k+{7t9y&KY*BesZPY`29as~!-InMVzSckA#;uo&8*gLjJuH~@YJHVe(Z;TEj z9e5a+Ql>V6+vA87{yc5)$yMhs_d1Xs53pe_38vg?&M&PonVZIfnbFx*bVktiiw}f3 z%qHm9zmU=6j*Ap2dU)6QX1x#dWNrG$n%w`94c6*4I61*_-rLGEq?HN0E>M5vE*5mb zE|f&{V)h2G5L0MOgKwc^s-et9mT|e&ZF+c&ri~_7xI8Uz2HPtp@ponW>c~b=(HV(4 z;HP2$&B^ldSGi`>>Mo%1a9M6j*t~)F@&eb4HzEEC7{^cw;HO0< zv2=!gYLplWh0yfMgrU!JUiVzpwXX3hmyxwXQNv>47WgflQ1EPAx5;D`&1S_r1a(J! zBkl0vZKlcGWIYv7e{&w%Y(Dk2Nm)So&>&U5w9|4FsgjHB zjtWtuDO}q_eDJW8;0yoWDtuAAOo}_Yk5!at^Jjvx{Q3~sPc)M20ipw+Rs3XvN^ev? zvs@$WI%ui5BY0WWf4QW>e$~&E_^OjG2{gcU5L#{~aL?3ZFBC6LlQsEft!zZXY+=!` zX5*9~Jo6NL z(cqCkwE`8+52RH1EV+~(zv?@@YBUp?5{rktH z=ClvmR&|is={EOILz?(rVE;aW#Su{14YMm)J?Pl26y)85mk2EzPovW3mtbxmzs!u)%qlS`SJIr$z|Jh!$!ge;_G_3J3r+$EM2#>?$2))=FEH3AZ+8(!)d3@BifO@KmXyB;Em z{7Zu!!V^JDFKOQxyGQNpt zt5jW?x`;Ei4Mw%A8)O~Ma1l+( zIiCl4o^Fnc1 z@d*wch_aX?M&+Tee}>4a1yDm!{~_qY4)9M^nyy&>(uxY8F(M$V#rWZcY$8xbLnfM31O#bKwyJ>(6=?vB?^ru_uA>WHUDJ{nw8M zVx(za&K!=fSx%DN%oF?GD+yyx7N5_1s6mXz``Wz65b0ZmA9)Km$k)DVKwUo8ldzck zkDuc5cu+D?#f{ZLLmi>fv(7VWk+SxBp$jy&x=Ft`D8`7`?{Y@-;nBhu~<$P}|4_$qNp$E7$FE$%4;@@P{!?=S$$k0HB;4;fc) zStx{OXrf~AsL;azk8FuVW}muL9v5En3&rKXO3L@_W)&56;&)jg8~WL-i;gRrru?E3 z1CBup9<$3!pe_q`sZRF0W(kw4+Y{9ck4$=X#(ev%CSRtZiWSX|;s)eyVgvL8A4NBH zEufuc0l(lKH%)@M%=a8ZN!q~!HAlIJLVm7v3+mxa9uO0v?Uyy}GeLUGja^CbEr@$SEVt@@fYp^`Iua3Y$NSvdr$U&^Z@Wu_m+;O|-izt{?T%Q<$ruzGL z+se5J(^k#x$g^6nlblcQMKn!LY#g|Z)hO;n{mF_`i*(ukwvkDZFssNX-tYUk8!FrA zI%5_%%VdvTjlhGC8_M0`*>^0BqG18qli|+Oja+MGu9RMzaur^!adW*Hyh3Ms6$g4j zuS1=#>JLdCrk+!_TRl6ovfFbRL5TT5?4Pm{biRZVUv#+}tn#;V$R(~M=Un{&*Y z@00qcFukL?$K1MUO>zp5WlO~x9hruruCd_abS(o2O6 z0gjzxT`D8hCL52bjX#*)pgr8N=4bljLgD}(Sg*lB=qJ5nFi@IuxN{r5Ni$F#h{N-_04tAXD>9V3UA7<(H zTr^a!=U)^tG`@W`RH~LzWuYLex=iGHu$qe5T6o-sJ^5=w#qnljwT49}=RoFq{b)_> z#FHb^T0pd)2UTEO6qvEh-%PiJP)5Xhg!`g9%vIt6l|P4d9vcLXD_Kv>3in>eh9Kik%8~jz-Ck zogP)60X$!^v7vEkX|n%BdBDufOdEt!+vko0G_j5fWPfvy@a>?JBvcVTv;=h`c*k0u zfb5sumVV&72~+%TPR;7_|NIOA12k|x*8}FXG8g|K$7clsi`okpy+B8JuYGeS8`8m@ z998yg1GM0{Rfx2=+K{08)SRW>|9o9Xymjr>$;e`ArU6Os@AzfY%LIjv?W#|+&Wa|d ztvjuLUMM3h(|Lx;ft+PMpBfE-@k%W4L0t*f%OmigQmMj$(!k3%>)VHbt>7)G=JRkF zPxCo1SDh>ISyAC|CCQ^5Qc>rgLo-+LOjK#C&7qNn+WYj}r86b_p-Uda_5O8UrAm(gB4x!3%d95cT@~Tx#GpjnRkMD4Tn)!D5LO;DD zqWvG-i5lYwFWdU`$ zu&>B((2PdDq5Eo-ixB552YE9mmsCGm>A5=6CQ4)}v465?=Zo$O&FS7oohp=<|D16n z9=uXQ+V;@*su2%v3MEnDW)@Y{4Saqo4nw~hJI$P`Y8`~uWjpc*$cKaM^X#>9sfH(fw7#JV$NHw=Tez+9# zr%r9-3{`@!Sepq&^5ns%=!Bar-;3ldU&!L<5Qo|J0MJR{@#5*yg8P8rrlScC?H7U} zg~EZ6s*6rDZ1+O8sZw~({Prda(K=Iz8sk7So6UsiOBw9z5~=PDtdyD*2y4T{7XYIO zPG|_{&$s!~+gcq)$^SA1TkV{obDiifix;vjMDIZ26e}eM(xsYvc4|ZBfRp)|5PQ>D44w+87P8rmjjnN!B zZbTi#y@j!hI{Fh09h~qKTo4{d^QuK*{U|uci_tB{Nzr7OKhu)hcpMRF<-*lR7ke$7 zhvxAUl9HMh-~6IytPyhn#W?80ZJa)tuyj(hru>tgwT5k9`0_^j?YJvHBD@_B0^by8 ze)7kER`YbXMO>~FO{C<*4@8@e6^*)Y;8>6BTMXa_&b3XO?WpH^<|5irbqnwkth0>aZ-18Tv{8SS(!qfTXwW!)0I7C6nW2|-vbl0&$zti zZE)c+WqfcvP%Wrz9i9jQd6&+WP{=kSe$OV+?wq3U`y>>hFXK{0TF8 z;&{2+;h_`G3&p-!1o(}{eCfKsYE|;JFf4#uty}!$^La3p#D1xdBn)8>z7 zOStX$V%=hYTqjrTnB0(h0e&*;^R4Y|Fn?t<*+saLJmb9G(`LfLBY%C)s47v8f$;sR z)loi}ukAvau`iOSwn|m(l{&gsYIXclo%a;FNA%M4n@G9B&&vSInWCs~Qk6T*Qz# zLB6#VY_X*lyr<6;%W={Y-k~za^>ySOfFrT=(Yk-KUe(#^<@BwxEi~soU&pZESdj-cTrIzY8&d%{J-d$(W@AB>N)MG< z34XTnQfeAd!U&cCAF$2)NIcq-vtB}J=DF>!YV$lDaK3c17T7z4%CydiZtv(4f|RA1 zJ*a&B7Xt<(=(%Fbao9n2d5tFpm&iD-LA?Z=XdyAbL2*53x0As| z3P;WUm+&s4Ykeju_T>-HN!;uv)+(ZhXa;HY>}jQCB$)07t+y|U|~rmQwq>W zVognEJ$Kg=E!}dL&2(SFvGTjCS+;k2`Hf5~y*k-@%m%6XjX`yKQp%Ma^}C*jfr(9M ztmjEA9-byqWhbMBJSRsU{-a zW+`aJBd31xbK%o2p6t&`TxsUFK+{UGK#qbfxRbWf#$|$jrJJJH*ZgB&q6v~WChGY3 zIV+1Q;bXo~_JbeWEQQ{c_CU?LG$#&`KIWLg{>3TWFVS(1A4K(T^N1=V~ZCM-j z@6>vVcM)k6ptrpBn8j2N;=5uJG3GsRC2YhCughxPJs(S&zO(I;i4*FRmOHcq@6I(t z!f(d6sg*hZ0|0a!dx92|1{MFcpZ|0g{C;$7?7p%%+G+5~t;v}O{R1QZYbJLg5{{7I zx<$o)gP0DAX5P|7WR35`mCD{9_d^}$g#3i6z4}xe>U0Nv?_QjEd*CPxQw?G};1n!6 z=uxs8uP=og8#}Pgqc;E;UnB4 z&SEPLgSL~oY=P|}C%+7^8bO735adGhU5|I6MY!pCLmY8*{&f(Am1<)*Kp1??9Bs8& zv3=5cG!=ihSh16UyRth{tK;a|>!bWMzbI7?DG2OQ59jQEjtO<0P6%#}Va-czvqBdU zm0wQ(An7f(nZ-KdRjk#+lZo#d4{seMN_^F~$4 z0EypZ4DzV7jcg%nZ=od1+N`Flv7Zdk@X0Hi#xiU55W|zFrT>87G!{OqKk&?>*dyL6 z=?Czxt{?Q7pFO35JC-9nR8ijRjRs$vorHVvoRvX63pLBLM_SibB85C4#%*_xbFJW} zUk4H~o0UjQBPhtoFYuh!Dbsy2>0Ao6t%ZhFT?&%5A9N~~L_p3d@!A=>F5q_V8zRD& zh^T7)$m3w#LEieZI%Dwe=39#K=G`S1@f&igo3R_84og)`jE9m}x@hdjvCI8}w3V4_ zrU?9b0=@%Nl?`X6>Tl9xywHAKTyP<1(FT~^^$OXFddA!AYwMScH24Nlj!D%}7OYgF zwwD7rYe(gZMi+tmbBcNx;?kv!EvJfApfR9;$uxP<`0`kFm=^a^+gatu&=~#93r}UF z9?`xi{+_ujn22j@Qxd67tmDc~pyk)~wBFQM9Q@5xx!G+uK))NWH*&a5+>H^T%R zowBXxE84q=nnK+7tQKWr-QVYUu~vPPtnQzQ0Wf~65vM;r#ty^gMN3)wj>+)rWk2}R z1O;2KcV=^<;354dadWz{pJlDUPi6-dlJ0K;WN|(t>Mg!Cu}x4t@iwsQOw&~1tR=hz z*g+QUaAe}zNqW>^-Y&CM7w%h!Y26_bR$>@s+D(Riy2_n6TSN&R+a5|bFgmYGeQl-l zdd@@i!onjz1ahit#*q`w2s#MTbpN5aa)%6#(o%7~!odQF#|%;N_6E%Ex>B_!HXTVq z?*GV*sxT`x#tv{_MH*w-Z>wz8q5IacLXFong2`owcplzquV7^l)p!N(Z@FeMgMn?@ zrAf(&o|a3>lNs%!bJ_q-yVKev!RDk#zpAiWX$`@Fgz+onS_pf9g1FA9P-KyNZg;cW z<>LmbDkAh-yDz^Z<$!$MRy(kt%gj0P%f`SJ19-Q0wpf9c-5|F1qZ<6 zv+JT>w*Kz@d#s7KZdO{t)TM4*DoEZ@?1O3{97fRSZK5T8HZ7$vw~?UCOeE1RpFnKe zg6=V>Z*-ktcO%>SW^!tk*hIzw5mIoe?Y%ph<#2=fg92eKO8>ALK)^tFsN-xz8(%*@ zra51TEdJ{zCf`r3E>wioqU_tMTV#9BW~6-tvm#Vbfr1;1EzTIdz^Zs*G{6Nr61PyT zWa;w^2Q0oS0?vWersvM~3zUCo<$h(@Q?@xqqW-*0(riUX(fgO=j17$C&l(r*PEK>z zhkVgK_E0DB`Rus6&&-rYxLf_ZSB)eKr@|){C^+ao>8*_TyQv|k%40_r=UxjS=pK!M zK~qk?O1q?!+U#EwevL39LHA6p$%U%OwQaaW3{|k^hFXGr33wjcShH42>q>ck&8BZ1 zpd`xFofpnB7Z<1d&LyVhc;Aqib93HTVg!?K&1n{(YYuA1_&CaxsDhgl`l^swuNAFt zAV8|~EwPneCq`^C`}>uyuP=fA_YQ0UX-6qBTg`=yz>zx7HQh!6HJ_9L0!~#9=Tlph z4i3UrJM}Nc+=Z_*YEt!$nd@%Q^W?o8QpR3Mb(UgVX%%9{CSNmo{9Y6>9Y7_@`MZhILNL!lsTjg6)e>)VAMHbCD8hd}k=iB~;;3Bll!n%dW;4>NMqP`5O6JP`BNzyJS z$j{*jBjlW{sIl9kw}A3nN&;G*n}w>k*3nPeGFpLF3n7<=j9*SW+>r)9?BAerdH;S# zRQZrIgxSH^cc4_w2m~EY%L_CnZ|r<+^*Xft^4pqAR;4v4K1DHMtao{On;1}wtQqe&G2c~I)O>YUoFug6enJ*RdHukw~(4K zGQ>ag5Ix!TPibv=rN^=u;@~anKH%&l06y{}a@O#Ppq$R>mW|x(&ME)q55oq>To_&d zXxVy*-u41Fa#{tf#iAMbzhomxy4S@+_L(-f=>(IsHi()629pUf$}5_*u|zXF$NosK zc-Z#L9~OI2eyckgTx1h5N%c$*F5TsF+p&ZJ7i0fuXa~CqF|1HeuUTML#i#K7Om8j4 zESiSI{J_-CH+m$GA^?NQ&)6lSPufc+C=%#YPNnv2`=cqxn!2j7>V!?X+L#4?a8%wt zI{!q(Jb8HKFZslS@!)+&#Ntt0uSd>(ph!)#Svsza!ccwPE{y z15n{$(M;r8xjr0EYFNe2>;oXbXV&QoznD!Nr0_g++Ufee5!6^3q`zT)?I0@u{`$e9 zWjohwB-M&+qpNx|)!u%U4#ta05bz-SrWoivIUf9@E6Yp=iJ8C%*cV(J-s%QW2GEa= zXVM}&udH&t&oP3oxCj7oEj#h7FYQ0DK|PhTl<3PpqA?tAHfL?Qj#O_k7%H>68#Mom z|K-W&1hY91E{G+k_B!-WS{^y`ABzo#n-&Yz_+c8}Pz|Ti5m7qm2R~yh*kzV9PJOP- zzAA%d1i%|F0?s%-q!cZDRU$jrI*(O+)e$9T33RbobnaKu2EOP__@?FWu~=*n6IndwDWA}L!|1O zKnm)rIVU6Nv{35@ozr4t4b#wbd%OlC_QMUzUWUzX(`6ksRtQ2*@q;9}(T3913?cf8 zaOgwi4S~Nl2W*P7vt2&hqeYN3Rq49naGu7qA zhhx0{8v;!idX|)1%utBQ4hs8i^5#CC4_su!x||iS&4;Uph-&A&UaNv~dANXCB#cED z;Qrwl434EIcIR|k6TIVC0q&1*z1Q#P%0;%Bx7<}K$+I_WN?qT-YYxxiN*@yGY4T-D zf&aMlYYhnl^6DTsVfEAQdM@yh_)D{mB_qjMr+V`N16tKIr$#bY>fJupQ}3d7o~EY@r)n|-O)HrDLF-tu0kW`U!6A+-rodGHx%;`D--X|$UFQz z=u#c#sywcWB=!t4OJItiJda*=H$>BuAyrNyUwz- z@zaOz1K3P2OL^o*{c#-68rn%#25|?i-^H@PUiQepKm81L5TeKom-;>6x!H5AO=pWV z?$*lL%^zyz!gRi{MGps*=oK>=>-vYQZLznFX6oKSvEB<@ZYNj|0zxUgJ&3cU5_kWO3R`a z-h=c_bB;Vu!A*Vp1EnAtRQyP8wl1ZNWaT4`+LME!6b4AuHW4imX=-Z1g{VT#PEm!U zV`CqC4u4_(i%<#1^l$2-!GNzPh(umyTCXL(VEBASd*UXFZ&k(o7eUg$Py6puF#R7Q zT>1|?)BmY){pULW?E%8%Qc5#Pr+!cX{XN#NA*nNG2Ep#GI!@aijpl%s)K5S~qguq- z9jwBO1k9WEimOY1euL2|)TdjF7OsJFermQg^nIkCjhxRvhq&H~c*4K=;gr99p<|@Z z0&)VqBIbvuL%#iMn4%;&EI~_r2(8~gj%|`C#8`e5?WOFAGP<%58BTTGF}k*~x4jRU zxQL0j=98`WQfu|F%y=$hyx1A|8*s$13?#TQ;xMU|y1Xhu+S`~8_bP`qHJM=$X!IND z*cQwoPu3V}9^5{_Zb$~`SktObu;QUIJPhUBPM{lAXJ@J$XFkqRmv8QA;pRrB-O!5e zW&_HEe3S4PWriQR4&KShv_cVE8#kKyL)+6T=SWgc@<+Isd z53QGxLnena@B6JpOgRq;n;#KebDu?i$srLAq{&C&tSA@3EGpZk{Zt0AWyPrs==u}8 zlItKBtk8eF$RD+aw#2E4Rr(jx)sn?gbF5 z{#f+kLzcv{-242H0(;@FGMgTQeO`*K2*bo<-W;v(kY77{3G7bN-mZJ{8Ut{O9o%=6 z1`r?j6ww-HQU6L%!WG|~TU~E9cv;Tbau;zEZpZcy4GsJzmBRx<+TxzMV%I zXTki-4F@YOLDusBEI)6Zq_Q|t;@#)eX6_#X-MrlM$}pyC2kP1rRc+_VgXOibnRMLC zM<33p&NV1imN0J#HsX|r*$#_{DnE$asE|xR(K>|Sil<5h*1qQyQXV_I%fl-IhP#@% zctar63wvvikQvP0LS_AD#p5)VtF#iKu1to`$9GxA7y024HN|hiDYu(%9l`wMq&zVz z3fWGIJZILRbfOmIze4p}5@T>4$lQTvAYM3iA3X!ZIw61Po+`y>FUay_qw?nVG%~5! zPxfX+kqc@%o${j5uZ>@RIR0JZ^VAC=-bkC@c1~_?eJ0gLB)FZ6=Dxl#Dg#ZnuJc&S zv`@Bs5;61W-}i2fDV$6Hkrad*Ml3BHpIrY~pL*znDdzL~?WUsC|D#qo==XmLtv z4){T2)XWOvb$AFHT!)(_0sPJ^t-Eq?m4OYLwr8(qje>~EP)=GpAzW@)5IYiRg((QLpv+54c>8082XSH}q+!#XUaR_c05Q802X%aFJw3b+Y$pOZDMzw|P0eQA-pY{^tY(RW) zKZx?5i@?Dz-C#;Fxt#&aO;u{$MyH?;d>D-&op*XO@+s0OSHHyMtCuk`sA$~uI5)DFWZaYZ zjZ$qz_TI-{q@K3XuathI#FX#ApXvoAoN!9n8BLhA!tL){mPJD_2RIU}xAJVOK>9K3 zD8M|vv-syJv<%w!zCDoDJAQjV3xgK$D` zk71Qp?}>=5`ew@sAkM?yIKA_Ur3Wrp-uX1hY$3{1s7El!MQ?wxlej68(DoJfU?>vAE3N{4Y43yJuh&yL8IFnKN zaYpy;QZR$^C^(WFca9GB+XVfY&LpS4s(1zL`*&js>}Ibhy#_cZfI|cNXSve1tZqet zTOQBIU&CB28TqlBFE~DEdR$Co65QT7V)!d9Otj9M-e#@zU3y5LLi(_}zD^?^@$^94 zC%q?a1ad#W@USOe9qua84MSZ+S+~ruZiam7+8tK_+RtjXiTGhM-T#_6j;^>Y$%%|C zEe5&hXi(U-T2A^5zS9_hsl<>Yd(FPLl(69Ao%nlp!~O;{f`OTA(xqI^5bcZ~)sb^%R4Pq~ z9pA0b?#SFuecCY0ofp;vjOZ2xa*QptFo2q6ipgyt$VpZZbd%5O<1nHsaH->ddSpJ% z)`WL|{M&dR;?Es&sl!U;^S%fISMNUf7}ik6*$j4%TXM91=?X1ap@=Ax@78^aJWo#* z!jFGvYxEXld7Gp{=DkZF0?;J6M6HvA@`_b8@9oR|4lgI#7$uiRd}Beihx$gZ);vs< z>C>RbI1d~XwEX4)zWFf$)op~ue}I&7JK#mrr42?Ys^%Uzu*plouW&84ccvz*)-H3r!&cyY9+s>Ut*{ zQ4~k&0K~^5J7m>jpv_cJnUAObq)?0R3m)0m`XJ0WXLqnqojV$)&a#o@7Uik>GmyByIx-8r^VvM2 z;4~{$pYKuEbIsKyPXr>}4CSd%vxPb<1Ocg270~fQeQUGgQ}FaMaQlUm={D9%&LdJu zAHd|xP0Moz+ui&}Hlx`}X$`WHz(u>ar?H`RhPoh5Ah+MCYl^{`97JHXQ1bcbd~*1G1?ZU>ONK^OrL`NPPqP`2PIOP?`rHys$Ax7jN% zL|vjl^EVd;g8uQmNLhY0IvHS$BW8=9Wk&I_F8+*CE>qK;sRicJB{O_4oXDrA~^nKV@UY zMzjIO2_I|lv7P6fbPW$$2Ul<9SlH9MW4?ntfzABe$__?%6=_Tu7`CVsTfmyT9_@nn1tzu}=q zK!#>;L!0&tF<_I7M8cAaGW(9Z!rbcIEXRDkO-w*HxKiWGJEno)QHVEdG5N*E+{435 zj`NE>4fw5tom2UKsRns;o+{RIA0_HwF>dLm8kfIQ2aEiHHu{{=@%G|l(UA&clapmp zr#^wh0KV%Us;pKeV#nbF&IU2wH-~ZO5w+?{UXs5D~9bk6brlX7CMJw zAI+_M<7KPQz2O&_ohDleQuM@?Zvn=Bo{TpRhSDKk-__P<<<5o_-Zr*2enD*jkI7(1 zY}8p&=1VJ^^}sXI}VS4pN*i35?=DApv{|~k!XPzVfYAHM-Av6xVT5h$Ddz5 z+2FwGe+AY3QUSo*+gpjYiWbR87`AGx-C809RhF}hCp7XORq=CTct$L~^X>42-5U{K zYy~5shuOA*|GbA;B?_z3EFo~|1iJ#a8FQwff=S+wxf!0~7vijdiRQmD+2@-7vlPn+ z-4G{Ml@6ky@Afwgc;>Ce3tOi=U??o&Ux0QMv&&vvW#t$Sjb$oxR6o6cC^}vAIs92> zxa7?Gmm^yg;ni~md(2Mv>uW6LnUI@?Xk%zNMUuo>9R}UG0GYuC^3l;T;n%0Y7VhcZ zqQJ?*-+^ec<$!}f9;+Rw_c02JO9g2IAf4kxj$?gmCU%~`KDKur{XYNK2mt6^I5;>> zK24w+Pt#Y=XP)v=@$o@c87y&whMsH-i;Je!T8=Ir17pkBsHmv_f!cBK`F3)4?*9E7 zQBy#ZyS4|e?mlQp78uaN@Y|$%ZEfu-h`@M~vwey<=$2`D*-&>I%o!Hc0(vWh9(Y}ja<3rsA}IO%JXqpSB>0tTAfRV4OHIe+EI$%3hA3r zo&@UP2sCgC^k+&A1YbtLp!ijO8}@g{+9Myb<^PWN@ilyZ06B_YZId8tByd3sF zj|fZfjdr(0^{3^U&Sbz}9)KN$~|j42CXwgReDowdizW(0QWEX2;u3C2hde60Dc zz9al*r_i)`eQCtCj%;M@Ld;V%mzuCL=f{^Ghdly;Bz_UxxE-^BbXP-hThWAB=T+wf zM%#^m$bKG%9>mT|URun~ku#m-)4M+ZVu1F*fhe0+q7CU)>`_qQut2K52!BFMCV$lk z=WlUbzYO43_L94#s7ONxuohK0VF#g!&&)nk;HMp~K)1#D`GQy32yc++rKdIdJ(A0Y zr}66?g_}=3iv+Eg@A^{FP#m1~)W^De2YwkAz6QsA@xcaaO;qF0HRm&aq z$tu-D*Sx@59reka-JoF3p$j~3P(Ow3r%B}XG$84@aW^HLD1iIvyx2TwSN$RQxk49C z+$^X)3%I$3`6wcPC3TUFAh8j#!l+&uAJ2$mDcoEye!mzLg`g{Oq#En)p1kB&6KZN> zyK2x_w^pjE{q9oqr??EuHAu=~qt=ol9@yS{+E#1z*#e~&W0AmZKJdaH>k#&0J0S(+ z`P<51Pc)XD9fes28V`of^B&B>cAy4gFhaGq6`B?&b1a^((>^$k69|=yuaeZ}eUH$- zT^4?Ic=<+eh&`V>S+PnFnju{p@Z$p%`OTGcKfBOZP`Y+5hj~Ci24E04sVPyEAXcC+ zp@g;OXo_9w+ZoPsOw2jZLuzwL{4!G@K}Rff0*`tkDC5}j&tlJ7?=Q=r)%7?NDoKUL z7uvkhS?^*BwonQo7OsV91cIe!EFUfU zym8E6-eY`TIIgv1To_B$GhzknvEk*iUe#-Kf9mt*? z&FcRS`s&1(Qz0&R@(|{YO77?(YoaSp%b>dUPM!X_D|Od%5ZaHLPLG-Ieh`@%CQ9S` ztX)qDpGP^KrY~uMV$a1YPXA_t-~tpK9S~!vG`~4-{sdcjS3??wZBM>LyDhl-{DQ&oFgrkEbdQ*;BO3<9gbp9iVY#J2Tp-d zgw~E2V18ndCqF9%z%^1|#6Lc-M;f9~qzfco^pEJtcrkT<1S(693F0jm%dY*<&bik!S=AxR zb?o(yJV9`MC96<{D0no@$G+C_cV1NuUo3-)SzkHgTp?FJ;5LZgP-4Ub2ZagUEXa-q}FR6Ogci&d&VP_3vn>kHFMFrX^OK?&$gN=}zrYx;591RR0=g(;`9;+b&lR)WBaORip#A z#bvx}QScMDuZkqX)cLsddzkS2)Oa&R@G-AX&~|olO72+Nbu&Zw?5_pJTc#CRi604Y zDG_9jNvo>j8yLHUu}^#9 z3S)}u9T<3Acbi6jN<6~<9tft8b+$a@$8OjsI9zHm8~!HRU?M;N$?ZP5u)igP|Mmgm z-&`^L8~@t}TY$|0s_Rm;znJ4cI_J1K!Sd9dTdrp89PQ2D;N_GHr7ULNOSOLS>zi!; z5U&W*a#Wt?E=+h)@hO6c@#{8_c2Dd28n}CVomlidP5UDI2AF5p$){%{68M3GsO7K) zUPU-N+Tt9J&5?afxDHqj%30~%iY2ZUp@m1MQCY}8C(C)nMtoLX2nWEW?M8Hx0yuf%XN_zLy9_Sl<1XLnHknyHb3rhhzD zxc=+oC#X%@E*gbkEDy!1v3$EEdG(9dE7lb<;qVVU;%oclA>)5@x$qpWSDb3(Y>{@P zh^{o*WPIx9X9TxlF=U<@TT*G@KoZ8duD4F+Lea}HHk_bR^Nf#UK~bPYG(orN$AHe2Ez-t>X) z&{g0VfC8E)i)Jesxu(uO_L#tR;qD^LPq6#{w0520a7NpDln6pZkPw4J8NJtN6A=VK zbb=6q=tS=mQKE#5G9p^^UMGxRBce-2@6kpdj9%}IoO{lB?mhS4{WW{ZP&2@6PGL_gavTtt&UUYr^m_?C;fC?3dM#s(!lLiiiFz#M-ukdnTc_tMoH4p21Jyqun zlsa5k=wP*;g5002!Kc~f*3r3w|j-6+cqz(iv&rxJw+&?T@mF;xRfsW885uRYMf9HBJO`&$z z!_@Ohid)wW_<*kla>&jK_3~BKkkQcEE|{?Qh@eJEvX`5EC#t%1}v*sCd3&xCU!yh}R0VVKZs>yURn?kyZ z8m~uEcEFWB?_j;=6OpO1`g+BmZnrX+e@Okugr=v3Ex6l?=0+WGwv z?JecYP)xT0Mm<@7fX41!QKJ7cDk-gG1#C;qlHR+xuAl^vpp=YsI#0J4O4;e9n zYO+#x%jLt_xs=DFxVVY-a$&fep}XpsTUod7tb1Or1)yZsws%GxHhAez?-G*!sttbJ zLKu@ZhQp_ho*)#FZ?P^$AK=CxhIqmsTs1Qp*Q z)vs`IXxEGap|!EfrF8yG4M)-}BWq>?697+FC64~*&jmF`7D&qm%#JA?$jYd}e3Rqo za zW0*ic@}0Ih&<5eao0|Pygr`6$X*`!o7>}hdG!n_i44FqXjy$fNu-u-hOYgg$!`0#kxeq?wCdi24yslyhn2?nGp0lF`xE zO&z_9*288-${UOAe4C`BanE828ePPl!2TxF#bdz8!B@Yzbvy+eL#KhBtKRl{`HGgP zzKw~ddwC0-M~ymZ_@Lmvq>hyKf+1SbcL-Gw{A}2hHqHax!}eg6XfFJ`ina7&uM>}7 zV+!&;w~-d}?EXmli1WbyDSvm7^*GQfXKev*JYy&hBI)p^%JxQ9d#tm&`vY0Q==97g zlX;pp`z`8P)E(ZMWj9u(M!a78y~uMxhmHCe|H=iRYZ&jmP9mOAckTlKfMQ?yiJVSU z8T3Yb)Le36r?YY5U-VDp3Zq#qduJBCVWsnu19+CHIn=*R)9Tq&TStV$DtP`{VaL|1 zJ@)z!;`Xe$Nn?3A&|B`In;FT(@F3AOeD=72%f|ANlE@=_B%Vh=U2y6u=(vy?HF9J% z|2TZ2V@HMD0{O-DyHe__;gw%|>48D<_4fS83W0ql3~Ru?Pqp<4=5<0bBncKj9F^pE zF4URGYwjQQPE;^d_)j>ZB%N_Z=@Y?sKBFJGGE&EW2Yk0H6LV;|lscw7jA!8qEWawg z+h2zMdT&*}OEJY_7q|()gsGYLHgRadQEZGRJ+ZEQ@g!a0lM6ALm?6Cp<7asDF8rl%MNri@iXWh#`jb5^}o zaXQW}8XGdIMOe@$xojL5R>Sb9KcsfVF5Z`PD^YU=h>o+P#p`{93baKuph53+!TXz=JX24&%dAu)Ta;b<*`fcI39_} znw)St`P;>28MvnfR=3GWG8l3Ensa&UVA9jomXJ?nb{#}*cPb)E5!lzSnMGVS0}Jps z{w!cGvjCpeNDx8*eM`F=#vJ*faB)EoW7d!LB43AEoyHsqkUur*@%ZBePNb~%rqx1? z7)d=>p2f}0UT(|{wefmg_C3p0V^Yt%s4$a&ILUFjq2&>`eC>y_H99d-o5;v(VmG!d zlXw2y2$`G8@C{q5+oW@|x<_TY^^TWZ=snl2Uo+tT`NeLT<_D{RCCf*bFWoTRAsX%0 zt3xXy@?ge+d8pIxDWyPFoI?Z}DBCX57d8`Y@dYH7{4qP5wV`eKmPuh27yscNav`MO zow2(?@0hX6;%q1EJl?-JMb`f6e@6d*pcMY)Q2pX?rA0qk1k3%mUVB01Mp1sYkbO<` z^-y6bSMZfWE&bdU@6Iv(%7rOz!ha9LU)BFZ%RiIp{eKny7X|>T1i`Azo^ZR#n@#7t z+qTI=_$$`T6kjKJVQ=I0nC33N|2Q)jLo)5D7T@WDmb}LB* zp`qux6~&nF7axL!Nf4{-Znx3Z_&Ia?MyF`YUGZqqRL0Ug1=jKl6l z4OB{9N)yCyW8CPYcJ=sJNg;QC2RntW87F3}D-I6Xe)2IB6CU}I&v9jR?3Ur)NT-oS zlirn+d+6d?h(*%!x3VNv1>7U!nCZPo%S!3;hJBWAqThRJ8-vl){O5WmoCO8h__<-~ zOjn&X0WhV{Y<-GCbDN126bbTI{ji6qx#aI5Os_HBvR@Em&}{txP2;NlcalXWjjTsK zXt0e|^zDgiM%DL0#Lfto1Gm^Kr}`C6BwvN);EdD!FZhx2I1%gKr>td1+IDme&_pI@ zm|qDc7I`OK$ERB$AE!|Et1_f4;>wSYwWtnR3Xh8X8a??l`uvo+4lsKxo++Do*p$+U zy?xJG%ZXifgssLz{^&~OSCR{uQ69QXSFH54``YH3Qs-gh+2+17hgQ-={mHL+o0!Sm zE3RFT)?GJvvegxccis{(!YkblgO@* zf8_5U`-wg{Cc=1coZxAi|1-949DGFUFcaK^Z3KkU? z3UoJowu<^ZgTBUfZKM9p4jLVjmnyf+*d$St-RZ8l&5aP-Y$fJh2cJpFglKD!a8*8>`hp$kmsG z{+QbgyH+O4R!ErJ8&W=Y4`FN~3-gaaFFy?FfRDo4H?E+IeGIfcYT;~M*w9ympA809 zQaCJDXD&$hYei%v;{9~yd6FbL@O)E?R?5DXgKqIdtqX%HSo$gRC#_0qQEJV6^hraTxUl~-;ExKz;>5r-BBy8V&=kjtVu_6|OjXfa z%T`d^7qM*31V6uf>FLlcALM-u?QGzV%xI6ue8|i9v;jNU>PnjBszy(C>@$k&fubMw ztAX*w_dbLTw>13m8L*s!*j=!3qk4)mIA3j&B|=YUL@}&)SB%9Q2&SzSpP;cCLePW&l@jy^f_mv`XMwcLi|9Fpgx7V&LJA+IP4P?V{+|4r?PW=0ms$oT8DcV6C*qtJZjw{EG)ELB>e~yd%zl3 zhl^9!unJH7zH79V8U`a0>N#@RUcK`pmn^Mdqa8Nh^V2X7Z@;0jMr)HZ%~`lcV8H^^ zOU~jw?M@oj)M`OqG+z_oFj5z-_xAW9w9bl+>duompLP0K3&TIWS#Ro@p%O(j;+-bh zI{96Yxie}{XVwxcPU*g$;?r`b_Y^P2R^Xp@EGtJ&_svRH@UQF;J4X1-jqN9Vod>058eUF9p8vT0K8ykPV z0#(>_v+6Cas$OZs-#C^J8^LWoGN_FYeE{jF7&g%^VZeyYXq?og`217)(!_&=bazS;V z6=sr~_*CI*<6Rcsq@$vw=F`;8-&)Fe(zhK9mt4QG4ENCJ-#I{)LwZ_k8xDJoiBP;dmj_$opl*D~!Vx-HO5&E* z(3AKDO*lSKj@z{2JbCbHF_6=GfoYtvHh63hg8OBKA}> zp4g6<)as1$zWNe6wS{4O55LD;>Ow-TrYYTXdt>WifbWc-=YY!>xU2~}hi7!XjA3-V zeaSIq$KmI51}PaqdM0ssI4AR-c%y`-mUpe*`+cjQgDj7CE44rwx7Rynt??sKbO z#SGWK)#e%8Egc_PKpxWS`<7+Di(b7b8SE?MDH$x8W6dGDqzU6Qk;W$D{+{Dw)9EJ~OZvngV@wTM>&PKc z7^~{DZ&qwZ!!C%I&1rT+kE}gH!Z@WtPg^PFc43P&!rGMm%0gUrZdra1+Oh&oU3Wwq zs>61C67PhUON**D3J(By1R!`1pLn~!RUN*jW?H6@JTpZ4aM)Nkvtdn7`FCTedPwo~ z*S+jV#~$Ol`rEY!*19UY9=^TxaD65w$$}Mx9_J>U|J#9Lcdi2DIo(dnNEORtO8euWj;L+%NUKe7 zR@RQ1W`Bv}v8J zVfG1@lAcYEc`G^0iYc=GF{JD6M{Sc>R$+^O)N30Y#q$-kRx%~jgp+9rajke{10tnd zN=#Ol%xE?`N%z%n9s@VcsBt6~M$`Afuk6z6p4fyBbRVMPd{Bd&39xaxYyTLyka92g zd89JpZ47r_HcSrJ8bvyV|MAs&LJog$eH|_K6}wtN^a0P4xFwxLWEbx60E*;}?|yuG zSh6#b1UFT-Q2V{f?63d3p94oDHuGY1?bKyZo6P4CEy}2q+f;wAi6h)<*_H-9d|kv7 z_mLA|6Wm`@{Hut7R9g<*6@QWQo2 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/generate-clients/image02.png b/docs/en/docs/img/tutorial/generate-clients/image02.png new file mode 100644 index 0000000000000000000000000000000000000000..f991352eb319968b48d250dbce616f4fefee4a7a GIT binary patch literal 59828 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

^JVTJ_UZf80nR0bkG);Q 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%0DBXpx8 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/generate-clients/image03.png b/docs/en/docs/img/tutorial/generate-clients/image03.png new file mode 100644 index 0000000000000000000000000000000000000000..e2514b0481a81262a307361c7e77a4464056f7b3 GIT binary patch literal 61043 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 G`~L<2+%|&% literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/generate-clients/image04.png b/docs/en/docs/img/tutorial/generate-clients/image04.png new file mode 100644 index 0000000000000000000000000000000000000000..777a695bbb1e3484f63594007e3fead45890c6c6 GIT binary patch literal 53853 zcmZs@byOTtx8_~AL(l{WF2UX1-QC^Y-4X}{cXxLPt_=i&ySux)+eh9zcYQN==CAHL zefm_b-Dg!jdq2P3p$c;1NborD001CKN{A={0E8d_fJ4H9e~c*j*6x11KsXCYs=&g+ zE^o?jd>npq5!G-}wl{NeH*_)ulr3CcTuhyee@wsu03jeLBBTk49LI>|Zf2an05`rZP!bT!gmpV@YKIA1LTW0{UZ)J_Yi=v{vOm*WYKuU*;VeJPP3|0*Od{($HG z6tk(%AisjfebSn`hNj!N5^3|sNA!HXgCT%2mcw%trxdELTycC{aTkQ8z3fd^7etb) zU;fYme1TMQT)+1O;zUZ%+04#@B*~813ubHz0oU}wPWil$uggv}H9uxt@EClr?6*;D zcoXT&CRAoQ-REuE^o2?eP+om|gQ^zOU!=f>@bPv0Xb)e%%&4T+M;vuGN9k~S`s~lP z5g;Tq2PkGPbSRgjFQpEH_*VZmeDBCsO21t6ej@;2SA7+w65;>E@LTqG{174 zQ{J7jzw%d0*?4DrAL&qk(dglbGv0@1fh#U-WFVxNt&%&NqDvKuDCn)BlcY_*EbGIKX zn^ZU5yZ*(4j=2%hRN+USE^37p8Z0aY%fW8-#iCwAG(cgmiM(-^^-?hE~`M?l?7`-`6 zJ$@HSw7y`lwJ*D4qsiAhkeWXCN*4Y6Ppn8>twG9~+zhq6-ds#hbXdTF-vVf5WhyUa zTRS(X>5_((Rr$nh@|RE6+gS|UQKWVo%aHsYg#<8h%HWy)4FF{G<%KY8v(O=X2T>@McQ3 zNfrsOk3q^B$0}shWvU7|(F#Anxx8AV6!ws~2(o1iYY*eN=zm)=9OV8Ky<1B2l1cR1 z*N|kvY4b30HXD_+Y8%mII_VBFhI$}{7J_~C!j7VnZEbycZJ41tVoQ43_32()492+@ z69fk&E!Z+!JlO}Rq{F7pvpBFuAsXmY;4N3LqfggZu)_bqak@R&;e$~Dh4Rt99<;Z* zIVZyAmQvIB_*|D?=?mTv6M{U88>q?AQ08c!xg!BG!!`HmFrup*)?uG%*cj&15F4GT zY=7t8vh>Awl{kaq5T`FR7OaRYH-D^&`~S2lb|I%#WWjtUC59_jA}$?S>8)v7l9;C` z)CeDK+%>zE8;Q=3G11$!4vi-P0N)%?C=IKVEu}vAZz4MPAH}iX3Ure(XuVT?*N2bE zOMM#GwUe?TUJj0*fq{LGS5Vpp{Eh0g;FXItW`#c=1jpl<{)A4TeSp7&NeP{NyR*^GbVM58(l-Ur*$e4t<+g7&iAk=iHP3E8LNs zu#Zf){p$F3pZ?|W^;ec0#XzP!Ex(0C7LXpgH;2Upm_=HZ@SfKs$+@`C!cFeg)6yI1 z>Kh3UpMPMql;q#<$El4ZFq}%4@Dt;|-(nZ#)n#y-Ud~zap7t}zru%5`E1x9eNp-XN z9aoP0t5BSOP<^> zCy5jQ1s<*DM->y@4Qu-AhXXSX1#pEmU34;xZfZlK)2cPyA>+~WoxST(?V2)*m%H>< z92}CsA3GjgA5X@2rFAdx=fiQu#%)8e5AAHO8xX_n0P+c zlV43e@LBjeUN+;GM1fDVdic;(l-_5$$?V3C!wSTQAQM?I8a()=_)@~?i)dB zIvHM9S$<3Qw(^VN7&dl0ZH-|65D*icSccZtAq@e3yl9f9!d~UKcBq`0iSxE#2Wj&M zlzVL4cW#wnlHD7B9Z+^x11NWgVpqM!h7gXwsuP0!ww`0`Dk)hFghU4Of{twR;&7WZ z1fw9sY}X$Dft92NKEa#TTw!lyRXzk6%5bzB{-&A7@6&oS7*>K42vUBAVT%iGifg;G zJ{}Fd3md5_u%bUcVO-TfC(VPA&wkWuT(PdKmL&_&cjG^rwa=K6UoHAQxEfhmwbtbx z4x0&MqsKGYKPv_UiR9A+TL*?B^C4_Lgw6!YfP?O50N^%wZliPJqORUmFlYl0gaW54 z`04X?<39@N-?Vq;p8traoA_?~HIn~_!uoG5^*K0ZMhDAG)k8lCQ5Xbl_!tl0H>pQbNMTBW5!Nst{~$HbP^MFFG$T zD4V?t3<&%)F+JV0`|D!~!{BFoL#9*?gaiHXg1VUl$T^6Q+jHE77M0L?hze*i#Sc2y zoWPMUHjU#W2r&fi<}fD!5GDNC;Q$=xNkI`DHF<%P(N)f<`^7JTn%id`_Lw$0j^Xmn zxAi)((pwL~;qW7jX3c3ZaKSat3ycstHnO+aCURN{?~mK^Q$fH=W2b(`R_-t%Y-x=8 z-_Q=vHxGrSbUXhbS&KV64Y8+&mSMZ@JkWB6=s4R;1AnSGn%61&>60wG)BKGtQCOKU z-m1^$8Z9l$I+CiRf6qW0xix!)izy?RNnUMxL`qk=IX-EaBvh~8PFAAuj(k#;#EH9& zS~yO>l;TcOi*_DHk*;{;`KDQ6btN&41agPtk&;4V28}iM>&?TQm=&TB70sY*c&pbC zd#wPxz&%crLvu2ygG*E+?tW)v$r-i#iTZEB>Xz#Cu)O@zXDZ)i#Xk-i4h9`>cbwd7 zzkmRH=BpF4DMqh?v2m`q>G#1 z)K0zrs)GmQ9dAi1kAi=u;pmPnm0NZmJehn*WS1^SKE=tBzLzItr)ytw?(c|NQlf+d zFeHzDat=o?y}J4OY0H+XfY*lI9CVd;e9n`00KKDr`N0mRQ+-%hYJSgK!rk|wVXZWx zQW5HL)Lw;!3AjeL)-}sDlXT13TN&u7uE;8zbM0>k57!yEefKLS;a<00zR+oYhV5w(@Uiz4~~=g2WZS|T(CtR zr8@keT34b%;Aq?aWk74csQf0b`f6q(Nd4Brh; z{)*;Fn>IHp8}s!bTcxO{apUsH{@!BF|MC14H{Qj}vq#t=|L%IPnEvJ1EObj(+;ct@ zVX+05{Pi+U{75^M@=*#Pgp0@L{W=^TddHiV$#qq>p-5_OobHy^WUuzxP@1g0dwfbs zoL8LSZ{G8lq!^g>{M*1%qVG$548}5 zD2^6PSBK?-!rgvp=r#JKIFHw6O+QkvV(oFKCn3>%zpk#di014h%=PUjq>A44lku`l zwI3**Z!H@d0Df*Z(L-I=IlBZFvDN*ag~A2`2>CcjKT=#Hz0gkwt*WJ>{hlM|AoO_{ z-#o_e*?3nJLDi5km(m^v$Ux2r9LSAP2E5GOtZIF+s^{0OlRD)03Uvp=dmn9#c1pGW9vG#)(? z@-rjNJUc?+G8Oj3Ry!QHwdL3fs0x1$%CnF2FS#wsH3ZM`siryX!x=B+<-!fqleb%2 zD;j^Ax>CwT44@etC^;H%KHyUzIlJIHn|ajb^~ujF;`RJ{d$wWdz?}0b;B0105UZ72 z51BkW3yWymlz-(u-sqnSBPGu>TT*o%nk(tqODUwOZzBzeXELJUzovfe#LV(hUB}h$0 zXO0@zlTB- zb{`n9#SX)UpWBqplmm+73yir`qC2_qCHdnD{gJKFVn-2%|8OH^YyCd4XZWd*D8DfQq#eHZEKY^?cncZ z?jYvrQu;!QP|ykU^&oRYjVcM1agV+#6)kkGBI)6^`h?MzE5Wk5;B zH^vc<$B+6#{q=<{3<#a%OdsTM&#M3USZ0Dj9)$73Yni^pSBPq~&B#UnkvLdgpBa>c-L-{ zXP^0QAUz7e03utr{PH1^U=l*>-frB}GtSzL-@+Si8-6P37=BcU^bTOJp9q@<$33Zp216=;y9PM=ElelZGz1t|7? z-E4>fu2%#*Hq-xCiYRmQm}??rmns37_sjYcZ(dWAiBNoYG*b7@NnSt*6--LcC-}Fn zG62y*6H5Ek80L>4MDc;+LM{9VN@EOp~O+K2}|Ab;1( zMyM)J4M|Hmx(dSP`fCS!f8H)YD55XS<`X;SY?2)MbLtAyJTy|_<6zRpJ`aaT0Z}sJ zcy3iGL^~{3QDRp;S+Z{Ki1(V>yI~Zw% zcE5rbrYnrdSX=$My;6U%Sz8g@aQ}sS85fIBIyOFFUdfut-`Tm-{~hertm5lm*;e;m z8xg-sd>15Fio$A~sVcEUrbm>JcIl98zsUv_x2^o4jDx%)->yFNn*~q3?ZxjfI2;wV zI2yQ+SLxylIQNgUf#neLIQn3tPG=i5umG`nlX)%XMeZ0*hM>Tmbte3hZ@M%^%{ z^d+ITD2QKK&ege69RN^bI>^op02F4n(8x{7b=H$(iqSHi-i);`*Vs{Xp?q%~qxntG z6{FNzAWBl&bWg1k_I=v-+!mG+-VgsYT(2WZI&QuL%l|wJ`Uys_Y8F^8FgveDb^`hWi zRfYOdoN`nrqRHAy;ojTC>2VMk5I14pWc$9*h^1~<5VGpe>faqPcoShQ*m8>%SYVy% zj(07tt~Rh2;=!zwS*cY>U-i}BQMmASWBobmYf9U*#VG&hM7YE#=sr>(zEs6lnYW(Y zhpEjrOZ^2a?b51Z;*DBidCbBP6*q0zy()b!2$_JbTBbtde661ap&mM^GA@3;k?9Mt zgmAB8!po&1KmT&N;H)wk%8MvQV#k6F8ZfM}^)e2v@m%^k>-QJUA50pDI9+yJd}7r+$Xm5mk`L!o z*3F-66^QYy(@hrb`}_+qEjd2lj51`>!+9b1YY`zh!`;boDRQb|X(SHUTOongjEZ~L z-Z*Dm^~7j`*~J!1TyIQ6!J$B5ao=ozk9Y#%PoRCJg#H;UVKEP$X31}GzWaAkM~E%W z6ub{7itkFj^J=v;`!jbC&gNqr9-1g3KWk9fvS7Qf$|URtF-WA?S=(3+pOCy#WV$xR#6@?O)M_X1pM_CRIj~Mfv(Gp!_SYK z=R0@z+#Is?W;rLv!aKNgY)Z<_F)dDL!BzMZy)D;6HPL9qp-XCn`WMgp?#L7jxAoC@ zM1l$)eA!ZDlY+o|jqEwLC##@{Wbb2-%3=<(BU<0acCfKI0ES|R2zkd63XNLf(F7QtafX_I;6T#YMnQ^ zOuBgZ=OcYIL9^PVN%xlCO#bq?$uOWoOHP|b({VcwW%v9T->x)X4N5H_m06O(T^$xm z{wLxxWX~9?l7DhRn8anwbXg}uTvIz88iqtgtP|C*BE~MSJtnlrk2G2d@n|ZCMhOH{vVs?VE@N@`#ZS~ojTQP==wHM zqEw3x9i8|`DdV6x@ZTpseo)!^-*5lfNV)!B8vn~N`fneJA755|9@ZM{)$8iI?w{oZ z``Y~*@4vjJ|79lqD|M6=j#!nQ7jWAC%HAt)f)6g-FIzRYTk&u(6SY2yreZ7Z{SlQ+ zYz|X2>g_amTV6z5*wE0H#l_8F>t?VdLU8S`%}Pb7c7yIX{jKG-1m5NOwEjJEx#M}> zz0TZcFn~07zT11YhVomLEWhW->YMt~oJ6<5S-s-@eq;;3{RlF5B$pSU_RiQ7)r_;@ z2lwylXQPQE5T(79i(dTy!gkwS3<$SncG9fxv?8S)OGRsNbSy8p(qm*lf6}bkTxgV^ zHiId8eIqnnI_!jrI>?>g@DWaB`a|nDoC;QXf1ia`N!VFrv@19WVdLfz-KMLykC2C* zvHQp0hM-!hu3RKP@vMxRg!J+dO&tYyQWt4v6rx z0V+Fj%`21cdUc4a?JKyr$A{Ksm)q6ZC`0eDwkB4+<9E>DpZMi(za0FgV(MY?KswQN zuz0A{zznOC4|ja-oDGI^%*om;2IL@sN$w5ILlVr)70P<*@yCMu=>* zdvkSJjr(*9e@z8j^y{fB& zjXdSTP4K&Ie(XKZO}13tn+FZUItzwp?NGPTJZo;Q&Y*Lwrf=T9!4&B zJj-FRIFn9NpC-fQIW!=W4Znb}5btB$j1nR^cC(iU9x(VhZTf zfyrO=^UX>4+65QJQE)FQ5-|@Cv_slc@84{Bk_>!?Jk6cEu zSbI~yHI1Eltv-;1%mokzB*sIig9Fp{Pj{7I#H#mTbY)P-N#f9-A%KElUhf+^y?I>& zKtZV@rQc2-N#9w^TSA}y8$@vZ)zc5&Z)9$tk=^f3y|1*iW-l_Z-S0huG6|ZfLZ&3V z7#wmTFoB(pKoq>_vKloF9F*Op{a7ds8DMxLu+59K#$Z~TpZ~@DmqCvxtA577<&hTd9sw-Tl`1>j%;+Lzq z&tS)HyBCt(1EAA|(8f723{OePm)qiRXGxNLb;zIJQk*g4CUB<96eS<>8LoUY4>VcR zcV`zw#RG}Z%?kSL5F~be?2crzQ3L(hi@*iu;=Psg`FT8Z*e%zrlFCzCuw=(*y>4iH z{K>1!L{Ej74-ZwO*u{m7p;J*`ja(JnC;^V9&h^|aR{K0)Ne1f1S4;4SJeFQ zz#^dJw@iSy;fTXJ(rn^cK>UBR02RFfZ+Pk2UrN6>bC8g49Azepy7rRmhRa71>8@j) zw1Iear|8`9%3ilhs&Y#1&h&`9($tBcMX2xZcg^N^2;-MGU2`Gl)BGV5i?~+i>Phmi zG*rfh{hwLihgOmWTL8q{q6-q{4D$V*oxpFy6-8@@6ilO#+b8@_IBf(J`lXPyc8Oj<(IpzS(LQhb$C+= zVdj;40MVyt=<0JHUWKE_ikh03rY{O7;ennBBK@O!_Zu6U%;1?h`UI9lDOW+RSWcttwOn zC@7Hkvi1_cmtVu?#CTFopWZ3_XS0`aVrB{YpJ!_G#z(ED@-gcdiJvl-lvcrG!2Q(X zLjLtzy<;Z1t9o1Dk7FR7~qF8vG^ReE4iI% z8r`@vtjg7Ng|p97W7S0tI5?@v0D~<~@7#uo_qRT7VzXCG-Xn(y^-3euYvCYOT=P#cM>Qp)ot`()QsNI9~l z7125o_Rj(9t`t6y)!UyD&^FiS3lxv~Qk5dh!}ex*m_yC?d{ZYN$C}lO-h=5~!l2MI z{Pk5kGJ<|VojkDFe05vEX#2J+y~fmk!Zd^F=_rD%mm0eDwU{N^Z1h| zs-hv43yKr~JZs#uq!J(<2*hEc&!>yR`&N~~^IXx{D^Ik;YyPS$TM$HUQ#R6n+qz)G#`1kidJd}2hq2-@B{ zssTdyrflC0P^Y(gBzI_b%g9g^H_nAy@D4i){}&Ix09@QSv<_oX`LDn;{AN>j_wiE_GHM?rU^GpK|?iMWaCrY8v6J0+D{&or-nlY|!2*`Y?YyGC zEC!B-ZTNWMz1aj)MWOPSnA^k05IH5!HM^CQG{mLqxftIa)W)?5oQOM&GG zIa~|A&9Bl`6<|j@OiLnP@F!6Mz%O6d#oTuTnAiMVC_q33OE-$H3?Ou7%KO{cNKQjh zzK4;h;VQham9nritQnA54inr= za=r(RwNig;WwWh~Q{-YLrjN}*c5zPAOl5zOl^hJ2X0G+IGJzvR@W8Iq8Pb}Zscnm* zQl=Xpk|0Rej5>8*k4CeY8LGXS$I+6#EKP^b;-)kaP$F}R`G7B4WF*U!4plF!L=;vR za@3Oa1rE}zm?d(dwZq4@F%ncW5n>DBcs4cgjPZU^d*i};_F}L5VTY&GzyBemwh|3H zk9%IR|B{|zv};#IY}sP|p*Ze!uZ>tFN*-=3$Z#rU_UO+hha}ZAHFfb>_uS>jZ8{&- zv(9EOE$ok$IxhcaqQk7V@j4r}7i57e3ld9uC{vTBis&NH^3QgJ&xTuDPJqg7^)3!w z7R~K_Oak&*nUBTFGAdSAmnx=e54(!<*Uyg!Ns(B=kHWXD$OPNyZ+IA;`**QD-Oa~V z;>lj03hB{J_b_KPq*MEBifEG6LE44k@EmBZ<-v3T2h+#DPoB^9NAN<9uIY5B6Z{+~ zY9QzYhsLJf96b3MI!4dKFyhfE|{pV=jT|u<$UNl&R z4AvrC(I%F(4h=8i^at703MIHUPK+4j<`MLtCK_BmvsC(J$+gAq%1Ntsmax}RQOi(b5f@; zT%kFfA>t3saJWbZ{+e>5hwt_kIpdUCqYJ=Fsgq%O&NLM&3Q+MpaeYH%??(A+ z;$#%S)g_6}yrP~Z3kLe|L=)wTQIS^Q3&YMGPDrE2k9-HGp2s7vi`+WfZl03+nx$MJ zbX|p1G{AGjz)H6!Vgf%~H|C*cmx4uhL$xJoimhfdzsqVhCT!(6ogCGdaf1f5mXDjD zxzh;qw-m*;@~1cZpWL}R|CINCe@Iub|Gqo5)P~ebyeH|g`Kg+&0@vkOZSTkaa2T$F z@r}HTx_^V)@egJFr5M^7`!<&#(?8!I$$NUL_`W%Wg>N~NB^E@5WUN)!!4 zvv*FUDk}fgk$ZH&V@%f+@3|VDj8gFjWB|P~xbSS2Wa5x%XyQ<-n*bH>=&W;`lDXJ7 zdI`EQQUPt*pPC8GButi0PL6EC&aIhQ9K6nACQ}g)84`#N2jYe-OiblZ1o|PiLQc-Z zg^-$BgfW(fIL9jNLI-Sd3&3C z;qRMb$);WsYnSd#NfmDH$77W5&1vO%!)#5}VghJIiJ7rOZM;8&3?{yO6vMk9@%BOt zzY~%%QBI_|uFlg#J)FG0QT=HIGoe(I@Df$U(=k$GGoF4H6W}jyj{SKiq=yCsra6XMqDvC1EQ%1zS_@B=?V~@h;S zraCpZ9pkw#OCH^{M!CgVbktfJU)Qu+i4mM4s@AjGh`uaiGI0iEKyp@v9)wI+M+rjbW^?Vb?FbOJOrguafimF{Tru|=7@Tei6i=5T z*^$RefmtB&jKo038yc0b6=c3m$SUu-%zL!*lL|}3kU3n+*@b%wn<3kptffpAWDXw4 zLWFqx+UbkziDF4!Usn9SWYTFr8U_q-gC=7tJKW2pq3nALr2`EB(zFcF)+ zmb!sEx`u(>`0$GYKcd(or%_v@>`LO_ zwxG|d#MUP^$7Q)?J$e3qvPA<3W8#Tv9-ee=3{3MX);4By<87}r*H7yHar6Vl*4|nc zrOK2@D;fzwrcJc{zV72TRe#L_-b>DXXcGyc9NEvljUQSUKlvr*!E(CW1^FM2ItZ!K zvNDd7Y|07x$*6_b7+kPczwf~p8g$hX69qpo=u$crhE2UBfE~7LdDgXLikhR|W970g z3-TYxI!acaz+jN8tdb)KDS3Tkymey&rRRSXn!`tO>ctz@!bI} zKFas0puZB+ZV305%%qRG-ULsk=l~EA5kDOG?PbksPtP^@S2mub{ru!qaC@=JR~)a~ zpYHFf@z6}2H><=q!F;)Se6L%OF%nnk;Z^T$M+>WE>3s{RfI`Qemm{P95YJ@!o4px6kE=%shTTn^`juKxTkm;6``nq+CL}In~N)9 z%sJ|C1*2BKyTHqr>hPQN-$2lF6>iIYUz4Vtd&+>lHBsr*4k{XnjHYBi@64HI5ylcG z9t|7R0`U+^UVPkVsz^mg!ehF>L(o97zpUv>?7FNpS-HwLlo3Q$kKsd%41K%zk`GOe z*Xm`*A0r96F7n1t%ac}v-FgwqRs#ytTpGv|l?GaSu#xQ|Qq?Y-tTS7z8LqUB|Cu_BsaKE|{&&0m~tc-Xcs1cwOg zBYU>@e#eNSIgnha$u9^gd*B*M~sjD-J8K4t%T+&1BosuJePnt*}yY>sYc^iA4E$n2ido znt5DRf|R9|k`k_3MX5oyy4mU(s*_V_p6|?%C`>9vx$5hQ&0-aWy>;|BKJ7k;N0F<9e7SRWqNm^ygGN&V{-WdDEkS@7c{l>@oi zsFLc4ctdGtrS|!~35mn`dRI+)n<1)HHD(`WcK#n$W@g|2;gjHC=jvI!tv0vN@nrbH ztyV5MXez8_rM%V_)D87rVJ1FD=pPsduEo+4O$F4=@!~LfwbLrI2-kcU z2)P86tu65n6GSLjT7JAsOW>fG828XrX`i5;mt_fW7h0i)@}oTe27!(Iabfn6DqL9j zXH|2-TsSmTgY;ujUYDdb5|`UW;>mRl{Fj2FtYN5$K-WK7v6Ih-4l~zY^oYGN0rPJN zPpkLpyJ1pyeV{xFbtFM5wq?eZyidDa3C-W2JJsfU4DoD52*R+>56u!qlFs8z;xEnhb28=0pqqC5>9%~ zEjc)vex1GfQ{}_x8}Bm5`RH9qDEhFQj(2%FZnYkI)*GZL&7X>{(iK!*nW5_YM!?_` ztqZTB>8gnTt*pL}8g6*PvO&!~2KseyC%zD5cK&2opr77$LQb>P zHmZ4J)1&_!@A=_F_)S->yO6lcuJ10JN>*m=)A(D~*$q-S<9!e~^uyzF9!`7B`gzT* zu7Uu*{MiYk9jj1+AA);l?ow?F_=h5&Etk0)4vVt`PE#{{Fpd)Ar za1VO5(c9DCX3E;kAIqU%HK)e9%RTcARY3+w2{*+WL%aTFoHZMSO07Q6=J%#9#R#zL z_#L&l*g;XTnyX1`RUi0^xQV8H!E`zaD~%w@VS(hXsxlu}{E2Sahdn(2yy>tBtLbx= zF3))NgvZ{V>}f<3oSKeu1d(c*+%|RNJw#(q<252kFKu z=*Mi|H<2DOm^>E-W}8cA!fj@p6x6K`l{ z<~G5~vr{S;53alyV$)N^9z2?nBv`rgE}KWDvZ_#n)%Z{du)>Y3zkb@kYhmo&Q$(Tw zGqpQP;4WYZGTTwk=46!%Ulr86PYCWt3V*lPH#8I+{y~X{QX5_NjMR}sms!WuU^N@f z(#<#s`eC;}U8tBtz|OvLC+izlrd({tM#cFjT0c=D=4{;nT9;p3F z_q)EH<;zP!zyzXed6F&HsD=Qgmd8$F*zidrLhFJ0UJ%G9Z^GGflhMkOB$L%zu6Q`7 zYB5)$Hqd@;h)9(d)Y^Q63A#cVPeNcu_^T?(`2SOp02?r|5=@WXo9fT^*7IXhlLm96 z_mNjxiP3JZ*0fr5F7m!o3s2|9kYCAlzU&94NT=5j2`dev09Dm{fPNbyG(gDil3i~g z&{x(uy>?fWb$vBA>V(y^P?_8&Yq%9SVFIQZuq^osHdbP~ZWlF`qwRF1Wq_v6QMN(Z|#8rWEP=3iO+UkEk>_)?sH}MG*oxJxTvCx@9K1!6s?R6 zyA>!*32ch3)57n)X8_n$Tf_s^-DI>tw>{=IefKzn$~XbRy!)nvcDjYU#sU zye`eK?Z|Ew57>{_r++3sy+~qL9tqkD5mTT__}#eV2YQs%Rn!F^|A_FZFaDHm_AmGr z!6XBDIjj9LZz&xZ$iAPpEtY!rDjOv^ev|y3tI064HUy8s$I_h5wCpmg`|GLMtLksd zW7xCy(QSAbvQLXb0|oq$L1`YnKH%QCKU-|FjymeediPMvB-40$!a_dH(1852n}kXV zTxhvk7L$!PAGFP@tb^Rk`RhjS2JC~D5fIBlf%IT%ywAKLp}o& z2-#IB&O)$&!2Hx4GlSdFkQz}zo)Bt7O+MuZ6V^UdI>rS@Pb`}0t*MnB|EGI=Ob+id zl;OO_PaWk0XKiM;zqI@4mjvB-TdbLG%)qTy&-?yXrw;S^fR^hWNvKtgE5X*}SbhL{ zVehYbM?ZWQVc4t^H$4~ufS3Ehr|Om=TQVN)e53DTR>EytOa_O;6=y?b^=B5kQ}=np z0gQYTPsW^+57r$2$HRJ_`71CHM5)e(_w$}Hs%YK(3_d(4Fx{SPkpI3N7p^Rdd7i#O zo{PcEmj(cKcsX1)8$JP4OhfCpYEJJ5Y|{qNM9+B^{F^Hwg+`a*t&+=9U46#K%1uBr@Z%!?bCwzf*x#QzqN>tFqA5N; zoqru~1F#{azW}a9igCzNPwg5Y4EEmL@csOcZxW_Q1sRo~SWPQ<}KO?9)63!#vw1Xs7624nqQ#@pGe^K@YB4s(a5PCo`f6Sm@Y_TF;4w z6*uX}XYAZl%fXuS3_i@!$mAGWf^OvWN0SSRA!}~MJDBmZvTK+Xf2@)=ZBGhd<%vtMODRVR;5?Df@u)&JPawq+}=7Ra%S_iGq0gu>AXC zu{du?yU{Ig`0D&Ce>N#N5H?@pS$WFUIDrgT{_Izo1_djbJik0dIuwP>p=n|P$`ilG z4h&3s?0a7KTsXV0%1^dw2$xhm;B2%oBBX?E#wHIsLcA|sEQQG3U$HKUqXz&h&8yLS zbwSfD>SDV_4d$63rE>GuFvmJJTHC`Hb@lV2Ss(KJ?sq+vHcGpE^%IwwCol_BgPXq^)8+}E&6pAuk&X6<{o;H{}CYOV-A1-y4lm~ZTh-- zNI}d`LEQQBD7@)v(Q7?9#MGGNRg|iY8aot>{MQ;QwV#z6pV*J2 zc=_xy@4_!13>I=nr(zhDEWa;h$?(dZYOLI!&uTwH374u?pIX2HhV2J`bDt{2O~LB*V(w3!m#^GqiwSJa zf**Y?Li}+50gOJN7t%QWQ$|^=@SowBxz%ibFArR8*<7wtV^6i^pLo6R7-n<)S60W? zuz)05-Kd60zfZ9xeLYSOnIGC!=p9acjG%hf^k_ix{a%siX7-~Q`vyHbh$sk0js|PK zMK+e@_MC}oMPia4vC}hpqPlvag?Yb=d~6o9Lfv^h)p?e#!!j0DnNjY|seYeEXLU=T zAwE{0C|1s`>}Z$|Jz$Qq;%OvIFuHUc-fesE1bVjD;c@+KonJ<`Q_|p0j}L0LowO)l z;*=lzjaPTRvxN1)^5v=Xj~hpjA2M2I5_Ve%0O(RNQ;kjgJ9TdLS!+T-lfvO$mgt>f z`zO)>eC?=VXBFP=Uxg6XR7>t2-R`*O1=wY~KfHycQg8`y)aJRv1>H&XNg^ zqtKm$VS<}ic&!&}Ps6OMZ~8-|x%@9Xd24UaeL7=yAAU~N>vc)-T-!S2;Nr6P{Or)t zPlINYUDMYbzVIv+AK}=9pv8LUYjJE)H22L;NPhA97-2_VS2o}1?^C~P1^V=|mYA@* z?d|IG&L{WahjQ_OLngLI_PwX?{n-@!dXyTO;wTIVi{9DQDVLiWKkS-NSMjFC$1*;r z+}|;BY^_M0AB(MptI^715ULzjNGLvNP zEzOKd@}al#PMTqokyk@8-%>0+vsPpAq^^^4gSrL>b=i|{z=nZ@8tbSc-8oA=5jaMJnL7I8myDQfC*6!lg)N6NKz=t zaT~u5dSq2*n85K!*&cW;YPVSNOb=&qFs!e4)0$;bPyF0Vwma(+4W_H|B}J>_ucS0y zfWGsmQ}efR@ll*3CqG*oD8i3F4#>@}J`JMV@8!J!#ST+{OC94g79ZE8(`h}C+>GWh zQ-%-!g^{Z!MHO9)#@3V`V(Q^n^cDD9RMo5O+cozkC(m+$%%`i_%o#O-8X8iA48niO#k?beqgma=b#t=p=D5eEY}75T2kT4sHFAA!RFfZ|n* zZOI(|-7oLcmF^jjxLwK+K(_&`4jwq57mZ?0@GG9VGB-4AY%RQHQwYd0H=7Jx_m3_Z z1BU=44@~TJ*SOBE5LoFQ*wu4~bqO-Y_~^%0`O8mlWxu{3sh>KCy-yaHhWVVWCjuFv z(z)s+fCaic$l&(>qwAfcBW=QO(auDZOfccZ&cwDgvF&7H+w9o3Ik9cqwkNi&+w=YI zS?k<&&-t&{>h5<{)mv51^X$EA*DfM)gkXjI#gp&$CdQHd>AF;;LubJZT6XG-34@gg z!pFwY$Yx6J@D$MNesL6=LYa`?VsjQdsVbR!DT94{K_Iy|+P&7)7lrBIdGLy)Zxne@Y4#1g2+W82t*RkB>l(n{ zb~o} zm=EyvUG~K?+MA8|8#KG-@hsXi2iPm!85~UlL%MY{$1r_qZ}$SfD;q&~?YWw$`|3_U zleHn}fWBD^x10?LDGUYQy>#W>?n6ru8vB%i?GfWxx#fMK@y+x%x^>W@XD1`<|&6=Zh`g5!eqAlyYQ$f--aM9nLlM~D9075 z!edVP>AG^u4+X&QiqKa6?nEbSBu%C&a^|p(LiBH0de$>$WdmPXc^NB0_FFteP&5bQ z1&^aMisc4N?yvs<%K&j*II5I+A1=}%#R~kJS!chLIS04R1&?LHE_=J%}HtRjp~qw z%z^1NEX=JcbJInzZ;fp3f<<^V7hB}nu>=Y>O8SKP61RkTT4xIp7oTEKAU}g`>zvoW zj76mYGS*(0Z7EHPs^=P{xakq?oAgK>EQdoG`N}`bE827XC^>nZB}b{wiMq`RnG zMba(SoAp`@i43O{dAtA1M8hX;@p;zVcwteZkzaUuQFOItXDig2vQoKp!bdiqRbybn z8^=4Nj)Gv`0xYUCw zP4$qKfu%vj#_H%$;w}C2^&&LNg|9V9fDkHK53Jc>Q*@ahv_I$9RGkd3#`&gx0>v(5sxx@ ztPCAi&4n)98lAbS8P$<%t7q^{Xz0!6=iyDbLl!T>`t2{JL)eIMc=)f;w24$Cq}MKr zEg0`ZGurUh+8W-pywY+RC}^EGLB$(B2sp^}#jdE1FQ%^M?mBkzBD13oC8*FAn&t*2 zC|wV@QgcGVTP*o>A78E3v|yx2Xv{fP7A`&TOA9zt&zt z0#>I`3&AVt9xRoVA&DtmM~ld_Do6n{bA!_~@zDM>9a_GdilGL7S|%k$3n5E~Ry<7Ee-Z8#=0pV4&(O_j}Ii-o;443gCPz|VW{{HtM4Ej0h2A?VX` zR#(z;CBFBi?z736lc8joAFrO!T>5*z+OiEWBxORVMhY3Frsr-p?SfKBMD~;4b6)&u zwUCk?Yny(MB$=@7u#~g1(U%XG4VPHE*@?s5SJ;UwlvnrEyRKX-?4QKP zZ(tnVA6Sf0O%pTFij=k>YMkt^ZYC56^nvVbBxeX1e4rFvYM66C2T0p?bwnA_k4hDD zPV$p&#Uj|zIZF}3KM{1bMD6!2rUjq?H}(p`l`+18KgrDOA$?#w)az!j#_0k44H0OUn7qTaBx*V31qYmMo~J4ClCnmY z^-Uo1S7j@?0e&?uiAB;KX5jvN>v>$xOxRTBjR{ws)JYil{)&-AL}ruOPC9UuZ=c#e zaTGamSS){7>>1`TxvgW}W9z#v5^JiSl+L{l%wf;1f_n19eA)H3WijqTo>2_Gx)#1q zhO0>h6x6TH&Wg**#XtP1ZdEx27kecJ@$blPiH6qE*A(F_X`R6FXLMRRuXsrH<9l_m z)45GbJ-^M)3+`&!ZQ)9`K9&1S@jjhIHD#skO)m=My!JdfIdw9``)K>J;afx*9lM4) z?WM`{bs#3vUHWaBICNz)OU)l}|52RKh{8gZM*_tM%dsbMuGWY(HkZBr>LcluON1hH zM@;8h?fpQs59m0_Jq);#S3VZ3pRr1SP+tEKy6L-mK`iZ8bt&~32WS4SCBDsX-oG8@ zHBK?@3X{;!za?0q9IKRJYNXf2!hEO_jJ9yJ9Mc(0Uh4e##v^*i`aYiR*y#YBgGTWe z0svU?(^#|{wU|_A6pM&oroTMcND>ZxRu4GXTYe)Vnm)m(mRlT*cEeQqz=ITX( z1hHb89YcvEK$>XCkRH3U$`#P%YJM)|V2zleukI=^cf$~@TRbVx0;Dt6QY=xdUwL_1 zb)u@$$R&uBt8;mthLt1?tZ|b7C!^YU9M37QXo;lW1qR2vCXxU!n&!Mr3b_Lb%*<_` zo%ETWVI8PcM@4~^%6qVY#MVBbIroJq&oDI48QB;;;Rwa}@b|q%BwHnMGk3^|ah<9I z+0>}mL>VW$ms8T=+TJ3&AAW)+Xh$%EXf2~J< zcPjTaIHq(-pD00cH`M(2RrCNvQ@ zcZQNn%dIToKHbDWqYGRv6s!(QZ_8r}s$28pM%~?L!24Q|R2c&bN0Q5d%PQj!1N>Pe zF16F?%bor0KtO}G4GIfR(IN(ka#rKxf6YnusApoDuCcX$8n}$+z)g+R%q&c->By|1 zfG0LfvpSDhOKU&Q^tKG*YYkN}&g>YQd%j;f&WyN|rUBmG+M*O?0aXwHS|*Qfyc^oo zP7Mt!mEfElN_uDo}(AjAZ7K#rd1KINlic0DDz1!GJa3y1t#!d(-x9rm1Q~_^Cx$g{fAL{4F0o>^8; zFS?w;lOmt@R7`)m^t?IyjYr%CwAFvx?<#fn;rHHC0Z=b|$L#SJWB`Zj9sN#NH0wBk z`qgD34D~OeXxHFD-Rv|u6yvb7_e~kwg;Z&YJ6K++&{JU~;2bAx`jR?qttXjJ!R;2_ zKvhrMDpu4D5O;Tp zsW{(c1EUK+b>~11)zg;3s{gF(FiLJ{bT-Z}DR?uH5{$n=P{!f7=`4B6aiL~3qum2L zDr>vb?R!W4uvM}Z`h=#ddghIcB~r&x*-`-&(0-=n`Uv+}n0cPs91P(;kabV<;ZvUJ z{qKg<9p*1jBzg;rbabuB-;rr`v)pD=NrQlGSI26Owp`qgqE<2_t^mtp7^|c0T zZT32!F0XlO+4K0UbSF!&pDV9%nru&@04muN-FF`FN9U&k=Rqu*~1 zBXV*G6cq6R2|2qpc5}>|HK|;Er$NsZgYYl3>Wymd)_Y}MSV3COP$iB zTtLLoIPmd@R6PR=cz}1^Va}|G=ec)t8m-51SNbB{gC_fBa!z-+I{u<5PiHC&0JLvf zK&e4TyGXbXb~xU-O=VlvJD#{4Q&A+nCqE;w%`K_qBcZk5rHg)%7881u`g&M$2 zNG&%|vx#QS?;WR2e+$C>Zed7`r@4N==d1zgnqxl~!B1RLx4H7t(KHnmQe1bgl1}ON zeJtL&&#QVSL2aZI=)E@bZ5mA+*6EVjiw$NK#S`53;rFDfuDsA0I?C&Fw_s2FGN3BE zb#%(YeY6a*`9Z2^V-M!@w(&XmyRY_b-as_3-^OLQ%NaPEbZ3#OZD_ilUz?tRhQ+Y z!8)byXIvv9@PNIG_zyfY9ouQ(;P^gQ?VZSE_G-8Qq3_DW6i2*tpoz*J5KfEOE>2X`WG8bin9hG@v zBoKen{2WzJ$&l|DYM3O zq@p*C*kH1vDXn3YecM#cx#F8=eX05OoEktb)n!-j{Kk=?P?E*5qaS{WNeUYo#l;0D_j*6;6|$le3_VuQRWnFS0Qpm!Yw?9yf6IDfT?-JSFhDIF3jo+of=>UaL=j z0s6JVZWIxwJ?=RcW%4e9xt~;-F5eAOopj?x)7$n_TuVp%uZAOXeMEirtVuf-Ut?H1 zc~QjK=%Qk=`LTQf_fFg2@q~e1DWDe0%kF7jh-zQ@x{oF`p;#0pJpUItT0${|c&Oi_ z`to6}Eb)sBG4|mkN(M=#Sn@WlEHUuVj4^e~rH*6rJ))u=oC;Z$!c`%w4Z>3<^^XS~ zIvg&tpSL!@vc6PkixPYfIbd=tm+crr9HXK$J1Pce?X0ENk(n>96NyTpPlexr^);2& zDBdYP@qd5Id?NJy{3*t#p@(`sdRr&49E8Pe>`?0~fLRq`Xcu7`LkC@4c${jXXVgoi z)l02FFTG+ObH7LpDQ`wCBNdgEmiI@AvZS0% zJAz=8zOa#UQ*K)-aaN&(dOxM=v!W@#5+zjifws%O+ju*p1;qrmZZlOd_-V3DH^im7 zp+Pv%$24HA=~S1-#N7M^?zgA((RcXuFSY>FH!=J9_r0KadKMPpg2<;A793@->g+Bm zAh5e88rinD_oi0Aq*-ZoqHlItp)Ex7;;;3~ldWxCuNdQSXJN@w+172+^;1* zuUcwgfcfFm$Muc_ska^z&8N>Vk0q~gkKZsVWE2w)MK3f_Gp5X!OjegC-9g9r|Ii;l z_@0^#t08>_^^3o~Fz|YZ_v;oK&lch>)m{=`XC@5b5+XQWJhY?iBL9cKDPaXBKEgH2 zZwrg?H`}ief7|j{9@?WLhdoS~pa8!en4zLw+?zHMk!z6LDju#F;hO^2J{;XF+UWg& zo@i-qLHq>YLI0vEVtKRGWndSQJ@KblFtqKcC<_-A1wSmNqEdue<#u>XBD>${qLc)-2Ju!dNL znOAu;c}+C7b1Ed8!R_|+XB3i{snx)jloBSQy$1v6CZG-RnR(dxQ^zN@o&4w3JVOln0FUJGcVMi^Qd%dm<8e0~ z25LR$web8cxA^JL(&Xo^f&3u^HCxtT0zUb~&tBGbSb~ypeuB<#l=obBGtymX27B`x zShdJqO+!EGR?_0$mha*uMw>b<@GFNDlx^dY`)^#7RL{aQU}c4@aQsh_c!@>A;$@&n zy{ZxeL%7=^y%=Nu>vk1{_@T9m`iw=kQUKhksS`KDZepEC;ZCFHQgdlcemgHQcg5Xt z0J;0))|!DN+E43vfT#E>K@4qa{8r$AuCVZ zUN1THo>4D-@(~hY;838AoR@KPZ@2N`B=F8P@otJGU;q)c#KsXP=fg896gvfh*~@N} ztq}abIS#gAiz24s@_jRDSZYT5%hsAQBvoSep}?Cg@l6!-g%)w`p>twNf(y$#H7YIl z!1k$!Vih~MS20ih*y%0?V>=Fa3rGNB&@_CXZQ2tY;h*ndfKj@Nbk95i)r>fO4&$K{ z!dB2BXuDIHC~yFg_i2Qayz)z3)0tcsr_*_2+R@QKVV_IYacZ5tw{4Qd5L#QIDvx{d z#gX}+!I-^3=u6%>g3=bf20K-o>>Zv8b}WL)XxMKY-;=1VVh0rzPPgdgAw!bb%t;E@ zCV=VLiLe0FEN#|9M`JHiE%l$nUKq9Swh{(WoRAxO_S0{yF0wz^-CMD0iv0qBE@!Pt zs&!EaOV=s%x5>2V?#u-Qx5uIWui1MeU~G?TNYl#S0Ad(F?Co&?N*gP8qPCXAB}#Kr z8=ga-#!DjE1(gcDl9Al+Q#C^@ni8xTdRjxfQ>k6eYDY8V$aVr}fjQbu7S4boS7;pk z-%xp@|7#=>pC>O#cmF|*eA_hI9B>09wPf!9hC)&@e?4wj=`t7aTPDK6AY5 z0M@cYhOTC+os{vpM*~_lVNj=hgdRq!jxgTKeHr7l<|rT~`>Ajij9*7}3tQ1?>O#hX ztrh5j5Q$2XrO~i2!BDX&xfenE?ICi`OTE&dNEglfBWp#rk6QUA+D6@-xFQ!z={E5n zOvnHBNXRgO&((m$!$m1h>A_%Tizs9cr7J&l+Utn-5&zdVN0&RB+1av+NKt`Wbo~C9 zxV7Es0=)9L8&k1$dhA=eRGE0<}wk4 zDXMV*U6R_()crBO)d|p7ocosU!tY;wtk=2nZcwHatO6VvsE^w`M1QtxYdqy)ZC7t zdTh0lLbis%ZzU-e*;F~081QZO?zJ5#dVH0|VXPl?Hp+mFyPWV^bb z)L28=cI1snR5pL0yvpHK&Dvw#tOpP-mFKAL* zID|IzdT(07MGmIeV+s0fwWY7a=LCZ7pN*L3I)N{pm5vQJY1Ryea&AWtfn2VPNnX%G zkTCFCz0d><((Z3r1q>ij6GQ!Or;po|sO3wGXxph79rH<*K=*$WhZ+CB8C^1aab%{R zcGvEs68lyibG~PO^8lTuf@w!h{!>@*d*VusEaRV*2d@`wn9BgIh<%u6c{1lt@{bs$ z(r?K5_Hp?8NvcLe1wTlB-6pu>u);_^>bf6`;%wOSu$C2vymC`t3Dg+bsDjt3F!X0Y zO9rU@FD*c4W)T4+78ryrt{GTCyD!08I14R2kzxt4_$$^nGk9&8URo8Db z5@BC|*tt8gRoFSbtxIPEFF!1zf6`npj{HIb5O%mxw6Ct#webRmd7vKA_z+fIcw))+ zig;iUBI7vPoJ^QE?o9W#*4crt9i=YX(XjEfcq)|ZcYcrQp4tK;=mY&7ZHcQMG%o}D zKuFR?Q|}+443T%H%8;QoExk8+>-E8UOYwZBjana(w~ygQsBSwmqAOvnjVcmwfXn5o zI_us7+@;-bVXmoUh#6FdZTC%9I)lZv{fZuR>yfe`6QRGnh-=uo)(5|(Etva=Xo$77 z67U{tbIL=q(H#!;4e=HOK-P+8ve6uMY(#;oF`ibRiLPff3z}8%lGb>3VvI2*AnF(}LXC3jQ zXs|@Gmf_#k?@!DY<}2vQ!+C*ZvI4UbD2*Ev3Qm_BGNF2Z*e`~A>Y`EVT7*egYQUC| zdsb&^C;fl(li+Ouxtan9CWpI!gd^}-{I&&s0AsOH+roeXyLg<(=nC=pif#Fyollp9j zW*gjO1ilL68T_AgC<%*&M8sbe;B7X+CD`3@)OU6>G@ui_WjK?qO~!Kt&F{&mMZy?w zl^j1pba*OgO}3hxFY`w_Udb<&9Z2a=zFKg9r@ZOSV6256`pUoed$LFBd@G?l)eBO5ZmFn|@HkO@1cqtTHIPJw4oB zZ_YWV-bqSLc|X4ixH@{zAt=NoCoVbz5)vUocTd>K6FJc>)1FAH3Y*CdufOH?i*AWw z>!;TQvW1#ye7+3fzvD#Q&mXhsbAqXY$FODS)zyb+x>@J5T06=}NJ`3jJ6?K+sjUw zND+^$E#Fnas^I^Gud5YgwM^;PECmUJ0r)Ok7r4NOkt$acA#y0Eu$O0PU2&*Gi>gwB zl|oX5nhvE6+uOssrBMK9A8Q}Kb$=-YqC{(6px1MP=KYQob(WD=Bw43xvgzbm4pm>;M ztZ_by_=%|$%)DM|=WAS@V3!Hd912B1R;_j9=>g=7Ic;C>c-59S3z7{W5)D0!6^3To4>e|U$aXRKgM&sZmB4_wr1$DwRQZyq;wpG_Jg%l*0)0>@cH*m3t0g93Ou zFy(Vj3C-TE)|V{M{v5=C7fc|lP>!LLqkz_Gn5<1SUdnN|YNppztFSRt_W-s#U^j;O z4B40q2gVscarPPGM5&0&cP5~wtf>#jS7wDGDa8SP&#FXkDh2VrAlHUs&Evoi&CgnP zHx_GX+#^C@aKkm|EH;eb?{X35ObAF%y1;GD^ml8EYG(&o%pMP}w&E4G7GhAM{|evc zayt8?aK+4+IJR%s!tMPKpMK0p)g%+i3{xnM)Z}XU$Op8e*RN}hc&f|4I0cp*?0s#p z@~EGK=yu|Ua#6JEa%A7E^RHqj%R%NW$_|Ch;uHU=u(*(NPtE>uwwM5(m%Z7XNC0*1_eS}_OD~6 zVMWq+cgJH*jg{K$%jomS`|%9V!8`fF4KI*iiN@1@Fe+KLn^0R?jT5_ybBD-e7Grn4 zkyjn1f&i$94Mb(1282uzZ;MGa?WWlIbFHM9n$@g2;#ii^?B7VFJv$NowH^w^ftJOb z-c*|!wjb{&G%lFB=m>S`+lLKho!o$1u*0!Y7%|%aiZ;la$xIGlU$81qCe0s#`-aO+ z7JYL5dvI}{(eZ3$Lxf`VK$*oF4(T!85I0!*+`MG0@r3DvEWL1(K)QD#$-LgFAqR|n zp4ueBnW|9BWLEd8mM5yj3kseLk^tbIGr4((YYh(s=QgA1i8IpY4A^HL+#F0l;4wt<&Cp8 zYjuHx%Uz9cU({=IqZQ6^1fpUAzf-Up_oME63)T=5LK*WfMD49I(no!rdt(RM3gW%7 z-;>G0WkSMXXLo78rZ3vo_B-UpHs%+dU;kml)C>^3v4OZ?yu#hx?~(@Ze_NKsM%1D+ z6DZLmh~&V;;xOp{>(zJU^p_Ffb1?^9v&-om1rJm)fklF{ABhk7Q;D+Vj!h0Z!q#+I zHbRq6VqV1e5WGZB_o>H%M5|zvNoTD-6p=@8>ZG6yj*w%T+p_0$-*K{3=ls&Rk`~|P z8+P{0njIM{A^3|4>wpKClEo>clk~&I?9^BE#u#|2|47Gobr_+?#O5(q;J4nqk?yCs zC6$r4$>UVmacP77;5JkJ(;$4>2I8_ljY03Uli`<CIgJ!&#?XF#wPnv^KkaoH>lOz({+v#|}4&SAMmYNvQ~rsAJ9Swqy87fF?h> z5G-#6ox+S2noKFl-T4?6I@O*725V*p`sS6P@WN&@hx_pY<-~^+yNIdmCO--aCp>-oZWuCcR#anar%?|BrBsX5kG?yAKhL z=UiXY6djaT&;QU^VFj^o;S`sUAL5#~{ZBF>Cz;znFSS-&6a=>TDw3VNRN2#<#cWkJ zyty94(99}=3X;dZ@~pjftf|*QlcyYWsB?cj)9CY7&T?1eHZy2vTzHQ_F8KWx0vy1!hf#xS*x zZ}NzHg>M!98hN~GhiugO)U>p-D*RlyshUik&Zto;B{_HGzY5ps41d*}1^Lms`@gHC zk)5x|MfHF5g>P^1_mrxX2h zp;_Pys}LyxHFHwzbg@>H$smblqH&is-$!t%$Bb+XVD~pVV0|I;_?VNV&@F$bZN0fn zv_CE3LJXq4a_!JPxrl#tX_-To)r|r@j7d(q?rddhK}A(sSh?xExF^$S>XJk?PyhKZ zvxByIWJLVbt#$-HLhi?&Np>UImHw!Sq6`V2n?||4T{3=_-`>q_fU;Y`zD;)bVvZ08 zTc%&>1>5FEtP+LtR^~5l9a^;fJb`-eV84ZrqR@P@>Uj#Z_KYhp-=(^pwk6xtC>_wO7-iV)6f?i2n@;v|??lZch*h=*GNeW~}&uIR^E)gp?~I{ir--iVA$ zUGND^Nv}x3iixV*!*}YA2D7n&@*v3d;OK(F=QFVIsLSYr&ZH=rB!o7u6A>-9>R$^t z-Ztl%MR^|uR)dXa}v?hD`{K6PDR-Q9&RuK{{n!r+3^vZy}8U0hA zEKp$Y>OsY3u0EOlNPe1mE{LnmPwRDacl_kXc<0YTjoS@$?=H?NBpzjbmKM}qD%|HsN*7ItkE^O^B zth-;us8@0|pk9L{Js?yZkhA`KJL!Da+~ruuWf*sR;US;$f5R&$*2AQOFLmaaO!nV+ zv|cF$>efUyDyomoON8Tp{0g+@v+Zhj9{MhljKm~z@4RPPmT)!OD|^O`w$Yv`P7#oj zOq|5zI0m-d`*wHNTgX@r;bXpAxyjq-p<&0&pMj5tZcjk1E}_s49>uBjlU@oZVMWg+ zVA3B*PwrN4<2Ia6S-(L4LrN6v{?urQd$vPL3@+^sQI-Q8};cIpR-;E=0^DeeDP8{-YWCo1#<{el>^8m9k9+CJTXPiw{}x@)^ZmRWR@)%(gUvkYm6!+ zmZUI<1+k-3Np+*-1pcbZQc146)NFg4+1vC=c+{W^wGUwFGP8Hnk{U{pCTn?#!r{z+ z&*<~oT8B6+G6TQTB<^bV=YVEv&_r4NyeEtppEK46@DIZP1Vz3>2n>Vm*?+OU3lt^z zAJG4kyjBxY$Ngh@NTH#)t4!de!K3OY$W8m%T$7J9YR#etrm&6^QS6JvICA8*-*Gn@~ zv!DQpRG=MzKaXRtE<{xH)zqG{*gqtI6&l`#7o_Pk=}$CvNCs=h z4vT-@i^XiM-5V1QOx{QjuZWe(Oibti2?V%g5e zi1(qtH15nqEcR0mw{92!pZ{~Vmt0^kK26)^J_t~Ti0yq4rMdEq(EK!XQk|mTtj_zZLK@ECKRF&OO>V7&E!9P z>hAs4;5I+x8`smdY;MlZFg0j~L1pwX+GD-P^L!rPpu%W?`+#^bQFu}P7n!+3_>k46 z50!&8#;6`F78A6?>(L6AEkq-kic(X(R^=C39bN+vF=XMxPG-535pMGl2(RtcOR;J* z0Lcp_@lK24De73KZy^DTLWi?y|6YJ&TL%+<=)|<3U&63wJmswB?chS{$TgK zK?G%uRaa|CltLFCk@eh{GDMatol36!6FRobj zbdcI1`!K@m>(uh^ymj0jj{=9BpayZ{fw?Va7%w%v=!rQBPOY zN;+Bt2)_R7@xRFG+2Hxtsf2}5hIh(^!J9qcB|h70HLE+EB5bO`SbI|cbXfRHN$tp- z(s5G0Uv!ka(;sf_Z$7GzIH_`i_O@6)sF;xd1=o;E>Ar>G=5M|N^uSGp;|gitA9cKe zK2+65YL|A2v$OW=g4yD}VJ9NAsuVPdqY6>aFI(;wRs099CbMEOV_>#8(EO(g|HE~I z+LVORr6lgWT$(z^sxz$Mxmg^008#^>J3vi*EDS_cY#hBUTJr}8Y zw%y9cjab&ua5uJ^zz(g^=|)4g%6L^jIkhdPW|`qd{~w0B6B~ZXym**t3gWDzXx1wY zL`Zk<-vaARMv$x4CucE_xdtJsJXS&6ys-Jh-M8gN7n|)`3UF%d%@PsfxA`9Khn$AB z#)>SS@=SC_BoNw$=Eo7O-F}-bL?&x_#|#EQo;zza1|IEf=NN6`^2r}6g6P=otE^+z zyQvp~h!NjhNoaE*7p6DB&z%ZC8G{HGRZ@a zA24p?od$Ox9jw2hk^p}HdAerIj(xFaQu*X)U8_jJe!g5UU3PRG#tOa~`A{_+MZ6&S z(c$_K@tunIlu3oGGh}u$-ZM};-GnDAr*_C?t?y)teUwDeC6#_t-p+DkKIDrZ z0ZC+9Mvu`aLvrrCgZy%LQ`D)^ht2g7$m|pWQD^t%`0Zzf9qnW!AxTMtWn;D%Cc3%d}a?)K6edq zovu>bdfDYwOS_2uYt^bJUtA8NNztG)*JiEvuL!OTdM^S6?L+O zk>a`L-*|7AuTuf_?H1oYI2Ew5unaH|(%y&UOdQ%NUk5+nhq4#AqXZ}FhXO+LIW;i; z{^PaJvcQ|ZVXr~S{pK+KZ0)fU1DT|!BYb}4ALHh-8u@&}AU6w=LHYUO*uc;aBk%lH z5Cg2-XYmjf&>Ax69oKCIG3*I`<3(f$7r;1GQ%-Kz$Wx}Sf+ES%(}Tll*z`80H@feY z*=+$9tj!k1Q2QWAghBc7?4sT||F!9GT1?GE?Y=gPE(#sDKOoBdKZq1vR3k-nV&8!0X@r%_R>B&VWr ziRFef^!3?81}m=kOLuM-Jh)wLxtJQ|Gd&+s1*Q4WQB6AYdeSA9>SJ@9{&U-81Cq+q|nd#gnvIS8eAm>lIlNHcr zKO=@Ya?)W*Hj|OSSVoN%V9h;ZQ)sq1bH9eKstI?UX&Ut{o8^U|&;@*O-OGmhUKvVB zZPI@=gX0LObH=Ve(+tyx*ZFlMEVY!MUSZzu7Xyi9Px2l15a)zX}xwsyXolL1RTRo-I%VJZziKVm#%+Z9y zRKjcZ+Cj*QFxu*o6QBgip>7W&`m@f|J1GLKx%yrH`lX`Pv2K>jOH#f>ImcorUx=Zu zMX5CzE;9H0m98nUcRDm1^E%U?wEPxDq0r=*O>fte5SF^us~a7lAmx2W*|a%@BJz(60zbqDWgc?5TMKlch`%&MT0xiHTo?(c zBk|E3Ob!gEsbuu0h`866`t>hs>AA^Uul7}+j{N<38xfnAGS_sAN|H~)O5GAR*9Z^K zKWU4(Do=dB9veOa2_nQ3lTkFAONc~_bytDJ3}j@lCj~=BC+G*O06Ej$V=Hw>>!H|? zJwJWx!FX^JBIb;jl~UH-j|I@t%MGbfYaE`q7-g*(Pm9acqLWGR)iSmzn57zBlZ^mL zuF9bwsMn0Lc0eM~gZS^A6&ZC7Kt|k$3 z^krA3CP*I8dl_RYqz=xflR5Kl8TDfxRsG@n3vs>k zqEpZKd|r96lv~``))0Ha{{(f>{L)u@_6JAm@3^KtHEDc~b-R3Au@t}snxydmOEr61 zpZCUW1^5^$q6I~u`>8XXWTT=j{Wv%c#|K4`4xy?8TdrE| z`Zuc;UbAzxx`SI?p9D?EJXJ6pU?e|@`DJ1-a{p;r&~kcMH>hd;s${JdM`CBj&(6-q z<8QQO6R8MJv_`H?4SC3}8O_o$@VxHdLhsBxOY;)^M_zxG23600un+)fmP`l@8R?2# z55f~W=*Va2C2O;Sok}nmzYUFqNlQwD!1)VWT6iby=P%fH_Q41O3uYr;QOrfGl+e~4 z1uB|K6OxGwotaFQ?o+)8B&3G?q*1!|7Pz?ssl5pko{q4O`7O0%dk(g57NR`zv>< zvqmugxA$YwE8sZunH_}aL^Tgr2g7_m_(pJMdmvZ63x)17ubxWo1rB{=p(K4q1(#w@ zm*zdVyWt<5H1ybvFH=o9n{>RsFFiZ0`;?k+83%A9kMO?N`7<+_?#xp~P0AqPYC(TI z-^${uP_JidJjd#U{anQ@rQRR!Jx0vX%FN(wc9&7RRZPzO#g3`w6ahg+M#e=} zWZid&_;h^s!cml-r7!E*l1LsFR+MdxbZVlz6_c5ucw%g@AyPs7IisA`LcF&AtBHiG zqnSmrc@yi7Gc#Huv`JX{}9jHj0%E;LmD56rp=>lV?o$o{vm!}`-gHL z?;aFeg+BG(-H+`rc}B~qYS<5qS-P$#CfE(_eC2{D+^)G5rg|>s0;7rk$P(+1&T|}K zU5*eJrgBJTJzY6`ZC)x-H6G$^x1~O^`2@O|%Ty+13zPdRJ-zi*5Vxt8v%e{Av|6mO z?MDBhC%#zR@AEA~-$29U#4Y*e&;koTS!R0)>kviwA#lzL@;x+r3NFY?i&y+( zZDuoQ>E^qQtm8}?Kc~`lAj>f}tfffkyt6S& z)de2=gQzn2Mm@LHoflDa7;}&#EX;yLFKFNCTX7tMA0>?G{s65-Kj&zrny?2j;{wR!~ubT5)tc;?(tEATsNb#ONuQ<09(6|=mzTlsA%fc1$Ea~|iJuNAqw~7Sk<2W0gq9YX?9Ep-g(=036u*TU zOh??N%WHC+R9adkoW$@;7SavP(WZ@TMq@p($!J&i6H@6jc?TO`P)YG>)MRNsXCynh zaHw?IH`CIZ{qfk8U|ls^%;`8{aJm|{;=Li}o6E<|<{2r2a#IF3y%@&M^unoldyn|3 zQ4e&`U5|PQ^`pf+R{FS3TJ54e299ksbe3%f{ofUg;z$lYCX zxzGZHX{VpeM!H&Qw8#};awADCovW(yae)k(@}MW{cAm^-^vaF;+Hw5e;WW@eW2TUA|!_@jMVlRxv|A&`(2%_7PW7%Y_5Mn z`TZZCc5;V?uUTP^Tq4dyede-P!URR<>Ei*G&UE)gG%<1ggH2L$oo zt+HK{hScp%fTsHemd55}-p|Q#SGv_XP1b#oE zc;BKx@glay2n%M>dtPD}9*$_KK5M_4Q&mbNb(CIkzP>*rIPc7v;`?PN{pN=vM$HuI zLzm^BgqOcbdnAQ*qqx35g8!SdvxRP5%&LB!4xE9)b)o#t+Ip&)p3fPAM@;;?bsJQU znOK5|-RbIIT59d$B3DdF?U3&5^LDd;c%)q2V-{G)y3A#{(kIXMq5*a4o3+;pxdq}v zjV`X?a;3JR&>7{W6y4S}F+tWKH0r5|-FvStw$=mN8mkq?EK15pbIXsMPFH8g`$L4- z3omb4#e{TBz>;t);%}-(RU$CTu7cp&rA0X2Ky3$22_02ku*XKAp>?q?|0-xrqQud&vbjETnXU)R~x3 zAo-g>DLnJ~fC6Y7vl-FDXxb31ta~()4<1TrUDxV&$4RQ=H+m30Gf3=Nb#@ocLO(G` z_>&gGVt<>+dwkWLfRjfqt>^8^pQ5Q6q|RC4MVLZ*J8T3kX=q|%Q%B65mVRlR#DnJ> zWwy(n#qY2Y>DFz-W{IRt@WPX-3als7P;dzo?EeLU>Ppwo{uG%A0X9F}2^$rH@k{yR zgQ2Ree#)#)f|ly-$!y&Iwes$>q4bjz?DQhhCC-09Pqx+PUiC$jzFejFhjn(VOkbcl z7S@)Tj3l^c$ShQx&j{t?uHTWC8(oDI*rfRcPoCbWv6-3r@v_V);tr3dNk&7UNSZL5 zQ(5iu`_x8hkW_Yhi`ny@VOEgjWLEew&-j)c>pw`;#}{`Lc$nZU=_Sq|;LZk;C9dWE z7k(tM*gyM!-Pzzlj3-)`pKy&V25&jUeXvrOD)%acmrRyRXhXIr9p&;1@U$0H#LJWI zIdP3x>FBqQ+2&9Ugce)*e~dY#a+)Q{yPOxVIR4YCPpu@aGNE9)A5_^}HGceof@uNE z(qC{5-M^x9aY<8nI&Vn<C{{kSYN}u_Cj5JTUPVq0n&=uh6=I(5hx%78vBO{d{k&z?j=A@BDM64X$4GR>Zx^z z-}>BV04qB+rst{YPe9x~_rD^rvcrmEFs~3(S6QaXcqj1UxlChE4uFH zv^}GwUP;Zz`(R51p`Z05=!FCdvXouYY1D7+9ju+0(?%c?!`Bn!i*02G&4bEi z{}okt*K~dZPxMgo78Pb#`DFF83nBZ%TuL_DBz>k3{YUbiI$LU40zQik>APIxRu$cd>|y!sfylT|A75125y`I^Weg^*0~sDx z_U>mhsK4g^2n^2UAOoP;-W8o2&8(tst}sTn@?_asWPO(MAkbGS`&Mo5a`iTpeZpPdBUXTj4WQZiqr+JF~rlY2XSv zFWPfQ#@0mZHks`4w(whJY56cEO*O5BOTDYNLoD#>+$MgecqoTfg+Z!RdMmBlI+edD zewuR{SIVOi8VTT}e!Rf6C0g(l)RP*-*Tp#`%zvoV>62@tdwdkAN)OO1+9Cx*!(<6y zXr^U6p>b$M+5Tj5ph}~$V;;MvzdS#&CI3azfM&D{goKxgSs+X5xt$)9mpAJ}Bf7Sm zdR6_2wy*Hl&2#0cffG$Ht0dY|(Dn%aRzXcG4_XYpUID` z2r_q3KI_&TO7!4lYnzuX6(vcTwQS}JU;~HhZp6nE zL0%S`PHw3nFKBBgLsm((`x1+JG4ZHk_;AMk9~JDFTT!vlX_Vu!Xe)sqJN&;XMpCi@ zp>bk9fKQ&beyod=Z=ASflfo%RnkjA`vO|>yNpQRbNFSqgjsNNG6kJ}#Zy$5Z_Xi?2)zQ0f-46&}H zvK_j=wh zz-syX0582ts>f|J%h)wT(=Cy7?Xl2GXMgC(1W?=0$*Lb{yE^(Jlh%7XsDBi`Nu{=;n14BvvoVeKE?zx2b5)jCf^RmyIj#E~B}h&83q}T!6&rCQIB;iRo%-4VA$z zv$e76@ZEkFu7%LN(vo73T>dGzni2YKE43nZm$TvypSPyAz`396i(v>t#B|Od6(@qP z0&!5i1Q)No2EEf#sH7HZICK3#!+bA`bKYKaoUKhRI{0%=!N5EbAtv5bd0=d+(}VU| zL6)9Z6-krrU}syU3@~TqWe5WRpbPf+fbDX=qC*+VQZB4)K*dVv3?bCRZt#>yp}Jsj z6m0Xcg8jK;B{fk)X>$bj;#>R;vT~=cBk3>UXSKKp-CqTzSMn?f1Ih_`BW07H$Ix}{ z6N4NJrwW|2cbm>?pM8{6Da&|sPAJhTY1;*9rmeHK#lxr;ypKW~z-rpV^gmOoCIm3|(Q z^p6|rVE_mDwpdqBPRVwELN*k(1 z$v=BjNmuT(_r&#y+|_0g5zh$)G>g%;{L)i4-z}^&(vs zZlxa7!A0sNvqgw(tZYMN=~2BbUT>nFaLA)Z*Jf?mZx|Qrwo9JxGu1YQmbh|2qUV3} z7?PYo3@c6maHku`;j%(b|Wxrx6~i(%j_#<(FLMuW9O5lX5iXbPg>-L<0(n41xs1%HA{Pm z2xuE9($g+}ihSdYR<`QWp;@zoTACLc676=1-`JYMgcHumDE1xS7a;fe#dKGKqJUvG3iG%2W`*=%_UY^)V5CnfRmIKY>4muYu!KYadsQ!VrlcH0l1Hp4 zlBL&hc?&&q9hx0+i1tz;V73$&;7W}_^9um@+9gm1{vxKOqw@*XBhSB0g{Fi^&9L9= z`;?D$R~^-rH7Rz+X@u4Eqwh)hf!@m(hyupyQ5W1r8-(!UlYc)V5|U^~g|h&tA7|Fy z@S)Llxm(DnPu{#!E_?N8f@WBp1mj9(*R>bLeRTUiqO(U$WY?GLrAzMFRTG}`@eZAd z12Hy`9e*-EhRyLrapb85*QEE_S)HCLfnFqif3{8cbVa3}Ab>3)iO2lg-*jO6u0GEe z=@dU^vCm^swN8Nz3^0wE>#?vGw zk}9=HTpDG+5Kc9`eo+@zBv(yU4xu&KPTkim3jt<1onP9LeLfHDbdrmI~z{#dATQ4)Ol`eXnXL9WH#eT zWJr=Gyh#soKSK?)$1mI3noDN_9e^L6_D>}6tMX1AAgxBKa&VgsjTni8A@s+2Z;=;5 z`_OW02_El+h4QJacbiXMIG1gdu!}vHB7EG+dBlO;ify8n4=g!++}?+s$n+7)q_-ZN zxHm2*H~BZ%(RwjH-)AbC3QtE0Sx>qLLQ<34rt1<nWbN7*UxMO6Q3UFGFsO5e=77O_}8JI~pO(ok?r zOEJy${=~@4*4Gj~t*iHr(;9!FQ&gB!x$yomEjzzRZ(O+Zl=6cLBPtd7ZJ2FTE!fWG7aLjU=DC zpj(h^c1H4;_eOsC{sG3ATY1+NY4MUO=;2D##6QZCDw^(sWv+W4vMw9oFvYOriRIxZ z=BBRG&nP1F7D_?L=jhUG)}p>tKGbaHd6MJWEM6DW)_arq8#jh7dogL1H*T(wq4`kU z!Q4Lv_qo?hIbBo8XK-eTSS^P5X=n1r+lPQ<*I*YSeMgK0Nk^5Qmr}+&LQ^lljEM#%R~|+{KITAM(m9RZ^3|&)2jHoBEF`X+ zf|AUoMyC_%ZZ^k|)W$U@wuN<9hsVob<{sN7TrRg*VbznqdnE_JsPi(@c?q9zKu;*2 zlyr;3b$6stbRoohQL>7JHyY-z@Hh+3<{IvxiFGFA$P}MyWK9!|c^sPV)~!oj#(=hY zZD7z2Xgv3Pb)?SjGFi`f(YhG*^4*lg;e$Zu*Oqg2nLFkMs(nt#6bZu=F5@4ERzI-y z^e*hZEBF02BNEtiuNy7PQQbGnZW&|VW($OHHj9vMJ@TQ!1H31|Gnyf1e^#!t$~iWB zyfUV*N|efF9lu!BQ{bm4QaNRM(p<||1x?XsJHw#QZn9@ijQI%@(EjF;(3lmU;0;XV zItc?(lmZQwz+&p(Jcm>{GnE(TwT+PSWTeVqXU-vgcvd|x0WI3wroUg(caCw}^lOfk z@S{w(gHw<4T=z1T6&Eu_{O;Fsz;f8kTb~8uY&;q$(fi!0eOeJtx__ld&u}W0uQ=u1 z6wLQN>gJan2br-g9AdPAg!c;pvZ#4x?`~Z+KG*ZW!+h!z7!+u{!h6t+c{B;qW)h0u zZ*wn^?E9eOC$nutPmYC%uT~U^H0<8fJLt@hs7fb>v)6HR=Cp0D3L&KLjgq0oY?@B~ zTXZqQTDm_;mwy>VFZcNmJ?Z&%dwD|l_MvXwWu1t-i%ubQYQV_L2VmAi?`4j8RoM-W z9*LmcW=;t+D1OY9OF@bn*C?rx{)MeHScx7bC|tPZ^s-0nzP&v-mov=yWF|XTf{zyRwah4aqz!oA83$WYnex*tI z&e{{r20J%$VEOHV7;O)b!c;S)zv&C8NqGyL;qxQEIC5fZhk!>t5sMg_Wd(-By3E7M zlhv~($X21+YnJK7;|DnaP;0kv*qzz6ndil(kfBa(om^#@oJ7WTHOjPu*mr#*VAAn{ zrNUHp9X&M;q;tb~59IuQ+kSQ-u%eNDJ=xfeUqtj$(&C%bhl;=S(r-qaD%Nrlx;)Zj z`dMnF#n6+A7YAnf8BH?3m~YIf>k*m@@WbxFX$_D3EZ;hwt)(!rcNe+7al=|z~t9XjjM!kw`L(b8|3lrM1!)t%uuAZTFbjBwz24hlu-XK zxW4DS)z4~1=KN*-Po1cf7AHsYv}Z_(BCXBOe4E@Wmx1d(2`=?Y_pmtw657Q$Vc|Es zpcEMiizR!Na=3=zfj`8~_k_<2=Sbd|$%j58if-w?Jwc^SG}b>Fozd>%g-);D7}tC5 zH0}oW3ka=Mz4-y(XD8~!@?@CJ7=}hvMr2zRq#Yx4@O-0a7UVCr_k}e@bxo``J50^T z&}_N-r>(J55~k6S?}dcwQ7i^uveum#NebmKJ^O9-fMvqB1IFtIM-+8Ow)g-lZ%3h~ ziiB<}lJ#k=Akcb=3n6VKj(|iB$D8t~HSU;FXV&M!axeMw6pyApX3F&}LAz38rnbQFkYR`BpB2NC5?coMx}gKR+y6X}y22?w&AHSSS5R+Enm>rFcj zaeYK9d?}=thz&uKHB}SWOgvpEX0EEmXl8%SVa2hXkG~u{Y#^52D!NQQWa_Rc5 zoLKEiGFut6sC?0jf_7=Dganev8{10It^$*6kv1m|u~EA&;i$5zIUVwg+t8Ljt(+RB zu!-7bjt%zqHF7g0Y9`EIGLkCU;VmE$9^rlMQ6DrGEuHc@np^%)E`X=E-b<&3kJ8L_ z#W@2Vt1cfS?W<7#aZEdn6v#fIW)a_@Y5A0WoL^fT-rMH2(R_jL+!=j}V{jLeimF7v zNi#ohyz&qSFR*f%2sGa9iB|Bbo%;ePax^G%Yda1Y+YqC=`LjHq(aUAR9po+)=lcx} zwZMw#hgJyGlK7FIT)Ylr?mZk8MkfLz%8od+pvu8G4?Mci$H((tpSl-91&D|^@9M24 z`Sz1YIp6}w;DB+SJ*T%@YogIy^aG`5S(KTK8ECXU7}lAxcwZenv!UT>Or#Q;a0J`m zmGf~>P{Tob7eAxizpT`Z#U+NMh+et2kv=K&FKF#Ldk1DN%>p{CgB+B>M_Se@d%4D zdma32^gf@l;oQcLY@bOMjW&&;o~(T(y5A)-JVnZfvxCgi+Ot+P8y4vp(2g!{c&;cF z!U~cgoRrXL1iN2oT9(wF^3WTf99jxLv3$q_qQhf`rD^=&qs)&6qHXIGL}u6Lk9S> zB1J46z>qvAeQBWa@W(AGM|GT5EJ!QF7D!Fa5D3N4<;mxU^j%jbu*JJjc zx^w{>-WBCb(MEg)STJ3lqyES+!ONojRUEI`J zP;}RSf?|IP9VK0dr-kWOI0RsKzGGM8$Aqb^xenFvluBb}jVCW=S*%y>^l=ElXwy3H zfsA=7o9F4udbDf9zn<#oOnzfF+A?=F=y+frp#NoIpVDAN*YR$PTbQTR>WwpE3d@@! zfpCj1(Y)-iS!!N}_q{q&DpL#2Wycu5i_SCW3jq0qk~Z}dYjOU73F`x8%8bZ3E6%{_ zRQc{Y!hYI~TR@g)6KJx_V*Kp41aQufsINXof`VB^MX+Utg`gNHse_<=R5s4<{1NhIVN>@fH8-=&pHGxZ@gTw=nwnC@*m8X^tKl`VD+@QCCB?(ae?FP>oy=(^FMa z-2NJKbbaMs@5LeRyo@ETu~tLREOX2hDMT;HJBA)LW9l3?cYE=Pvlz5L+;CBlBSp{4 zc3`vMQg|@^KCGtMaV9)h3$B+a@cI7EZch160S5=tW;$QeGF_(q?89i&pCrG&xX7@> zvSVaTV}Ja{`PtB2rLtx%A8dP9-umHrX?)MZc~R*SB>8m5sV&y84$im>Ql~vXwNQ7v z-n36eWFjs!kn^A;Y$ec37WzyzgPMsctZc1TX7-D!J=rN-T>;Sq*UF+I76hM0q||VZ zjRf?`+jPFDtqU9{Udb+{lk&IYqjwD&Ixe+r7B6m;@S9R!?(oN|ouD=lub!z|+b8k# z8W`nfh5}WLyh$7iYL4@(;0B0ItF9Kgb>pxH=PDZ`&J>@33m$-Y#Hp&U`kRkmQzsQL zz;>|aL3cETElNw&kqMK>6Om0?TwF&df=hMzf_$mF^sP;FAEuVVk)|1oUDu>1f$?<* zgHhTJL$*g@$>7Je``vzgiQ<~UY!D5zFLvS6*i}kb0EeR+FzK=BFFK2toG4C(;5kpe zC1^@ovxQK{dYyni7FV$F+)6aOdux-NVXzk${uR`C_I?9*FtCRcS+~7|K;Av8`z6`8 z87nQ4*GX9m4D{3>25i_j#HPtvvF6u;tojOmT+AFgtv*9)nltGbB^Q`E-=eM%z!aSKO{B_Ccs1#^3_zZ6U z@eA&!?~}&eH6))Q=j%x<*KZy-;)Fy3_&D9ZTJ)LfUfjBVpp>R(HLsuR`u(^x*|AEZ-@}O~>Y` zO-!Mc`RVQs_kCHzvh|-CrpP|*yA+LdVnGJyegf|hv*M>tUCZ^se3IN^qoU!{l8bP< z>j+aiv-C4Y>>aYMFQqRB)i|s9Z`L~21yNo&ZtTsz4?*y)^}8Qm}#i+Np%~~HxP|{yof|{eakd~-d_tDza4Y!EUc>`Hg%yu z@(+Jd-EFa~E6AQ>l~#2_ZhfSffu54Cbm}wfS&g{5btcPA|2ixn?u|DbOqwCTCwiO! znGu>!l<-48Vm{(KZa2f$+6a67_$+Yi-In3+s7((sq(6aBe7l{zlpP%JYIRi(A564I z549u|Jo$Gn)<18zjog*=%}bJA>crMVHwr0`!*gc!VGs+)o1`1mHs+!#Pd{78;}39? z1ry!4^nK4&$&dusS*;g2wZtI!*qnp7An)%b@j2a}a;ju^nw2;`yE`5EM+e@y%BM`& zFZCfjY?I@lIHvQhFJWavZ5reDHL}vINBw8!jii6H^1dua4{MLO7-K zF=o4mDBu+Kdg*K!t~5nYi}hG{N$fqdSDOoH#to>ne7V1-C*U*JNpROc>Ng`95OmPG z*25oqW--4V#Yijvm2cAjaeBMhZITkIIpF1K0^`pDw)GW}QX*96%rjrdf!S7;zMzBSb^7 z9Cz_uxt8m~YL2_NGb9PX*PufigU#ht8Yd39Nw=1#CkM2|YuHcCB{k)Hwe9>VN>TCj z<-Xpi%tL9eBVsb(Q5UuQOL668U-n)XdCgvt?rGu!%n#(74>xjPR&@hpNpJOZuD4XT zsT!Mo4r8w%MIC2(+MRgeL^9r2x#3|b1|9wnyZX(U5Gq|3@-tNl+94Nf$;1gak1w4m zMP|(`TUnBek$rB10+Y53OD0HJd z9fqP3kAQ#l6BhTk9_VC(Rfh2*lAc@yo5O}im2@$Z@re6;1XPmUG-y+g zqxzkv?FgEU1Dq*v05@oS9tnbB8oFy6(@bh*%TR6+PL$ap*5Z=rw4*>MBSqgL+aOdO z=;8cXT>PO08QK&QkN;`ONAR|zNAVO*E&W~$kmxBIz&AYjB zsK9ro_DOBFyBVP_W-(s9xfxKz)XrfLP;i-&PQV${EB9_~BlzhH98Al8-ZqzoG}cSj*O8gG*nCp5Y?bdS)u00i zd6JM)sQi9lhhlD1Vd_W+SZ-VDmCGwB7V*LVxb2`g;Y-q@+nDE^fDrKb?oB!hw37DH z({X4P2^g4uyVv6nsF&rx3jZIc)GfJn1^9LGtD&1;!SK^sYd1+1gm@=W4m&1)D1Ef z`YS*4VnVBX%x5FI6I+GE9sUr*dbp3Hwh^>ya=qefJ*QzRASnuM5Jx5bScvS}AR_1X z66Z|FZJBs-T))6)y(bI(^{M`-T~u2{p;zSH>|>F95GV{H0gQcgHHLr_QS@-)cfmw! zAdu}4U+w)|pR#t71jy#K|NVBZ9c+;xfbvW0%t1;0K1j4{c~|b1vj>NDtqV;HeuzJp zkyBT1GJYGWHfMq7e?yQ|0KkSs)*&bJbME{nwBA4NhF2Td;!;3^ld-h*8cWEfkfS?E znBb#VijDPSCwVVj)21POsTLoIY^7q~sEy8MoJp`u+FJ-Mxx#L!ZqrBp3pI3Pf4q1F z4DradMqy2JU&QUlHgd2&Y#piZN~|eUPg9!T`GJ-2z@{yNAi^iDojvFM#x?bwmbsvX z%B}4GgdzJup#FakLk?@SK8`13i#5BsAU^c&Wk?GR3z#S{K6ZmX;)MBv?oRWrH z=;aayvmsJJTg1G;0yM^_BbA?O+IGh(jX~sq@U!nvUYM&vC_#T#Xhe66>t_yD z$Ml9%9iQI`v?bW?a3*ySTz9txT^maVPKP&N(W9F3>E(-+z}%@H#94D?4wY;>i$>Kk z%Q$rDzV&xBq%C+ZE|)b8HRv<#*|s4)B-xrF+}}L7`PhymjufleNX=!(K>G{BN|czp zieY5FHK5PF(C3`mtMF~pli^FZqMmyL8$0)(Y-v?PB9TU=n3=y%$p%7H;Clb@snJk4>2h(1X4q&%OChRvvM1u(vU9p3gBc2w%WNfI=aT%^u(k`PPjshbsX zMH@(}{xEj<5!iF^7rLS0NKz*`FFkt0vF>G%)%fYp&0WvN3bCVH=b)*O&nxd;v24;G z%%XIq9!zcbA1{8ahQ-{>AfSXzK7eTEyul~*+I?+LcXchHi;mJ}&nj&ve@53=0lg~m zF^v`ripZU>(nj9?-+eciM-LUOc;1`2abVFeeGh8Fma!^soS7TH1l5+q7iO>KxF?#9kpW6+zm z`|@=~x$c$fHGGc9*(*~|li&|YZryf2gg-%)t(n0KH22Mn=U5;WF)_*}_>7al@2Y1l zTJHY&_U*t@)K6m3coWIHKKo%(7?_M}<9f9w!E!IVNB@W-LCUO+NHriZ0kwLN*NwlV zrBlJl5eh-~nm>@Uz1W)|68U>uxyk;DwWVL)Mvj6lg?3C~h;=!&;Q>Rjxa4=8N2<~C zu1nDYcNBj`=d;e!9s**a4#lTHT~(D^Nv#RZa1f0O$*p3nt&#fA(#{gx^J#VEuT|sY z2w&0+0D6+{1HUeKe3ud#!w6(B<4_;+nZwrGNS5qkb5DOWgx5Ep!A-ENjNe%;cFWV({IgSeVGFDa6Edg8QdmPmdCaa|Eh-ErU zY#F0m&J^0wjG?ustL7M22Cx?cj*ugBo>VPyuPyy&^fBL@?pU{4ptdzNph z$BZ!GdTTK7M6z}G!&^AiclCh>RxZby8*Q`Wu=vpYy%{@u%6!E$Ij2OqC!YY(Zb^jK z{HqS2Fs9Z`HBNf%{>3V1N_uu2Ut3om#p-hTKY9<&HtqzLLiscKOLR<`Yb{tbMo20b zm+=_M<_0dbyOf>*Ms6hra#}&^PkY;nB>Bn?FD|ooE&d$?nyJQ=lT~sUl36`o$*Hnc zYf}FRI5{9o&7Il^l_{gM3J4^5mShn)_R;=5^93L_92KDg#L-?4Gpn?x_<(h`0s$WT zX3kXLY7v`fVX=MX5do@bX`M&>J{e7nfSlN6S`PMvq{s1qZ5Esyhx*BEzFtD$KGXTKB2{R*i@H<%w69Yy;;S`L zAe)qNU-Ff#&20JfNCL=V`7sD|xbr|m*HXYeGGi&_H^#>JOE{=MRULnu$P?*maxDX4 zb&@&rlQ6)&*IyjyHP&wKGhF1zlb*Muca4?=q1}O1Mzk?pNw=U^zBIP)%NrN!s6ev03HQN~V`#-aD)P!=dx^1Na)D zyx?fb>=MI@UX2{O+n&1PJu@Tms@kVrMypG-XO;cqQKNp13L(k^+xKM0nT}R61M?E~ zWKfY8M){*wx(Eix8yNi5)PzIJ#ej|rd6rtfZ)%V@W8pp*+4i3dMXw{|jP-z3AzwVD^hwJX1WEurS6f&OY* z;s;fMzhCb%c_11{4Mq<61?|0@5=nMQts|5ISxq2CO{Wi1EZP3|VSI-Q?DF$s|H}!*2&cB5wQmZlP z*;jYl7rR3Ky$c-5An8TfpMuuGx9?c{8SiE{?usY+7Uj>mYE@RQGA=0xH$86UM&5r} z^2sGj1qcF3vvFsileYBpsE%2=8Colz#4q=?xD>4D2N&vWI>!2@kyYP0KQgb+^g8$_ zLmQ{V+ibCaJ|(&bhK^>x9ok@gl)0eu{i5>7+{N1j#sV*^TT6O$e0iz?apXdK?Z9#J z&(qRX9`}6%Vv5O-XPPrH_f`F23V|;Bz{htx=BAJc$mdrMA)12P7oUYd& z-wPm7``S+&&zU^tT$3F;HP8QhHTQGzoi1WapxompUe_yJgg%C!N6^$GA8k`l7u2ws zZo|+v^gk~&e>?Bc5!*0O#hfX(@>RTvV$)9aO}~4pfl-fJXgbQNgTyl>v0he(BSa#g z$WdcH_QIbr#aX5B-TmpMuLb{EkFhpEIGA*vjQo&ZITB-fSkXk^)WT zcrjDv%46&8pBMYJ_blzB*W@y? zSTjV`-KblhRd4XhC-Bv*If~9J`D6|y6ciPp636~(4oGdh$9=BZ8>3LQmo%_Z3#wr~ z9pFWiKcrf@+UD}bU9fz1v!Y7Y1w?#^b=V0eQpKN`$*RpO2o6zpm09&_sHCMcvT(O= z_>$~t({*gDs1S-l%?IU%@Yj$`jd^waok0EFk;#P-mE+C^s5CLgK_;|rh}2}ZsxHj{ zfl@qvdyLjuJ*P&%KoF4_(pZJwIF7cgYm+}Xl@iimS8_&=lfCKdk7LbyOgCH#OFs3^ z)&d>EEg^=g<9ujoLJm7Y$7GDD{7jEk6x5%ia63N@cTd<`#vM&-Vwm88spj08R9v!e z^Q$C`EuZKkE6|vcQ|WdFnOe0UZl`&Jp6`rCr4Uau10K9ncv>6xeRxI+=N*^%nwG~_ z<)}xoD_t3P#kVrA{w3HpJ&c4ZSLkAaYO<<T#*pBR@FzA;tFY_&6RZ5wqqF2!y{VFE1KtOMWYg=s%xBTZQx%zV#;Q_7r#1H0Pk9 z{|qckW+vAtZ^6jt zq6DzUtAF@yT!xHaCNI(%SvGCVVfA7tErIhbH2c)J>f(hd;*B4 zN$8*rf3@2r6VH0~>H+rWhDI{orASbxQUo!_^c^^|Oi?f`4L!`rxY-i!eCe8GnNEr< zrU7m?Oewf{Ms~OoC(8BrN7qaalTBI?AovZ_%+(cYC_a0A2Yb>qm$9eAIB#z zOq{@VMzkR02G+CW7J%nmg5!(BKD)geArru}i%TelJ)>dk{xm``4qC`=>y5iR>=_3ikYv1o5UFm!sB!V%7q}2z&_bK(~MWD6{lGbCx?jF()LwVe0`Xk<8;1l zeT<~5+xA1TOxzM;*!~c%jWu)2OMgrvsiX)1uskZ^W?T~b$EC`w1Eq!VzL(?88k^U&4Y3yGd1y_)^5k7FfGT?JzQ~yP_^J<}fXq(5;1_fB(+Z`#09#f1DCvEHRV#-H3=TXbt@>6dL^n3JlwY>M7_IlE5!2yeO%& zFPcopQCK!-7JN1XSqK$rdos`~Pv_Ts3elv#4+}Wl{*W*cR)(HySB_ifY@*32O=cw$ z2hM)w0E^JsITm{jq_`+5F=aspcdA2}imTEyaJH7t!%LsB1zt6qv|40w;7@5>J8bMx z#NX@XrO`Vh-6Mtzp)v+4#?U48jWjNIunKT%TK&V@SpQ9`DOvo{0VH1o2uP2tRZl6Z z1sdO^J;ulW$&Q^BxWrqA}GDkjLNZ zLo9c-sl1Lq#sYZQT#Vyg3971X*@S3~{-q^MoKI;1D&2dVIatf2TZC<+R!V63n@o?J zH+zUAV^`kywqX%&b>Okdm*_Qbd=J{xT7e?r=pg|OW2vXs!LqZ~(|#nf2ZL@nvgb_7 zn6CIKa#6k^P=ZvF_#M(EB!_rN?a^KDq~rtS)}XUEY#WgadV>Zhx0%W9{E%^6=rhci zHGz5>OpKG{Q(Lc9F0PuPdLJDr;q#&tus25X99_g>d6w+*1Jq0?Nqe@hRK!?uUR#?W zb*#de&1I9DiRwuwrJGIs#Y-gv5y)~phmyu}k5+Y;nLZr_cC+kC-y#;ytd)H3{=cuF zG!;ghp47&y7HPMB9~__Jr4puM=MM5)6`}U|nA&t7;U!*o^O_E&b)w#KOw%4hn+y#}17|*@*^^bJ2jA`%(-L&2B3OtPLIh zWsuE)%Zd~bR*Q{=9;IxnFm@L|(srRJs%wzhqr5}?ZM1>Q%hEW#%o#TK>#P_CFU1;O zgHmtoi?UUdJ!Y$|3Q|P3_DGf;!XU&a-b(-A(AFH3j21s;r%zz zuqx?aprPUutGazp5S-(-$STS0Rdjty%R&6J3ytnSG)VR9eZ>MLmP%o?XB6zJxPzm& z74*Mbp@0%h4Skn)fBZy8OI$?yZj)2`1p|0x#evK*i!&Xx_wD&gwdT%MIYT1zV=}vm z%a^tG8$C?YXT#-CCjnfZ=O$Vp^1hU8irJ5^z&lkVqJ)~Gq10BR09g{-q`Mx3xQ_Cn zYM-mH5YrY<{&N0i^^MCsAh7ow(I9d-j;!m-tM|XX_+3lzk}I7Ds!Qp!^d#}PxLdjD z4SXwR84=W=9vLyHzO>e;Hrqio z^1b==)y&j&^{({8{Gsj=n+0w<;mq&j<~t$ld6Nyy=;I zQ51e~Yj9ja|I7BrgcY~%XF2)~o#HKX^coJ%B8|0V=>EARd=>>4ZDhLHP|77aL0`Yy z9O72pkwCp_>{lvBq!PkhEX=5u^<+{xf^i)O@5f=rBku2;M3;G4x!>6>3Xqc(y=@PYp5UdVY*SZ-FYw zFFr=US$>-`64IMmiM3EQ438p|&~J?2Oo)h#T!U7J%23s6tGo(o%>rWBHs4>)^wvYbcuKatG4#Up&?%k({-zzw4I=aabLzC2`T7ciQk7qiFt5nngq!5+uNGMZy(NW37 zAsMd&vyi%PABz8f;t&78Uc79}upT+T?OYV?L~<`S7L7DLFwt35qMNVhwwmT6|K(6p zcY0leg#(HcMM@6&%~Z_*_V>0Tf(wvCPK&P*dCn&MAyjw&&!(^J+|A?Hou6}Of?ez@ z)?JhB(oZ*e?q42Jll;5?#pSJe3vPr>*_?m3X@37o$)wwSbMNksoNy*sB}v<;@Bglf zqwkcs1q+|t%6Y|~-P!W$uDq|!m7;%79*8FIvq)4Bsw$ThxW75ocBgdqm8ofOV?Nz% zGkNB<7P+pyc<;km&*t4GTm_FMw=Ng+n>jt?A+|w=b6pGiSz*8~+~TnV+NW9Wh<+6ECOnoIgp& zjyZ|{S93njCx7YZm*>%@z!K5#{Jc-OnpzG;I z?q6;d+!93vS64kx`SVZwd(qq{Ka=$>g-tS?N$C+bZbfl%? zb<6o}Vjj*)HK)w{XKg(GZrz)2@3u@V6o0(`UVh;seb8QpyVX9|O(f3rvB&kMModeM zlomXnw&|worw#|r^mQi!rwTqbeRJjN{txS2>(y3vd2(B)j~wyHE4px>GD&rrzC@G-XBS5*Gw**p$aDkt1#w486HVa$# z09rfNU0wTQThZQFg_6_@g222AY`N{oPFdHKmiQ<*-d*_OneBhl_C0lXS-!6?PfTr} zvs2PZFQch2rEzNnJxG3VF2AC>HPtyOv|?%js$D7bVg{41lE>T>N1 z;r=Vk7OB5j;{pt=ANpw)N?!UYzt8OTaq%vjqH{CQ$))yLoS*(4=NXS~Z*i^KUL`x5 z<Dx115936t*+kj?8Cldn|JfFP8a;zdwi2>ZoK>@ofFQ_?(ZyI5a8jG^0iCWpfYBC z!O5+rmXlbn_j7y__}IJZNz&{CS3{F+|Ng_R!9?|1m7|`hm>#H7x4fmT z95mJcHG8+I>b2-Ji}YXe`{g=c+P`|e&L;WSvYFjpR=rivC3nv5J{vJ*SM||vKKst@ zth*+(T`<4z*B9P$qnCW^Www7g(H42%)BTI2_3PY?YcKP+aA+02ittZjcsc_XHS2tseEl` zPT8Xi4-13$NorhJJ$c*N$c?_eiE9}cfUJE#pGBMg`Q}*A ztZ?#2=+E2dXJkb)TQ0Fv6sn%tS=#mF;rl)2H?#l$o}a&V&Z>w9uTGhC%{E?j?xAP! zbSt7F~I~UpKmT%MnKx zzhmoBb9dvfx3nVg6BMh)OT_+{Geq9*ayTxBjqS7DX=hUqwc0w3Lq}&P!it%@8`*acEd4n{Q7@OTx~{z5W@lBeE9=l zv+e`1omT-IE#YTpXlQ2!3xl{ez^ow0hoTC|g{k^b05pvlWpGt6vtd@E7=~39)CCAD k38{h^jpiGWFvzUc3_oVx-}Wx2$qp0{p00i_>zopr01oKCxc~qF literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/generate-clients/image05.png b/docs/en/docs/img/tutorial/generate-clients/image05.png new file mode 100644 index 0000000000000000000000000000000000000000..e1e53179dcc2b244f2fbe62dced312a3c1ae5160 GIT binary patch literal 31091 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/generate-clients/image06.png b/docs/en/docs/img/tutorial/generate-clients/image06.png new file mode 100644 index 0000000000000000000000000000000000000000..0e9a100ea4e8bac7a85e54915286a602e0d9c5e2 GIT binary patch literal 43434 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 O6l7KJ None: self._debug: bool = debug + self.title = title + self.description = description + self.version = version + self.terms_of_service = terms_of_service + self.contact = contact + self.license_info = license_info + self.openapi_url = openapi_url + self.openapi_tags = openapi_tags + self.root_path_in_servers = root_path_in_servers + self.docs_url = docs_url + self.redoc_url = redoc_url + self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url + self.swagger_ui_init_oauth = swagger_ui_init_oauth + self.swagger_ui_parameters = swagger_ui_parameters + self.servers = servers or [] + self.extra = extra + self.openapi_version = "3.0.2" + self.openapi_schema: Optional[Dict[str, Any]] = None + if self.openapi_url: + assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'" + assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'" + # TODO: remove when discarding the openapi_prefix parameter + if openapi_prefix: + logger.warning( + '"openapi_prefix" has been deprecated in favor of "root_path", which ' + "follows more closely the ASGI standard, is simpler, and more " + "automatic. Check the docs at " + "https://fastapi.tiangolo.com/advanced/sub-applications/" + ) + self.root_path = root_path or openapi_prefix self.state: State = State() + self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {} self.router: routing.APIRouter = routing.APIRouter( routes=routes, dependency_overrides_provider=self, @@ -83,6 +118,7 @@ class FastAPI(Starlette): deprecated=deprecated, include_in_schema=include_in_schema, responses=responses, + generate_unique_id_function=generate_unique_id_function, ) self.exception_handlers: Dict[ Union[int, Type[Exception]], @@ -99,40 +135,6 @@ class FastAPI(Starlette): [] if middleware is None else list(middleware) ) self.middleware_stack: ASGIApp = self.build_middleware_stack() - - self.title = title - self.description = description - self.version = version - self.terms_of_service = terms_of_service - self.contact = contact - self.license_info = license_info - self.servers = servers or [] - self.openapi_url = openapi_url - self.openapi_tags = openapi_tags - # TODO: remove when discarding the openapi_prefix parameter - if openapi_prefix: - logger.warning( - '"openapi_prefix" has been deprecated in favor of "root_path", which ' - "follows more closely the ASGI standard, is simpler, and more " - "automatic. Check the docs at " - "https://fastapi.tiangolo.com/advanced/sub-applications/" - ) - self.root_path = root_path or openapi_prefix - self.root_path_in_servers = root_path_in_servers - self.docs_url = docs_url - self.redoc_url = redoc_url - self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url - self.swagger_ui_init_oauth = swagger_ui_init_oauth - self.swagger_ui_parameters = swagger_ui_parameters - self.extra = extra - self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {} - - self.openapi_version = "3.0.2" - - if self.openapi_url: - assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'" - assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'" - self.openapi_schema: Optional[Dict[str, Any]] = None self.setup() def build_middleware_stack(self) -> ASGIApp: @@ -286,6 +288,9 @@ class FastAPI(Starlette): ), name: Optional[str] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> None: self.router.add_api_route( path, @@ -311,6 +316,7 @@ class FastAPI(Starlette): response_class=response_class, name=name, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def api_route( @@ -338,6 +344,9 @@ class FastAPI(Starlette): response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: self.router.add_api_route( @@ -364,6 +373,7 @@ class FastAPI(Starlette): response_class=response_class, name=name, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) return func @@ -395,6 +405,9 @@ class FastAPI(Starlette): include_in_schema: bool = True, default_response_class: Type[Response] = Default(JSONResponse), callbacks: Optional[List[BaseRoute]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> None: self.router.include_router( router, @@ -406,6 +419,7 @@ class FastAPI(Starlette): include_in_schema=include_in_schema, default_response_class=default_response_class, callbacks=callbacks, + generate_unique_id_function=generate_unique_id_function, ) def get( @@ -433,6 +447,9 @@ class FastAPI(Starlette): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.get( path, @@ -457,6 +474,7 @@ class FastAPI(Starlette): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def put( @@ -484,6 +502,9 @@ class FastAPI(Starlette): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.put( path, @@ -508,6 +529,7 @@ class FastAPI(Starlette): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def post( @@ -535,6 +557,9 @@ class FastAPI(Starlette): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.post( path, @@ -559,6 +584,7 @@ class FastAPI(Starlette): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def delete( @@ -586,6 +612,9 @@ class FastAPI(Starlette): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.delete( path, @@ -610,6 +639,7 @@ class FastAPI(Starlette): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def options( @@ -637,6 +667,9 @@ class FastAPI(Starlette): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.options( path, @@ -661,6 +694,7 @@ class FastAPI(Starlette): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def head( @@ -688,6 +722,9 @@ class FastAPI(Starlette): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.head( path, @@ -712,6 +749,7 @@ class FastAPI(Starlette): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def patch( @@ -739,6 +777,9 @@ class FastAPI(Starlette): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.patch( path, @@ -763,6 +804,7 @@ class FastAPI(Starlette): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def trace( @@ -790,6 +832,9 @@ class FastAPI(Starlette): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.router.trace( path, @@ -814,4 +859,5 @@ class FastAPI(Starlette): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index aff76b15e..58a748d04 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -1,5 +1,6 @@ import http.client import inspect +import warnings from enum import Enum from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast @@ -140,7 +141,15 @@ def get_openapi_operation_request_body( return request_body_oai -def generate_operation_id(*, route: routing.APIRoute, method: str) -> str: +def generate_operation_id( + *, route: routing.APIRoute, method: str +) -> str: # pragma: nocover + warnings.warn( + "fastapi.openapi.utils.generate_operation_id() was deprecated, " + "it is not used internally, and will be removed soon", + DeprecationWarning, + stacklevel=2, + ) if route.operation_id: return route.operation_id path: str = route.path_format @@ -154,7 +163,7 @@ def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str: def get_openapi_operation_metadata( - *, route: routing.APIRoute, method: str + *, route: routing.APIRoute, method: str, operation_ids: Set[str] ) -> Dict[str, Any]: operation: Dict[str, Any] = {} if route.tags: @@ -162,14 +171,25 @@ def get_openapi_operation_metadata( operation["summary"] = generate_operation_summary(route=route, method=method) if route.description: operation["description"] = route.description - operation["operationId"] = generate_operation_id(route=route, method=method) + operation_id = route.operation_id or route.unique_id + if operation_id in operation_ids: + message = ( + f"Duplicate Operation ID {operation_id} for function " + + f"{route.endpoint.__name__}" + ) + file_name = getattr(route.endpoint, "__globals__", {}).get("__file__") + if file_name: + message += f" at {file_name}" + warnings.warn(message) + operation_ids.add(operation_id) + operation["operationId"] = operation_id if route.deprecated: operation["deprecated"] = route.deprecated return operation def get_openapi_path( - *, route: routing.APIRoute, model_name_map: Dict[type, str] + *, route: routing.APIRoute, model_name_map: Dict[type, str], operation_ids: Set[str] ) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]: path = {} security_schemes: Dict[str, Any] = {} @@ -183,7 +203,9 @@ def get_openapi_path( route_response_media_type: Optional[str] = current_response_class.media_type if route.include_in_schema: for method in route.methods: - operation = get_openapi_operation_metadata(route=route, method=method) + operation = get_openapi_operation_metadata( + route=route, method=method, operation_ids=operation_ids + ) parameters: List[Dict[str, Any]] = [] flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True) security_definitions, operation_security = get_openapi_security_definitions( @@ -217,7 +239,9 @@ def get_openapi_path( cb_security_schemes, cb_definitions, ) = get_openapi_path( - route=callback, model_name_map=model_name_map + route=callback, + model_name_map=model_name_map, + operation_ids=operation_ids, ) callbacks[callback.name] = {callback.path: cb_path} operation["callbacks"] = callbacks @@ -384,6 +408,7 @@ def get_openapi( output["servers"] = servers components: Dict[str, Dict[str, Any]] = {} paths: Dict[str, Dict[str, Any]] = {} + operation_ids: Set[str] = set() flat_models = get_flat_models_from_routes(routes) model_name_map = get_model_name_map(flat_models) definitions = get_model_definitions( @@ -391,7 +416,9 @@ def get_openapi( ) for route in routes: if isinstance(route, routing.APIRoute): - result = get_openapi_path(route=route, model_name_map=model_name_map) + result = get_openapi_path( + route=route, model_name_map=model_name_map, operation_ids=operation_ids + ) if result: path, security_schemes, path_definitions = result if path: diff --git a/fastapi/routing.py b/fastapi/routing.py index 7dae04521..0f416ac42 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -34,7 +34,7 @@ from fastapi.types import DecoratedCallable from fastapi.utils import ( create_cloned_field, create_response_field, - generate_operation_id_for_path, + generate_unique_id, get_value_or_default, ) from pydantic import BaseModel @@ -335,21 +335,47 @@ class APIRoute(routing.Route): dependency_overrides_provider: Optional[Any] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Union[ + Callable[["APIRoute"], str], DefaultPlaceholder + ] = Default(generate_unique_id), ) -> None: - # normalise enums e.g. http.HTTPStatus - if isinstance(status_code, IntEnum): - status_code = int(status_code) self.path = path self.endpoint = endpoint + self.response_model = response_model + self.summary = summary + self.response_description = response_description + self.deprecated = deprecated + self.operation_id = operation_id + self.response_model_include = response_model_include + self.response_model_exclude = response_model_exclude + self.response_model_by_alias = response_model_by_alias + self.response_model_exclude_unset = response_model_exclude_unset + self.response_model_exclude_defaults = response_model_exclude_defaults + self.response_model_exclude_none = response_model_exclude_none + self.include_in_schema = include_in_schema + self.response_class = response_class + self.dependency_overrides_provider = dependency_overrides_provider + self.callbacks = callbacks + self.openapi_extra = openapi_extra + self.generate_unique_id_function = generate_unique_id_function + self.tags = tags or [] + self.responses = responses or {} self.name = get_name(endpoint) if name is None else name self.path_regex, self.path_format, self.param_convertors = compile_path(path) if methods is None: methods = ["GET"] self.methods: Set[str] = set([method.upper() for method in methods]) - self.unique_id = generate_operation_id_for_path( - name=self.name, path=self.path_format, method=list(methods)[0] - ) - self.response_model = response_model + if isinstance(generate_unique_id_function, DefaultPlaceholder): + current_generate_unique_id: Callable[ + ["APIRoute"], str + ] = generate_unique_id_function.value + else: + current_generate_unique_id = generate_unique_id_function + self.unique_id = self.operation_id or current_generate_unique_id(self) + # normalize enums e.g. http.HTTPStatus + if isinstance(status_code, IntEnum): + status_code = int(status_code) + self.status_code = status_code if self.response_model: assert ( status_code not in STATUS_CODES_WITH_NO_BODY @@ -371,19 +397,14 @@ class APIRoute(routing.Route): else: self.response_field = None # type: ignore self.secure_cloned_response_field = None - self.status_code = status_code - self.tags = tags or [] if dependencies: self.dependencies = list(dependencies) else: self.dependencies = [] - self.summary = summary self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "") # if a "form feed" character (page break) is found in the description text, # truncate description text to the content preceding the first "form feed" self.description = self.description.split("\f")[0] - self.response_description = response_description - self.responses = responses or {} response_fields = {} for additional_status_code, response in self.responses.items(): assert isinstance(response, dict), "An additional response must be a dict" @@ -399,16 +420,6 @@ class APIRoute(routing.Route): self.response_fields: Dict[Union[int, str], ModelField] = response_fields else: self.response_fields = {} - self.deprecated = deprecated - self.operation_id = operation_id - self.response_model_include = response_model_include - self.response_model_exclude = response_model_exclude - self.response_model_by_alias = response_model_by_alias - self.response_model_exclude_unset = response_model_exclude_unset - self.response_model_exclude_defaults = response_model_exclude_defaults - self.response_model_exclude_none = response_model_exclude_none - self.include_in_schema = include_in_schema - self.response_class = response_class assert callable(endpoint), "An endpoint must be a callable" self.dependant = get_dependant(path=self.path_format, call=self.endpoint) @@ -418,10 +429,7 @@ class APIRoute(routing.Route): get_parameterless_sub_dependant(depends=depends, path=self.path_format), ) self.body_field = get_body_field(dependant=self.dependant, name=self.unique_id) - self.dependency_overrides_provider = dependency_overrides_provider - self.callbacks = callbacks self.app = request_response(self.get_route_handler()) - self.openapi_extra = openapi_extra def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]: return get_request_handler( @@ -465,6 +473,9 @@ class APIRouter(routing.Router): on_shutdown: Optional[Sequence[Callable[[], Any]]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> None: super().__init__( routes=routes, # type: ignore # in Starlette @@ -488,6 +499,7 @@ class APIRouter(routing.Router): self.dependency_overrides_provider = dependency_overrides_provider self.route_class = route_class self.default_response_class = default_response_class + self.generate_unique_id_function = generate_unique_id_function def add_api_route( self, @@ -519,6 +531,9 @@ class APIRouter(routing.Router): route_class_override: Optional[Type[APIRoute]] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Union[ + Callable[[APIRoute], str], DefaultPlaceholder + ] = Default(generate_unique_id), ) -> None: route_class = route_class_override or self.route_class responses = responses or {} @@ -535,6 +550,9 @@ class APIRouter(routing.Router): current_callbacks = self.callbacks.copy() if callbacks: current_callbacks.extend(callbacks) + current_generate_unique_id = get_value_or_default( + generate_unique_id_function, self.generate_unique_id_function + ) route = route_class( self.prefix + path, endpoint=endpoint, @@ -561,6 +579,7 @@ class APIRouter(routing.Router): dependency_overrides_provider=self.dependency_overrides_provider, callbacks=current_callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=current_generate_unique_id, ) self.routes.append(route) @@ -590,6 +609,9 @@ class APIRouter(routing.Router): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_api_route( @@ -617,6 +639,7 @@ class APIRouter(routing.Router): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) return func @@ -654,6 +677,9 @@ class APIRouter(routing.Router): callbacks: Optional[List[BaseRoute]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> None: if prefix: assert prefix.startswith("/"), "A path prefix must start with '/'" @@ -694,6 +720,12 @@ class APIRouter(routing.Router): current_callbacks.extend(callbacks) if route.callbacks: current_callbacks.extend(route.callbacks) + current_generate_unique_id = get_value_or_default( + route.generate_unique_id_function, + router.generate_unique_id_function, + generate_unique_id_function, + self.generate_unique_id_function, + ) self.add_api_route( prefix + route.path, route.endpoint, @@ -722,6 +754,7 @@ class APIRouter(routing.Router): route_class_override=type(route), callbacks=current_callbacks, openapi_extra=route.openapi_extra, + generate_unique_id_function=current_generate_unique_id, ) elif isinstance(route, routing.Route): methods = list(route.methods or []) # type: ignore # in Starlette @@ -770,6 +803,9 @@ class APIRouter(routing.Router): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -795,6 +831,7 @@ class APIRouter(routing.Router): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def put( @@ -822,6 +859,9 @@ class APIRouter(routing.Router): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -847,6 +887,7 @@ class APIRouter(routing.Router): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def post( @@ -874,6 +915,9 @@ class APIRouter(routing.Router): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -899,6 +943,7 @@ class APIRouter(routing.Router): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def delete( @@ -926,6 +971,9 @@ class APIRouter(routing.Router): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -951,6 +999,7 @@ class APIRouter(routing.Router): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def options( @@ -978,6 +1027,9 @@ class APIRouter(routing.Router): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -1003,6 +1055,7 @@ class APIRouter(routing.Router): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def head( @@ -1030,6 +1083,9 @@ class APIRouter(routing.Router): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -1055,6 +1111,7 @@ class APIRouter(routing.Router): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def patch( @@ -1082,6 +1139,9 @@ class APIRouter(routing.Router): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( path=path, @@ -1107,6 +1167,7 @@ class APIRouter(routing.Router): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) def trace( @@ -1134,6 +1195,9 @@ class APIRouter(routing.Router): name: Optional[str] = None, callbacks: Optional[List[BaseRoute]] = None, openapi_extra: Optional[Dict[str, Any]] = None, + generate_unique_id_function: Callable[[APIRoute], str] = Default( + generate_unique_id + ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: return self.api_route( @@ -1160,4 +1224,5 @@ class APIRouter(routing.Router): name=name, callbacks=callbacks, openapi_extra=openapi_extra, + generate_unique_id_function=generate_unique_id_function, ) diff --git a/fastapi/utils.py b/fastapi/utils.py index 8913d85b2..b9301499a 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -1,8 +1,9 @@ import functools import re +import warnings from dataclasses import is_dataclass from enum import Enum -from typing import Any, Dict, Optional, Set, Type, Union, cast +from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Type, Union, cast import fastapi from fastapi.datastructures import DefaultPlaceholder, DefaultType @@ -13,6 +14,9 @@ from pydantic.fields import FieldInfo, ModelField, UndefinedType from pydantic.schema import model_process_schema from pydantic.utils import lenient_issubclass +if TYPE_CHECKING: # pragma: nocover + from .routing import APIRoute + def get_model_definitions( *, @@ -119,13 +123,29 @@ def create_cloned_field( return new_field -def generate_operation_id_for_path(*, name: str, path: str, method: str) -> str: +def generate_operation_id_for_path( + *, name: str, path: str, method: str +) -> str: # pragma: nocover + warnings.warn( + "fastapi.utils.generate_operation_id_for_path() was deprecated, " + "it is not used internally, and will be removed soon", + DeprecationWarning, + stacklevel=2, + ) operation_id = name + path operation_id = re.sub("[^0-9a-zA-Z_]", "_", operation_id) operation_id = operation_id + "_" + method.lower() return operation_id +def generate_unique_id(route: "APIRoute") -> str: + operation_id = route.name + route.path_format + operation_id = re.sub("[^0-9a-zA-Z_]", "_", operation_id) + assert route.methods + operation_id = operation_id + "_" + list(route.methods)[0].lower() + return operation_id + + def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) -> None: for key in update_dict: if ( diff --git a/tests/test_generate_unique_id_function.py b/tests/test_generate_unique_id_function.py new file mode 100644 index 000000000..ffc0e3844 --- /dev/null +++ b/tests/test_generate_unique_id_function.py @@ -0,0 +1,1617 @@ +import warnings +from typing import List + +from fastapi import APIRouter, FastAPI +from fastapi.routing import APIRoute +from fastapi.testclient import TestClient +from pydantic import BaseModel + + +def custom_generate_unique_id(route: APIRoute): + return f"foo_{route.name}" + + +def custom_generate_unique_id2(route: APIRoute): + return f"bar_{route.name}" + + +def custom_generate_unique_id3(route: APIRoute): + return f"baz_{route.name}" + + +class Item(BaseModel): + name: str + price: float + + +class Message(BaseModel): + title: str + description: str + + +def test_top_level_generate_unique_id(): + app = FastAPI(generate_unique_id_function=custom_generate_unique_id) + router = APIRouter() + + @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + def post_root(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + @router.post( + "/router", response_model=List[Item], responses={404: {"model": List[Message]}} + ) + def post_router(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + app.include_router(router) + client = TestClient(app) + response = client.get("/openapi.json") + data = response.json() + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "post": { + "summary": "Post Root", + "operationId": "foo_post_root", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_foo_post_root" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Foo Post Root", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Foo Post Root", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/router": { + "post": { + "summary": "Post Router", + "operationId": "foo_post_router", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_foo_post_router" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Foo Post Router", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Foo Post Router", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_foo_post_root": { + "title": "Body_foo_post_root", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "Body_foo_post_router": { + "title": "Body_foo_post_router", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + }, + }, + "Message": { + "title": "Message", + "required": ["title", "description"], + "type": "object", + "properties": { + "title": {"title": "Title", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } + + +def test_router_overrides_generate_unique_id(): + app = FastAPI(generate_unique_id_function=custom_generate_unique_id) + router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) + + @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + def post_root(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + @router.post( + "/router", response_model=List[Item], responses={404: {"model": List[Message]}} + ) + def post_router(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + app.include_router(router) + client = TestClient(app) + response = client.get("/openapi.json") + data = response.json() + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "post": { + "summary": "Post Root", + "operationId": "foo_post_root", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_foo_post_root" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Foo Post Root", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Foo Post Root", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/router": { + "post": { + "summary": "Post Router", + "operationId": "bar_post_router", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_bar_post_router" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Bar Post Router", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Bar Post Router", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_bar_post_router": { + "title": "Body_bar_post_router", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "Body_foo_post_root": { + "title": "Body_foo_post_root", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + }, + }, + "Message": { + "title": "Message", + "required": ["title", "description"], + "type": "object", + "properties": { + "title": {"title": "Title", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } + + +def test_router_include_overrides_generate_unique_id(): + app = FastAPI(generate_unique_id_function=custom_generate_unique_id) + router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) + + @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + def post_root(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + @router.post( + "/router", response_model=List[Item], responses={404: {"model": List[Message]}} + ) + def post_router(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + app.include_router(router, generate_unique_id_function=custom_generate_unique_id3) + client = TestClient(app) + response = client.get("/openapi.json") + data = response.json() + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "post": { + "summary": "Post Root", + "operationId": "foo_post_root", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_foo_post_root" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Foo Post Root", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Foo Post Root", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/router": { + "post": { + "summary": "Post Router", + "operationId": "bar_post_router", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_bar_post_router" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Bar Post Router", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Bar Post Router", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_bar_post_router": { + "title": "Body_bar_post_router", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "Body_foo_post_root": { + "title": "Body_foo_post_root", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + }, + }, + "Message": { + "title": "Message", + "required": ["title", "description"], + "type": "object", + "properties": { + "title": {"title": "Title", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } + + +def test_subrouter_top_level_include_overrides_generate_unique_id(): + app = FastAPI(generate_unique_id_function=custom_generate_unique_id) + router = APIRouter() + sub_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) + + @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + def post_root(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + @router.post( + "/router", response_model=List[Item], responses={404: {"model": List[Message]}} + ) + def post_router(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + @sub_router.post( + "/subrouter", + response_model=List[Item], + responses={404: {"model": List[Message]}}, + ) + def post_subrouter(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + router.include_router(sub_router) + app.include_router(router, generate_unique_id_function=custom_generate_unique_id3) + client = TestClient(app) + response = client.get("/openapi.json") + data = response.json() + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "post": { + "summary": "Post Root", + "operationId": "foo_post_root", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_foo_post_root" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Foo Post Root", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Foo Post Root", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/router": { + "post": { + "summary": "Post Router", + "operationId": "baz_post_router", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_baz_post_router" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Baz Post Router", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Baz Post Router", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/subrouter": { + "post": { + "summary": "Post Subrouter", + "operationId": "bar_post_subrouter", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_bar_post_subrouter" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Bar Post Subrouter", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Bar Post Subrouter", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_bar_post_subrouter": { + "title": "Body_bar_post_subrouter", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "Body_baz_post_router": { + "title": "Body_baz_post_router", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "Body_foo_post_root": { + "title": "Body_foo_post_root", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + }, + }, + "Message": { + "title": "Message", + "required": ["title", "description"], + "type": "object", + "properties": { + "title": {"title": "Title", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } + + +def test_router_path_operation_overrides_generate_unique_id(): + app = FastAPI(generate_unique_id_function=custom_generate_unique_id) + router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) + + @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + def post_root(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + @router.post( + "/router", + response_model=List[Item], + responses={404: {"model": List[Message]}}, + generate_unique_id_function=custom_generate_unique_id3, + ) + def post_router(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + app.include_router(router) + client = TestClient(app) + response = client.get("/openapi.json") + data = response.json() + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "post": { + "summary": "Post Root", + "operationId": "foo_post_root", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_foo_post_root" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Foo Post Root", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Foo Post Root", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/router": { + "post": { + "summary": "Post Router", + "operationId": "baz_post_router", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_baz_post_router" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Baz Post Router", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Baz Post Router", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_baz_post_router": { + "title": "Body_baz_post_router", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "Body_foo_post_root": { + "title": "Body_foo_post_root", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + }, + }, + "Message": { + "title": "Message", + "required": ["title", "description"], + "type": "object", + "properties": { + "title": {"title": "Title", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } + + +def test_app_path_operation_overrides_generate_unique_id(): + app = FastAPI(generate_unique_id_function=custom_generate_unique_id) + router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) + + @app.post( + "/", + response_model=List[Item], + responses={404: {"model": List[Message]}}, + generate_unique_id_function=custom_generate_unique_id3, + ) + def post_root(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + @router.post( + "/router", + response_model=List[Item], + responses={404: {"model": List[Message]}}, + ) + def post_router(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + app.include_router(router) + client = TestClient(app) + response = client.get("/openapi.json") + data = response.json() + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "post": { + "summary": "Post Root", + "operationId": "baz_post_root", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_baz_post_root" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Baz Post Root", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Baz Post Root", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/router": { + "post": { + "summary": "Post Router", + "operationId": "bar_post_router", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_bar_post_router" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Bar Post Router", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Bar Post Router", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_bar_post_router": { + "title": "Body_bar_post_router", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "Body_baz_post_root": { + "title": "Body_baz_post_root", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + }, + }, + "Message": { + "title": "Message", + "required": ["title", "description"], + "type": "object", + "properties": { + "title": {"title": "Title", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } + + +def test_callback_override_generate_unique_id(): + app = FastAPI(generate_unique_id_function=custom_generate_unique_id) + callback_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) + + @callback_router.post( + "/post-callback", + response_model=List[Item], + responses={404: {"model": List[Message]}}, + generate_unique_id_function=custom_generate_unique_id3, + ) + def post_callback(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + @app.post( + "/", + response_model=List[Item], + responses={404: {"model": List[Message]}}, + generate_unique_id_function=custom_generate_unique_id3, + callbacks=callback_router.routes, + ) + def post_root(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + @app.post( + "/tocallback", + response_model=List[Item], + responses={404: {"model": List[Message]}}, + ) + def post_with_callback(item1: Item, item2: Item): + return item1, item2 # pragma: nocover + + client = TestClient(app) + response = client.get("/openapi.json") + data = response.json() + assert data == { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "post": { + "summary": "Post Root", + "operationId": "baz_post_root", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_baz_post_root" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Baz Post Root", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Baz Post Root", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "callbacks": { + "post_callback": { + "/post-callback": { + "post": { + "summary": "Post Callback", + "operationId": "baz_post_callback", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_baz_post_callback" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Baz Post Callback", + "type": "array", + "items": { + "$ref": "#/components/schemas/Item" + }, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Baz Post Callback", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + } + }, + } + }, + "/tocallback": { + "post": { + "summary": "Post With Callback", + "operationId": "foo_post_with_callback", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Body_foo_post_with_callback" + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Foo Post With Callback", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "title": "Response 404 Foo Post With Callback", + "type": "array", + "items": { + "$ref": "#/components/schemas/Message" + }, + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "Body_baz_post_callback": { + "title": "Body_baz_post_callback", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "Body_baz_post_root": { + "title": "Body_baz_post_root", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "Body_foo_post_with_callback": { + "title": "Body_foo_post_with_callback", + "required": ["item1", "item2"], + "type": "object", + "properties": { + "item1": {"$ref": "#/components/schemas/Item"}, + "item2": {"$ref": "#/components/schemas/Item"}, + }, + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + }, + }, + "Message": { + "title": "Message", + "required": ["title", "description"], + "type": "object", + "properties": { + "title": {"title": "Title", "type": "string"}, + "description": {"title": "Description", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } + + +def test_warn_duplicate_operation_id(): + def broken_operation_id(route: APIRoute): + return "foo" + + app = FastAPI(generate_unique_id_function=broken_operation_id) + + @app.post("/") + def post_root(item1: Item): + return item1 # pragma: nocover + + @app.post("/second") + def post_second(item1: Item): + return item1 # pragma: nocover + + @app.post("/third") + def post_third(item1: Item): + return item1 # pragma: nocover + + client = TestClient(app) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + client.get("/openapi.json") + assert len(w) == 2 + assert issubclass(w[-1].category, UserWarning) + assert "Duplicate Operation ID" in str(w[-1].message) diff --git a/tests/test_include_router_defaults_overrides.py b/tests/test_include_router_defaults_overrides.py index c46cb6701..5dd7e7098 100644 --- a/tests/test_include_router_defaults_overrides.py +++ b/tests/test_include_router_defaults_overrides.py @@ -1,3 +1,5 @@ +import warnings + import pytest from fastapi import APIRouter, Depends, FastAPI, Response from fastapi.responses import JSONResponse @@ -343,7 +345,11 @@ client = TestClient(app) def test_openapi(): client = TestClient(app) - response = client.get("/openapi.json") + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + response = client.get("/openapi.json") + assert issubclass(w[-1].category, UserWarning) + assert "Duplicate Operation ID" in str(w[-1].message) assert response.json() == openapi_schema diff --git a/tests/test_tutorial/test_generate_clients/__init__.py b/tests/test_tutorial/test_generate_clients/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial003.py b/tests/test_tutorial/test_generate_clients/test_tutorial003.py new file mode 100644 index 000000000..d79123163 --- /dev/null +++ b/tests/test_tutorial/test_generate_clients/test_tutorial003.py @@ -0,0 +1,188 @@ +from fastapi.testclient import TestClient + +from docs_src.generate_clients.tutorial003 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "tags": ["items"], + "summary": "Get Items", + "operationId": "items-get_items", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "title": "Response Items-Get Items", + "type": "array", + "items": {"$ref": "#/components/schemas/Item"}, + } + } + }, + } + }, + }, + "post": { + "tags": ["items"], + "summary": "Create Item", + "operationId": "items-create_item", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResponseMessage" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/users/": { + "post": { + "tags": ["users"], + "summary": "Create User", + "operationId": "users-create_user", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/User"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResponseMessage" + } + } + }, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "price": {"title": "Price", "type": "number"}, + }, + }, + "ResponseMessage": { + "title": "ResponseMessage", + "required": ["message"], + "type": "object", + "properties": {"message": {"title": "Message", "type": "string"}}, + }, + "User": { + "title": "User", + "required": ["username", "email"], + "type": "object", + "properties": { + "username": {"title": "Username", "type": "string"}, + "email": {"title": "Email", "type": "string"}, + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi(): + with client: + response = client.get("/openapi.json") + + assert response.json() == openapi_schema + + +def test_post_items(): + response = client.post("/items/", json={"name": "Foo", "price": 5}) + assert response.status_code == 200, response.text + assert response.json() == {"message": "Item received"} + + +def test_post_users(): + response = client.post( + "/users/", json={"username": "Foo", "email": "foo@example.com"} + ) + assert response.status_code == 200, response.text + assert response.json() == {"message": "User received"} + + +def test_get_items(): + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + {"name": "Plumbus", "price": 3}, + {"name": "Portal Gun", "price": 9001}, + ] From 786b5858e5b18ebb9722d0fc48c5ba39bb0c0d33 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 4 Mar 2022 22:02:55 +0000 Subject: [PATCH 396/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c5ca7376d..266578c97 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for custom `generate_unique_id_function` and docs for generating clients. PR [#4650](https://github.com/tiangolo/fastapi/pull/4650) by [@tiangolo](https://github.com/tiangolo). ## 0.74.1 From 586d17bfb592a904bceab0647cfdacaea51b7e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 4 Mar 2022 23:08:06 +0100 Subject: [PATCH 397/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 266578c97..a28b255f5 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,8 @@ ## Latest Changes -* ✨ Add support for custom `generate_unique_id_function` and docs for generating clients. PR [#4650](https://github.com/tiangolo/fastapi/pull/4650) by [@tiangolo](https://github.com/tiangolo). + +* ✨ Add support for custom `generate_unique_id_function` and docs for generating clients. New docs: [Advanced - Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/). PR [#4650](https://github.com/tiangolo/fastapi/pull/4650) by [@tiangolo](https://github.com/tiangolo). ## 0.74.1 From 19769d04836f8144aa7af32d6d0af356aaa92093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 4 Mar 2022 23:09:11 +0100 Subject: [PATCH 398/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.75?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 ++ fastapi/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a28b255f5..a34c87567 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -3,6 +3,8 @@ ## Latest Changes +## 0.75.0 + * ✨ Add support for custom `generate_unique_id_function` and docs for generating clients. New docs: [Advanced - Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/). PR [#4650](https://github.com/tiangolo/fastapi/pull/4650) by [@tiangolo](https://github.com/tiangolo). ## 0.74.1 diff --git a/fastapi/__init__.py b/fastapi/__init__.py index dc265558a..4bce5f017 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.74.1" +__version__ = "0.75.0" from starlette import status as status From c89dc736bd576bc1a9e2bb893576b59c6b906b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 4 Mar 2022 23:11:21 +0100 Subject: [PATCH 399/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a34c87567..2feb9dfff 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -5,6 +5,8 @@ ## 0.75.0 +### Features + * ✨ Add support for custom `generate_unique_id_function` and docs for generating clients. New docs: [Advanced - Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/). PR [#4650](https://github.com/tiangolo/fastapi/pull/4650) by [@tiangolo](https://github.com/tiangolo). ## 0.74.1 From 9f38a05954f9d307c8f2a1a6e9f8ef2f938755cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 5 Mar 2022 10:49:15 -0800 Subject: [PATCH 400/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20Jina's=20QA=20Bot?= =?UTF-8?q?=20to=20the=20docs=20to=20help=20people=20that=20want=20to=20as?= =?UTF-8?q?k=20quick=20questions=20(#4655)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: yanlong.wang --- docs/en/overrides/main.html | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index adc6f79fb..5255bfd9b 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -61,3 +61,35 @@ {% endblock %} +{%- block scripts %} +{{ super() }} + + + + + + + +{%- endblock %} From abd148f63a3a4fc9c110a8fe3da571ae8e37d57c Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 5 Mar 2022 18:49:46 +0000 Subject: [PATCH 401/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2feb9dfff..68292286e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add Jina's QA Bot to the docs to help people that want to ask quick questions. PR [#4655](https://github.com/tiangolo/fastapi/pull/4655) by [@tiangolo](https://github.com/tiangolo). ## 0.75.0 From 87e29ec2c54ce3651939cc4d10e05d07a2f8b9ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 5 Mar 2022 19:52:18 +0100 Subject: [PATCH 402/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 68292286e..d8df7a622 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,7 @@ ## Latest Changes -* 📝 Add Jina's QA Bot to the docs to help people that want to ask quick questions. PR [#4655](https://github.com/tiangolo/fastapi/pull/4655) by [@tiangolo](https://github.com/tiangolo). +* 📝 Add Jina's QA Bot to the docs to help people that want to ask quick questions. PR [#4655](https://github.com/tiangolo/fastapi/pull/4655) by [@tiangolo](https://github.com/tiangolo) based on original PR [#4626](https://github.com/tiangolo/fastapi/pull/4626) by [@hanxiao](https://github.com/hanxiao). ## 0.75.0 From 9aa698aa67b2507e289db30652e52f6ba163911c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 9 Mar 2022 21:29:40 -0500 Subject: [PATCH 403/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20Classiq=20sponsor?= =?UTF-8?q?=20(#4671)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/en/data/sponsors.yml | 3 +++ docs/en/docs/img/sponsors/classiq-banner.png | Bin 0 -> 5321 bytes docs/en/docs/img/sponsors/classiq.png | Bin 0 -> 6286 bytes docs/en/overrides/main.html | 6 ++++++ 5 files changed, 10 insertions(+) create mode 100644 docs/en/docs/img/sponsors/classiq-banner.png create mode 100644 docs/en/docs/img/sponsors/classiq.png diff --git a/README.md b/README.md index bec58aad1..5ed443ad1 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 4d63a7288..cc9201fbe 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -11,6 +11,9 @@ gold: - url: https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings title: https://striveworks.us/careers img: https://fastapi.tiangolo.com/img/sponsors/striveworks.png + - url: https://www.classiq.io/careers + title: Join the team building a new SaaS platform that will change the computing world + img: https://fastapi.tiangolo.com/img/sponsors/classiq.png silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas diff --git a/docs/en/docs/img/sponsors/classiq-banner.png b/docs/en/docs/img/sponsors/classiq-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..8a0d6ac741907732efcd69b7a0e2a5b29e48aeec GIT binary patch literal 5321 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 V0r@Q>O`z!r($+9guTr%Q`yVU$Jsto6 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/sponsors/classiq.png b/docs/en/docs/img/sponsors/classiq.png new file mode 100644 index 0000000000000000000000000000000000000000..189c6bbe8a4ad558391ae4b54412c8c9ed09f65b GIT binary patch literal 6286 zcmcIp_cI(|x7Jtho!DTNh_Xr&y?3Gut9MpgEqYs`*C2ZDMDLv-dh~=KI;#W`WwFZ5 zcjx{AcjnIh;k0+o%z0+cob%2+Cq_#{i3pz_9}NwSNJUv*=b!!aPi$~;{^^e5-qC*s z&rKQPiH1f%@gG4)%g&|!_lWMPqa=$~H_dqXFTk>wc`Jj4)|fxZ1DZlC@lOV-mFEMX>RD$Saw#mw)9h~qEor!K&{T)W{14sTugD6%G;Ra(lt`` zutpOlHXTR#+80zGZq=v}1v1hc+S2JCzJ@+8R4mj6%OZkZk+)Y5zcvESkn6A_)EvV2 z>R@B_)PGuHQUWmtc3iBaF45xr8=dZ|SfsT}Ju!f|K(O>^2VAa{Cc~v zC^)rzLI3T~NAowBk(X{uBtTKSHrV4@4dgZp^004jw{gnXOzFg~A^J_d=TA$qQ~%?h zhJkCZ+v=~O*y*MIps^amzcE!*BY8`!>K%U=PWg6lXfsZ7`oU^6r{BaCC2g1@lYT=H z#qHfAhVC_i4;0Ohd2(5ku&!M~!PB*oYXTl`;(h%$fXkp79?#s8jQj}q(02~NOPxu6 z&A3Saz(rnAC1@6kdnyly7YMk7X8B(Y41z$G5p2a71#5ZP(RE$WhR(nH%nD1ccZm1; zWPap^flPr=^|@Cg7Zp!kU-jb9MD_Xl)*<{(b%yo~6z8y^f} z=W*>u<=D-$J>VmF(g$JrP3!6J7i|<)_>x87z!<%~qq}-rDcSTq*`W2a1iUra zw|{fKQ?3(;0LTd>P!Wb4n-1wntafYqcn&4a2teG*zB`wjNet-4?u<5nL(fh#7S<7{ zPr5kS_L|W}=v}(L^Xec9yuaaBa`@F{YpkZ#pDam8-lmhX!jkgFQJMsJKT%_JUJ>SX z0xjq)JoHjamWa*YF`f9bKOURTMf(B|3}gH#1fe32x$^V8?y_ts$K`SSwGwW3Tt0M) zjMna*Y9B$qSaXv6^Qkq;_`3=94#+Ocf=zF6Tl#kOb5qb=(y_qVNonpzR zb^sL7fkMsFc^;Qlm+IGUe|l?6h5S8ao5_=?t}rfTYE0?KKXAjTlNb2X1GYi=m9Xv# ziycnn6qk)}BcucffE%{iB#)g3clQ8Ea4O%4efh&5ZY6p3mEXXJ^{P^Cp*>t7`8cTQ zgHx@odNw_*S{RXRyIn@-tn>x!WDsR|f6sK$@{Fc`BRujNjFb}m0j+2bY5Dnk*#q=l zmeEmw(r>kWU|bDS zbgv03qinbf$sG2IC+}!_!(ViI9CGMq3GB^o5eD|9dWU?MJbxj2B*uwVlL>YkGXcA% z3BldXeVy&`WX4dFCtTgGC(IXT%}SXSh*R)t&2Cx39xZ?MRU3}3(`>y*A{FS8{1|Pb z&y7-Q#;wli5vsC*48AGL3R<;WaCVUpqNVHhxVkzro!SkM5qcjEvHr$k2rMKnDNY?jBYYvz%6#35|CCszM`jNqNuaaA`e=McI07eSYwsF^x z7qhM$chfc8H{x!6U?CdAS7c{xQg-n}*F5HWJf_JOl{-3pX+$0DaRKy)#tv@2Rkc&4 z$WDD0MrT24$;Rde>4=j;m(0-I61G{A#Sruzsq3}%EW~pj(Oh_jv7J@@3{f

#8&X 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 Rf9C@<6$K6XI$4Xb{{s5EMvMRe literal 0 HcmV?d00001 diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 5255bfd9b..1c09405e5 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -58,6 +58,12 @@ +

{% endblock %} From fab2a765de051380e94db4dd5748c6ec96759853 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 10 Mar 2022 02:30:13 +0000 Subject: [PATCH 404/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d8df7a622..136c708c1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add Classiq sponsor. PR [#4671](https://github.com/tiangolo/fastapi/pull/4671) by [@tiangolo](https://github.com/tiangolo). * 📝 Add Jina's QA Bot to the docs to help people that want to ask quick questions. PR [#4655](https://github.com/tiangolo/fastapi/pull/4655) by [@tiangolo](https://github.com/tiangolo) based on original PR [#4626](https://github.com/tiangolo/fastapi/pull/4626) by [@hanxiao](https://github.com/hanxiao). ## 0.75.0 From cf8b40e660ad60f7febec7ea4fc7e1a79493ecb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 15 Mar 2022 10:47:36 -0500 Subject: [PATCH 405/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20Classiq=20spons?= =?UTF-8?q?or=20links=20(#4688)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- docs/en/data/sponsors.yml | 2 +- docs/en/overrides/main.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5ed443ad1..0fb25cc7e 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ The key features are: - + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index cc9201fbe..65a114584 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -11,7 +11,7 @@ gold: - url: https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings title: https://striveworks.us/careers img: https://fastapi.tiangolo.com/img/sponsors/striveworks.png - - url: https://www.classiq.io/careers + - url: https://classiq.link/n4s title: Join the team building a new SaaS platform that will change the computing world img: https://fastapi.tiangolo.com/img/sponsors/classiq.png silver: diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 1c09405e5..83c26e72a 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -59,7 +59,7 @@
- + From 6125dc72cdf245573b3eb2cba66ed8d1e52ba2cd Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 15 Mar 2022 15:48:22 +0000 Subject: [PATCH 406/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 136c708c1..b7ccd67f6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update Classiq sponsor links. PR [#4688](https://github.com/tiangolo/fastapi/pull/4688) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add Classiq sponsor. PR [#4671](https://github.com/tiangolo/fastapi/pull/4671) by [@tiangolo](https://github.com/tiangolo). * 📝 Add Jina's QA Bot to the docs to help people that want to ask quick questions. PR [#4655](https://github.com/tiangolo/fastapi/pull/4655) by [@tiangolo](https://github.com/tiangolo) based on original PR [#4626](https://github.com/tiangolo/fastapi/pull/4626) by [@hanxiao](https://github.com/hanxiao). From d3eb78709030650f24f5e31730f47591d6cef4cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 17 Mar 2022 13:36:21 -0500 Subject: [PATCH 407/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20FastAPI=20People?= =?UTF-8?q?=20generation=20to=20include=20missing=20file=20in=20commit=20(?= =?UTF-8?q?#4695)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/people/app/main.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/actions/people/app/main.py b/.github/actions/people/app/main.py index dc0bbc4c0..0b6ff4063 100644 --- a/.github/actions/people/app/main.py +++ b/.github/actions/people/app/main.py @@ -501,9 +501,16 @@ if __name__ == "__main__": github_sponsors_path = Path("./docs/en/data/github_sponsors.yml") people_old_content = people_path.read_text(encoding="utf-8") github_sponsors_old_content = github_sponsors_path.read_text(encoding="utf-8") - new_people_content = yaml.dump(people, sort_keys=False, width=200, allow_unicode=True) - new_github_sponsors_content = yaml.dump(github_sponsors, sort_keys=False, width=200, allow_unicode=True) - if people_old_content == new_people_content and github_sponsors_old_content == new_github_sponsors_content: + new_people_content = yaml.dump( + people, sort_keys=False, width=200, allow_unicode=True + ) + new_github_sponsors_content = yaml.dump( + github_sponsors, sort_keys=False, width=200, allow_unicode=True + ) + if ( + people_old_content == new_people_content + and github_sponsors_old_content == new_github_sponsors_content + ): logging.info("The FastAPI People data hasn't changed, finishing.") sys.exit(0) people_path.write_text(new_people_content, encoding="utf-8") @@ -517,7 +524,9 @@ if __name__ == "__main__": logging.info(f"Creating a new branch {branch_name}") subprocess.run(["git", "checkout", "-b", branch_name], check=True) logging.info("Adding updated file") - subprocess.run(["git", "add", str(people_path)], check=True) + subprocess.run( + ["git", "add", str(people_path), str(github_sponsors_path)], check=True + ) logging.info("Committing updated file") message = "👥 Update FastAPI People" result = subprocess.run(["git", "commit", "-m", message], check=True) From fd6ce6739231b4c00fb44c956ff761d6a32ad13c Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Mar 2022 18:36:57 +0000 Subject: [PATCH 408/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b7ccd67f6..bbe6ce221 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix FastAPI People generation to include missing file in commit. PR [#4695](https://github.com/tiangolo/fastapi/pull/4695) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Classiq sponsor links. PR [#4688](https://github.com/tiangolo/fastapi/pull/4688) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add Classiq sponsor. PR [#4671](https://github.com/tiangolo/fastapi/pull/4671) by [@tiangolo](https://github.com/tiangolo). * 📝 Add Jina's QA Bot to the docs to help people that want to ask quick questions. PR [#4655](https://github.com/tiangolo/fastapi/pull/4655) by [@tiangolo](https://github.com/tiangolo) based on original PR [#4626](https://github.com/tiangolo/fastapi/pull/4626) by [@hanxiao](https://github.com/hanxiao). From 7982aa514313eb7ee7cfecc71efba5a43cd43bc9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Mar 2022 15:19:43 -0500 Subject: [PATCH 409/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#4699)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/github_sponsors.yml | 427 +++++++++++++++++++++---------- docs/en/data/people.yml | 182 +++++++------ 2 files changed, 377 insertions(+), 232 deletions(-) diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml index 162a8dbe2..1d8dc9984 100644 --- a/docs/en/data/github_sponsors.yml +++ b/docs/en/data/github_sponsors.yml @@ -1,67 +1,115 @@ sponsors: -- - login: jina-ai +- - login: cryptapi + avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4 + url: https://github.com/cryptapi + - login: jina-ai avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4 url: https://github.com/jina-ai +- - login: InesIvanova + avatarUrl: https://avatars.githubusercontent.com/u/22920417?u=409882ec1df6dbd77455788bb383a8de223dbf6f&v=4 + url: https://github.com/InesIvanova +- - login: chaserowbotham + avatarUrl: https://avatars.githubusercontent.com/u/97751084?v=4 + url: https://github.com/chaserowbotham - - login: mikeckennedy - avatarUrl: https://avatars.githubusercontent.com/u/2035561?v=4 + avatarUrl: https://avatars.githubusercontent.com/u/2035561?u=1bb18268bcd4d9249e1f783a063c27df9a84c05b&v=4 url: https://github.com/mikeckennedy - - login: RodneyU215 - avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4 - url: https://github.com/RodneyU215 - login: Trivie avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4 url: https://github.com/Trivie - login: deta avatarUrl: https://avatars.githubusercontent.com/u/47275976?v=4 url: https://github.com/deta + - login: deepset-ai + avatarUrl: https://avatars.githubusercontent.com/u/51827949?v=4 + url: https://github.com/deepset-ai - login: investsuite avatarUrl: https://avatars.githubusercontent.com/u/73833632?v=4 url: https://github.com/investsuite - - login: vimsoHQ - avatarUrl: https://avatars.githubusercontent.com/u/77627231?v=4 - url: https://github.com/vimsoHQ -- - login: newrelic - avatarUrl: https://avatars.githubusercontent.com/u/31739?v=4 - url: https://github.com/newrelic - - login: qaas +- - login: qaas avatarUrl: https://avatars.githubusercontent.com/u/8503759?u=10a6b4391ad6ab4cf9487ce54e3fcb61322d1efc&v=4 url: https://github.com/qaas -- - login: johnadjei + - login: xoflare + avatarUrl: https://avatars.githubusercontent.com/u/74335107?v=4 + url: https://github.com/xoflare + - login: Striveworks + avatarUrl: https://avatars.githubusercontent.com/u/45523576?v=4 + url: https://github.com/Striveworks + - login: BoostryJP + avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4 + url: https://github.com/BoostryJP +- - login: bolau + avatarUrl: https://avatars.githubusercontent.com/u/488733?u=902c9f9b85db0e21aca11bf30d904ee8e87fffef&v=4 + url: https://github.com/bolau + - login: johnadjei avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4 url: https://github.com/johnadjei + - login: HiredScore + avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4 + url: https://github.com/HiredScore - login: wdwinslow avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 url: https://github.com/wdwinslow -- - login: kamalgill - avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4 - url: https://github.com/kamalgill +- - login: orvad + avatarUrl: https://avatars.githubusercontent.com/u/7700522?v=4 + url: https://github.com/orvad +- - login: moellenbeck + avatarUrl: https://avatars.githubusercontent.com/u/169372?v=4 + url: https://github.com/moellenbeck + - login: RodneyU215 + avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4 + url: https://github.com/RodneyU215 - login: grillazz avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=16d7d0ffa5dfb99f8834f8f76d90e138ba09b94a&v=4 url: https://github.com/grillazz - login: tizz98 avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4 url: https://github.com/tizz98 + - login: mntolia + avatarUrl: https://avatars.githubusercontent.com/u/10390224?v=4 + url: https://github.com/mntolia - login: jmaralc avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4 url: https://github.com/jmaralc - - login: AlexandruSimion - avatarUrl: https://avatars.githubusercontent.com/u/71321732?v=4 - url: https://github.com/AlexandruSimion + - login: Filimoa + avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4 + url: https://github.com/Filimoa + - login: marutoraman + avatarUrl: https://avatars.githubusercontent.com/u/33813153?v=4 + url: https://github.com/marutoraman + - login: mainframeindustries + avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4 + url: https://github.com/mainframeindustries + - login: A-Edge + avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4 + url: https://github.com/A-Edge - - login: samuelcolvin avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4 url: https://github.com/samuelcolvin - login: jokull avatarUrl: https://avatars.githubusercontent.com/u/701?u=0532b62166893d5160ef795c4c8b7512d971af05&v=4 url: https://github.com/jokull + - login: jefftriplett + avatarUrl: https://avatars.githubusercontent.com/u/50527?u=af1ddfd50f6afd6d99f333ba2ac8d0a5b245ea74&v=4 + url: https://github.com/jefftriplett + - login: kamalgill + avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4 + url: https://github.com/kamalgill + - login: jsutton + avatarUrl: https://avatars.githubusercontent.com/u/280777?v=4 + url: https://github.com/jsutton + - login: deserat + avatarUrl: https://avatars.githubusercontent.com/u/299332?v=4 + url: https://github.com/deserat + - login: ericof + avatarUrl: https://avatars.githubusercontent.com/u/306014?u=cf7c8733620397e6584a451505581c01c5d842d7&v=4 + url: https://github.com/ericof - login: wshayes avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes - login: koxudaxi avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4 url: https://github.com/koxudaxi - - login: falkben - avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 - url: https://github.com/falkben - login: jqueguiner avatarUrl: https://avatars.githubusercontent.com/u/690878?u=e4835b2a985a0f2d52018e4926cb5a58c26a62e8&v=4 url: https://github.com/jqueguiner @@ -71,18 +119,15 @@ sponsors: - login: ltieman avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4 url: https://github.com/ltieman - - login: mrmattwright - avatarUrl: https://avatars.githubusercontent.com/u/1277725?v=4 - url: https://github.com/mrmattwright - login: westonsteimel avatarUrl: https://avatars.githubusercontent.com/u/1593939?u=0f2c0e3647f916fe295d62fa70da7a4c177115e3&v=4 url: https://github.com/westonsteimel - login: timdrijvers avatarUrl: https://avatars.githubusercontent.com/u/1694939?v=4 url: https://github.com/timdrijvers - - login: mrgnw - avatarUrl: https://avatars.githubusercontent.com/u/2504532?u=7ec43837a6d0afa80f96f0788744ea6341b89f97&v=4 - url: https://github.com/mrgnw + - login: corleyma + avatarUrl: https://avatars.githubusercontent.com/u/2080732?u=aed2ff652294a87d666b1c3f6dbe98104db76d26&v=4 + url: https://github.com/corleyma - login: madisonmay avatarUrl: https://avatars.githubusercontent.com/u/2645393?u=f22b93c6ea345a4d26a90a3834dfc7f0789fcb63&v=4 url: https://github.com/madisonmay @@ -93,32 +138,50 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/3148093?v=4 url: https://github.com/andre1sk - login: Shark009 - avatarUrl: https://avatars.githubusercontent.com/u/3163309?v=4 + avatarUrl: https://avatars.githubusercontent.com/u/3163309?u=0c6f4091b0eda05c44c390466199826e6dc6e431&v=4 url: https://github.com/Shark009 + - login: dblackrun + avatarUrl: https://avatars.githubusercontent.com/u/3528486?v=4 + url: https://github.com/dblackrun + - login: zsinx6 + avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4 + url: https://github.com/zsinx6 + - login: anomaly + avatarUrl: https://avatars.githubusercontent.com/u/3654837?v=4 + url: https://github.com/anomaly - login: peterHoburg avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4 url: https://github.com/peterHoburg - login: jaredtrog avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4 url: https://github.com/jaredtrog + - login: oliverxchen + avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4 + url: https://github.com/oliverxchen - login: CINOAdam - avatarUrl: https://avatars.githubusercontent.com/u/4728508?u=34c3d58cb900fed475d0172b436c66a94ad739ed&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/4728508?u=76ef23f06ae7c604e009873bc27cf0ea9ba738c9&v=4 url: https://github.com/CINOAdam - - login: dudil - avatarUrl: https://avatars.githubusercontent.com/u/4785835?u=58b7ea39123e0507f3b2996448a27256b16fd697&v=4 - url: https://github.com/dudil + - login: ScrimForever + avatarUrl: https://avatars.githubusercontent.com/u/5040124?u=091ec38bfe16d6e762099e91309b59f248616a65&v=4 + url: https://github.com/ScrimForever - login: ennui93 avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4 url: https://github.com/ennui93 - login: MacroPower avatarUrl: https://avatars.githubusercontent.com/u/5648814?u=e13991efd1e03c44c911f919872e750530ded633&v=4 url: https://github.com/MacroPower - - login: ginomempin - avatarUrl: https://avatars.githubusercontent.com/u/6091865?v=4 - url: https://github.com/ginomempin + - login: Yaleesa + avatarUrl: https://avatars.githubusercontent.com/u/6135475?v=4 + url: https://github.com/Yaleesa - login: iwpnd avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=b2286006daafff5f991557344fee20b5da59639a&v=4 url: https://github.com/iwpnd + - login: simw + avatarUrl: https://avatars.githubusercontent.com/u/6322526?v=4 + url: https://github.com/simw + - login: pkucmus + avatarUrl: https://avatars.githubusercontent.com/u/6347418?u=98f5918b32e214a168a2f5d59b0b8ebdf57dca0d&v=4 + url: https://github.com/pkucmus - login: s3ich4n avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=ba3025d698e1c986655e776ae383a3d60d9d578e&v=4 url: https://github.com/s3ich4n @@ -126,116 +189,158 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4 url: https://github.com/Rehket - login: christippett - avatarUrl: https://avatars.githubusercontent.com/u/7218120?u=434b9d29287d7de25772d94ddc74a9bd6d969284&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/7218120?u=f21f93b9c14edefef75645bf4d64c819b7d4afd7&v=4 url: https://github.com/christippett + - login: hiancdtrsnm + avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4 + url: https://github.com/hiancdtrsnm - login: Kludex - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: Shackelford-Arden avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4 url: https://github.com/Shackelford-Arden - - login: cristeaadrian - avatarUrl: https://avatars.githubusercontent.com/u/9112724?v=4 - url: https://github.com/cristeaadrian - - login: otivvormes - avatarUrl: https://avatars.githubusercontent.com/u/11317418?u=6de1edefb6afd0108c0ad2816bd6efc4464a9c44&v=4 - url: https://github.com/otivvormes - - login: iambobmae - avatarUrl: https://avatars.githubusercontent.com/u/12390270?u=c9a35c2ee5092a9b4135ebb1f91b7f521c467031&v=4 - url: https://github.com/iambobmae - - login: ronaldnwilliams - avatarUrl: https://avatars.githubusercontent.com/u/13632749?u=ac41a086d0728bf66a9d2bee9e5e377041ff44a4&v=4 - url: https://github.com/ronaldnwilliams + - login: Vikka + avatarUrl: https://avatars.githubusercontent.com/u/9381120?u=4bfc7032a824d1ed1994aa8256dfa597c8f187ad&v=4 + url: https://github.com/Vikka + - login: Ge0f3 + avatarUrl: https://avatars.githubusercontent.com/u/11887760?u=ccd80f1ac36dcb8517ef5c4e702e8cc5a80cad2f&v=4 + url: https://github.com/Ge0f3 + - login: gokulyc + avatarUrl: https://avatars.githubusercontent.com/u/13468848?u=269f269d3e70407b5fb80138c52daba7af783997&v=4 + url: https://github.com/gokulyc + - login: dannywade + avatarUrl: https://avatars.githubusercontent.com/u/13680237?u=418ee985bd41577b20fde81417fb2d901e875e8a&v=4 + url: https://github.com/dannywade - login: pablonnaoji avatarUrl: https://avatars.githubusercontent.com/u/15187159?u=afc15bd5a4ba9c5c7206bbb1bcaeef606a0932e0&v=4 url: https://github.com/pablonnaoji - - login: natenka - avatarUrl: https://avatars.githubusercontent.com/u/15850513?u=00d1083c980d0b4ce32835dc07eee7f43f34fd2f&v=4 - url: https://github.com/natenka - - login: la-mar - avatarUrl: https://avatars.githubusercontent.com/u/16618300?u=7755c0521d2bb0d704f35a51464b15c1e2e6c4da&v=4 - url: https://github.com/la-mar - login: robintully avatarUrl: https://avatars.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4 url: https://github.com/robintully - - login: ShaulAb - avatarUrl: https://avatars.githubusercontent.com/u/18129076?u=2c8d48e47f2dbee15c3f89c3d17d4c356504386c&v=4 - url: https://github.com/ShaulAb + - login: tobiasfeil + avatarUrl: https://avatars.githubusercontent.com/u/17533713?u=bc6b0bec46f342d13c41695db90685d1c58d534e&v=4 + url: https://github.com/tobiasfeil - login: wedwardbeck avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4 url: https://github.com/wedwardbeck - login: linusg avatarUrl: https://avatars.githubusercontent.com/u/19366641?u=125e390abef8fff3b3b0d370c369cba5d7fd4c67&v=4 url: https://github.com/linusg + - login: stradivari96 + avatarUrl: https://avatars.githubusercontent.com/u/19752586?u=255f5f06a768f518b20cebd6963e840ac49294fd&v=4 + url: https://github.com/stradivari96 - login: RedCarpetUp avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4 url: https://github.com/RedCarpetUp - - login: Filimoa - avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4 - url: https://github.com/Filimoa - - login: raminsj13 - avatarUrl: https://avatars.githubusercontent.com/u/24259406?u=d51f2a526312ebba150a06936ed187ca0727d329&v=4 - url: https://github.com/raminsj13 + - login: shuheng-liu + avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4 + url: https://github.com/shuheng-liu - login: comoelcometa avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=c6751efa038561b9bc5fa56d1033d5174e10cd65&v=4 url: https://github.com/comoelcometa + - login: LarryGF + avatarUrl: https://avatars.githubusercontent.com/u/26148349?u=431bb34d36d41c172466252242175281ae132152&v=4 + url: https://github.com/LarryGF - login: veprimk avatarUrl: https://avatars.githubusercontent.com/u/29689749?u=f8cb5a15a286e522e5b189bc572d5a1a90217fb2&v=4 url: https://github.com/veprimk - login: orihomie avatarUrl: https://avatars.githubusercontent.com/u/29889683?u=6bc2135a52fcb3a49e69e7d50190796618185fda&v=4 url: https://github.com/orihomie - - login: SaltyCoco - avatarUrl: https://avatars.githubusercontent.com/u/31451104?u=6ee4e17c07d21b7054f54a12fa9cc377a1b24ff9&v=4 - url: https://github.com/SaltyCoco + - login: meysam81 + avatarUrl: https://avatars.githubusercontent.com/u/30233243?u=64dc9fc62d039892c6fb44d804251cad5537132b&v=4 + url: https://github.com/meysam81 - login: mauroalejandrojm avatarUrl: https://avatars.githubusercontent.com/u/31569442?u=cdada990a1527926a36e95f62c30a8b48bbc49a1&v=4 url: https://github.com/mauroalejandrojm - - login: bulkw4r3 - avatarUrl: https://avatars.githubusercontent.com/u/35562532?u=0b812a14a02de14bf73d05fb2b2760a67bacffc2&v=4 - url: https://github.com/bulkw4r3 + - login: Leay15 + avatarUrl: https://avatars.githubusercontent.com/u/32212558?u=c4aa9c1737e515959382a5515381757b1fd86c53&v=4 + url: https://github.com/Leay15 + - login: AlrasheedA + avatarUrl: https://avatars.githubusercontent.com/u/33544979?u=7fe66bf62b47682612b222e3e8f4795ef3be769b&v=4 + url: https://github.com/AlrasheedA + - login: ProteinQure + avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4 + url: https://github.com/ProteinQure + - login: guligon90 + avatarUrl: https://avatars.githubusercontent.com/u/35070513?u=b48c05f669d1ea1d329f90dc70e45f10b569ef55&v=4 + url: https://github.com/guligon90 - login: ybressler avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=6621dc9ab53b697912ab2a32211bb29ae90a9112&v=4 url: https://github.com/ybressler - login: dbanty - avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4 url: https://github.com/dbanty + - login: rafsaf + avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 + url: https://github.com/rafsaf - login: dudikbender avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4 url: https://github.com/dudikbender + - login: jorge4larcon + avatarUrl: https://avatars.githubusercontent.com/u/54189123?v=4 + url: https://github.com/jorge4larcon + - login: daisuke8000 + avatarUrl: https://avatars.githubusercontent.com/u/55035595?u=5025e379cd3655ae1a96039efc85223a873d2e38&v=4 + url: https://github.com/daisuke8000 - login: primer-io avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4 url: https://github.com/primer-io - - login: tkrestiankova - avatarUrl: https://avatars.githubusercontent.com/u/67013045?v=4 - url: https://github.com/tkrestiankova + - login: around + avatarUrl: https://avatars.githubusercontent.com/u/62425723?v=4 + url: https://github.com/around + - login: predictionmachine + avatarUrl: https://avatars.githubusercontent.com/u/63719559?v=4 + url: https://github.com/predictionmachine - login: daverin avatarUrl: https://avatars.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4 url: https://github.com/daverin - login: anthonycepeda avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 url: https://github.com/anthonycepeda - - login: an-tho-ny - avatarUrl: https://avatars.githubusercontent.com/u/74874159?v=4 - url: https://github.com/an-tho-ny + - login: abdurrahim84 + avatarUrl: https://avatars.githubusercontent.com/u/79488613?v=4 + url: https://github.com/abdurrahim84 + - login: NinaHwang + avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 + url: https://github.com/NinaHwang + - login: dotlas + avatarUrl: https://avatars.githubusercontent.com/u/88832003?v=4 + url: https://github.com/dotlas + - login: pyt3h + avatarUrl: https://avatars.githubusercontent.com/u/99658549?v=4 + url: https://github.com/pyt3h +- - login: '837477' + avatarUrl: https://avatars.githubusercontent.com/u/37999795?u=543b0bd0e8f283db0fc50754e5d13f6afba8cbea&v=4 + url: https://github.com/837477 + - login: naheedroomy + avatarUrl: https://avatars.githubusercontent.com/u/46345736?v=4 + url: https://github.com/naheedroomy - - login: linux-china avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4 url: https://github.com/linux-china + - login: ddanier + avatarUrl: https://avatars.githubusercontent.com/u/113563?v=4 + url: https://github.com/ddanier - login: jhb avatarUrl: https://avatars.githubusercontent.com/u/142217?v=4 url: https://github.com/jhb + - login: justinrmiller + avatarUrl: https://avatars.githubusercontent.com/u/143998?u=b507a940394d4fc2bc1c27cea2ca9c22538874bd&v=4 + url: https://github.com/justinrmiller + - login: bryanculbertson + avatarUrl: https://avatars.githubusercontent.com/u/144028?u=defda4f90e93429221cc667500944abde60ebe4a&v=4 + url: https://github.com/bryanculbertson - login: yourkin - avatarUrl: https://avatars.githubusercontent.com/u/178984?v=4 + avatarUrl: https://avatars.githubusercontent.com/u/178984?u=163b8c6d9b2d240164ade467cbc9efb16d2432e4&v=4 url: https://github.com/yourkin - - login: jmagnusson - avatarUrl: https://avatars.githubusercontent.com/u/190835?v=4 - url: https://github.com/jmagnusson - - login: sakti - avatarUrl: https://avatars.githubusercontent.com/u/196178?u=0110be74c4270244546f1b610334042cd16bb8ad&v=4 - url: https://github.com/sakti - login: slafs avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4 url: https://github.com/slafs + - login: assem-ch + avatarUrl: https://avatars.githubusercontent.com/u/315228?u=e0c5ab30726d3243a40974bb9bae327866e42d9b&v=4 + url: https://github.com/assem-ch - login: adamghill avatarUrl: https://avatars.githubusercontent.com/u/317045?u=f1349d5ffe84a19f324e204777859fbf69ddf633&v=4 url: https://github.com/adamghill @@ -245,21 +350,33 @@ sponsors: - login: dmig avatarUrl: https://avatars.githubusercontent.com/u/388564?v=4 url: https://github.com/dmig - - login: hongqn - avatarUrl: https://avatars.githubusercontent.com/u/405587?u=470b4c04832e45141fd5264d3354845cc9fc6466&v=4 - url: https://github.com/hongqn - login: rinckd avatarUrl: https://avatars.githubusercontent.com/u/546002?u=1fcc7e664dc86524a0af6837a0c222829c3fd4e5&v=4 url: https://github.com/rinckd + - login: securancy + avatarUrl: https://avatars.githubusercontent.com/u/606673?v=4 + url: https://github.com/securancy + - login: falkben + avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 + url: https://github.com/falkben - login: hardbyte avatarUrl: https://avatars.githubusercontent.com/u/855189?u=aa29e92f34708814d6b67fcd47ca4cf2ce1c04ed&v=4 url: https://github.com/hardbyte + - login: clstaudt + avatarUrl: https://avatars.githubusercontent.com/u/875194?u=46a92f9f837d0ba150ae0f1d91091dd2f4ebb6cc&v=4 + url: https://github.com/clstaudt + - login: scari + avatarUrl: https://avatars.githubusercontent.com/u/964251?v=4 + url: https://github.com/scari - login: Pytlicek avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=169dba3bfbc04ed214a914640ff435969f19ddb3&v=4 url: https://github.com/Pytlicek - - login: okken - avatarUrl: https://avatars.githubusercontent.com/u/1568356?u=0a991a21bdc62e2bea9ad311652f2c45f453dc84&v=4 - url: https://github.com/okken + - login: Celeborn2BeAlive + avatarUrl: https://avatars.githubusercontent.com/u/1659465?u=944517e4db0f6df65070074e81cabdad9c8a434b&v=4 + url: https://github.com/Celeborn2BeAlive + - login: WillHogan + avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4 + url: https://github.com/WillHogan - login: cbonoz avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4 url: https://github.com/cbonoz @@ -269,111 +386,147 @@ sponsors: - login: rglsk avatarUrl: https://avatars.githubusercontent.com/u/2768101?u=e349c88673f2155fe021331377c656a9d74bcc25&v=4 url: https://github.com/rglsk - - login: Atem18 - avatarUrl: https://avatars.githubusercontent.com/u/2875254?v=4 - url: https://github.com/Atem18 - login: paul121 avatarUrl: https://avatars.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4 url: https://github.com/paul121 - login: igorcorrea avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4 url: https://github.com/igorcorrea - - login: anthcor + - login: anthonycorletti avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4 - url: https://github.com/anthcor - - login: zsinx6 - avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4 - url: https://github.com/zsinx6 + url: https://github.com/anthonycorletti - login: pawamoy avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4 url: https://github.com/pawamoy - - login: spyker77 - avatarUrl: https://avatars.githubusercontent.com/u/4953435?u=03c724c6f8fbab5cd6575b810c0c91c652fa4f79&v=4 - url: https://github.com/spyker77 - - login: JonasKs - avatarUrl: https://avatars.githubusercontent.com/u/5310116?u=98a049f3e1491bffb91e1feb7e93def6881a9389&v=4 - url: https://github.com/JonasKs + - login: Alisa-lisa + avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4 + url: https://github.com/Alisa-lisa + - login: unredundant + avatarUrl: https://avatars.githubusercontent.com/u/5607577?u=57dd0023365bec03f4fc566df6b81bc0a264a47d&v=4 + url: https://github.com/unredundant + - login: Baghdady92 + avatarUrl: https://avatars.githubusercontent.com/u/5708590?v=4 + url: https://github.com/Baghdady92 - login: holec avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4 url: https://github.com/holec - - login: BartlomiejRasztabiga - avatarUrl: https://avatars.githubusercontent.com/u/8852711?u=ed213d60f7a423df31ceb1004aa3ec60e612cb98&v=4 - url: https://github.com/BartlomiejRasztabiga - login: davanstrien avatarUrl: https://avatars.githubusercontent.com/u/8995957?u=fb2aad2b52bb4e7b56db6d7c8ecc9ae1eac1b984&v=4 url: https://github.com/davanstrien - login: and-semakin avatarUrl: https://avatars.githubusercontent.com/u/9129071?u=ea77ddf7de4bc375d546bf2825ed420eaddb7666&v=4 url: https://github.com/and-semakin + - login: yenchenLiu + avatarUrl: https://avatars.githubusercontent.com/u/9199638?u=8cdf5ae507448430d90f6f3518d1665a23afe99b&v=4 + url: https://github.com/yenchenLiu - login: VivianSolide - avatarUrl: https://avatars.githubusercontent.com/u/9358572?u=ffb2e2ec522a15dcd3f0af1f9fd1df4afe418afa&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/9358572?u=4a38ef72dd39e8b262bd5ab819992128b55c52b4&v=4 url: https://github.com/VivianSolide + - login: xncbf + avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=ded074228b35b46a76b980d2dda522e45277f96d&v=4 + url: https://github.com/xncbf + - login: DMantis + avatarUrl: https://avatars.githubusercontent.com/u/9536869?v=4 + url: https://github.com/DMantis - login: hard-coders - avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4 url: https://github.com/hard-coders - - login: satwikkansal - avatarUrl: https://avatars.githubusercontent.com/u/10217535?u=b12d6ef74ea297de9e46da6933b1a5b7ba9e6a61&v=4 - url: https://github.com/satwikkansal - login: pheanex avatarUrl: https://avatars.githubusercontent.com/u/10408624?u=5b6bab6ee174aa6e991333e06eb29f628741013d&v=4 url: https://github.com/pheanex - - login: wotori - avatarUrl: https://avatars.githubusercontent.com/u/10486621?u=0044c295b91694b8c9bccc0a805681f794250f7b&v=4 - url: https://github.com/wotori - login: JimFawkes avatarUrl: https://avatars.githubusercontent.com/u/12075115?u=dc58ecfd064d72887c34bf500ddfd52592509acd&v=4 url: https://github.com/JimFawkes - login: logan-connolly avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4 url: https://github.com/logan-connolly - - login: iPr0ger - avatarUrl: https://avatars.githubusercontent.com/u/19322290?v=4 - url: https://github.com/iPr0ger + - login: cdsre + avatarUrl: https://avatars.githubusercontent.com/u/16945936?v=4 + url: https://github.com/cdsre + - login: jangia + avatarUrl: https://avatars.githubusercontent.com/u/17927101?u=9261b9bb0c3e3bb1ecba43e8915dc58d8c9a077e&v=4 + url: https://github.com/jangia - login: ghandic avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 url: https://github.com/ghandic - - login: MoronVV - avatarUrl: https://avatars.githubusercontent.com/u/24293616?v=4 - url: https://github.com/MoronVV - login: fstau avatarUrl: https://avatars.githubusercontent.com/u/24669867?u=60e7c8c09f8dafabee8fc3edcd6f9e19abbff918&v=4 url: https://github.com/fstau - login: mertguvencli avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4 url: https://github.com/mertguvencli - - login: rgreen32 - avatarUrl: https://avatars.githubusercontent.com/u/35779241?u=c9d64ad1ab364b6a1ec8e3d859da9ca802d681d8&v=4 - url: https://github.com/rgreen32 + - login: dwreeves + avatarUrl: https://avatars.githubusercontent.com/u/31971762?u=69732aba05aa5cf0780866349ebe109cf632b047&v=4 + url: https://github.com/dwreeves + - login: kitaramu0401 + avatarUrl: https://avatars.githubusercontent.com/u/33246506?u=929e6efa2c518033b8097ba524eb5347a069bb3b&v=4 + url: https://github.com/kitaramu0401 + - login: engineerjoe440 + avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4 + url: https://github.com/engineerjoe440 + - login: declon + avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4 + url: https://github.com/declon + - login: d-e-h-i-o + avatarUrl: https://avatars.githubusercontent.com/u/36816716?v=4 + url: https://github.com/d-e-h-i-o - login: askurihin avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4 url: https://github.com/askurihin - login: JitPackJoyride - avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=9638bfeacfa5940358188f8205ce662bba022b53&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=cfad4285914e018af72a3f3c16d8ac11321201e3&v=4 url: https://github.com/JitPackJoyride - login: es3n1n - avatarUrl: https://avatars.githubusercontent.com/u/40367813?u=e881a3880f1e342d19a1ea7c8e1b6d76c52dc294&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/40367813?u=cfaaedfb5da6c2c00330f8ebb041cd39c6a6273d&v=4 url: https://github.com/es3n1n - login: ilias-ant avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4 url: https://github.com/ilias-ant - login: arrrrrmin - avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=05600727f1cfe75f440bb3fddd49bfea84b1e894&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=fee5739394fea074cb0b66929d070114a5067aae&v=4 url: https://github.com/arrrrrmin + - login: 4heck + avatarUrl: https://avatars.githubusercontent.com/u/45015299?u=7dfb2aca55bff66849396588828a90e090212f81&v=4 + url: https://github.com/4heck + - login: igorezersky + avatarUrl: https://avatars.githubusercontent.com/u/46680020?u=a20a595c881dbe5658c906fecc7eff125efb4fd4&v=4 + url: https://github.com/igorezersky - login: akanz1 avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4 url: https://github.com/akanz1 -- - login: leogregianin - avatarUrl: https://avatars.githubusercontent.com/u/1684053?u=94ddd387601bd1805034dbe83e6eba0491c15323&v=4 - url: https://github.com/leogregianin + - login: rooflexx + avatarUrl: https://avatars.githubusercontent.com/u/58993673?u=f8ba450460f1aea18430ed1e4a3889049a3b4dfa&v=4 + url: https://github.com/rooflexx + - login: denisyao1 + avatarUrl: https://avatars.githubusercontent.com/u/60019356?v=4 + url: https://github.com/denisyao1 + - login: apar-tiwari + avatarUrl: https://avatars.githubusercontent.com/u/61064197?v=4 + url: https://github.com/apar-tiwari + - login: 0417taehyun + avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4 + url: https://github.com/0417taehyun + - login: alessio-proietti + avatarUrl: https://avatars.githubusercontent.com/u/67370599?u=8ac73db1e18e946a7681f173abdb640516f88515&v=4 + url: https://github.com/alessio-proietti +- - login: spyker77 + avatarUrl: https://avatars.githubusercontent.com/u/4953435?u=03c724c6f8fbab5cd6575b810c0c91c652fa4f79&v=4 + url: https://github.com/spyker77 + - login: backbord + avatarUrl: https://avatars.githubusercontent.com/u/6814946?v=4 + url: https://github.com/backbord - login: sadikkuzu avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4 url: https://github.com/sadikkuzu + - login: MoronVV + avatarUrl: https://avatars.githubusercontent.com/u/24293616?v=4 + url: https://github.com/MoronVV - login: gabrielmbmb avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=92084ed7242160dee4d20aece923a10c59758ee5&v=4 url: https://github.com/gabrielmbmb - - login: starhype - avatarUrl: https://avatars.githubusercontent.com/u/36908028?u=6df41f7b62f0f673f1ecbc87e9cbadaa4fcb0767&v=4 - url: https://github.com/starhype - - login: pixel365 - avatarUrl: https://avatars.githubusercontent.com/u/53819609?u=9e0309c5420ec4624aececd3ca2d7105f7f68133&v=4 - url: https://github.com/pixel365 + - login: danburonline + avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4 + url: https://github.com/danburonline + - login: foryourselfand + avatarUrl: https://avatars.githubusercontent.com/u/43334967?u=8abd999f94bc0852d035b765155d5138a88288ce&v=4 + url: https://github.com/foryourselfand diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index ebbe446ee..591800a35 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,13 +1,13 @@ maintainers: - login: tiangolo - answers: 1237 - prs: 280 + answers: 1240 + prs: 289 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=5cad72c846b7aba2e960546af490edc7375dafc4&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 319 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 + count: 330 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: dmontagu count: 262 @@ -29,14 +29,14 @@ experts: count: 130 avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 +- login: raphaelauv + count: 71 + avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 + url: https://github.com/raphaelauv - login: ArcLightSlavik count: 71 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik -- login: raphaelauv - count: 68 - avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 - url: https://github.com/raphaelauv - login: falkben count: 58 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 @@ -50,7 +50,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 url: https://github.com/insomnes - login: Dustyposa - count: 42 + count: 43 avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 url: https://github.com/Dustyposa - login: includeamin @@ -65,22 +65,26 @@ experts: count: 33 avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4 url: https://github.com/prostomarkeloff +- login: frankie567 + count: 31 + avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 + url: https://github.com/frankie567 +- login: adriangb + count: 31 + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 + url: https://github.com/adriangb - login: krishnardt count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 url: https://github.com/krishnardt -- login: adriangb - count: 30 - avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 - url: https://github.com/adriangb - login: wshayes count: 29 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes -- login: frankie567 - count: 29 - avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 - url: https://github.com/frankie567 +- login: panla + count: 26 + avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 + url: https://github.com/panla - login: chbndrhnns count: 25 avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 @@ -93,10 +97,6 @@ experts: count: 25 avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4 url: https://github.com/dbanty -- login: panla - count: 25 - avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 - url: https://github.com/panla - login: SirTelemak count: 24 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 @@ -113,6 +113,10 @@ experts: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 url: https://github.com/chris-allnutt +- login: jgould22 + count: 20 + avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 + url: https://github.com/jgould22 - login: retnikt count: 19 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 @@ -141,14 +145,14 @@ experts: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 url: https://github.com/dstlny -- login: jgould22 - count: 14 - avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 - url: https://github.com/jgould22 - login: harunyasar - count: 14 + count: 16 avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 url: https://github.com/harunyasar +- login: rafsaf + count: 15 + avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 + url: https://github.com/rafsaf - login: haizaar count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 @@ -189,43 +193,31 @@ experts: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/2858306?u=1bb1182a5944e93624b7fb26585f22c8f7a9d76e&v=4 url: https://github.com/oligond +- login: n8sty + count: 10 + avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 + url: https://github.com/n8sty last_month_active: -- login: harunyasar - count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 - url: https://github.com/harunyasar +- login: yinziyan1206 + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4 + url: https://github.com/yinziyan1206 +- login: Kludex + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 + url: https://github.com/Kludex - login: jgould22 - count: 10 + count: 3 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 url: https://github.com/jgould22 - login: rafsaf - count: 9 + count: 3 avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 url: https://github.com/rafsaf -- login: STeveShary - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 - url: https://github.com/STeveShary -- login: ahnaf-zamil +- login: gmanny count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/57180217?u=849128b146771ace47beca5b5ff68eb82905dd6d&v=4 - url: https://github.com/ahnaf-zamil -- login: lucastosetto - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/89307132?u=56326696423df7126c9e7c702ee58f294db69a2a&v=4 - url: https://github.com/lucastosetto -- login: blokje - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/851418?v=4 - url: https://github.com/blokje -- login: MatthijsKok - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/7658129?u=1243e32d57e13abc45e3f5235ed5b9197e0d2b41&v=4 - url: https://github.com/MatthijsKok -- login: Kludex - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 - url: https://github.com/Kludex + avatarUrl: https://avatars.githubusercontent.com/u/1166296?v=4 + url: https://github.com/gmanny top_contributors: - login: waynerv count: 25 @@ -265,7 +257,7 @@ top_contributors: url: https://github.com/RunningIkkyu - login: Kludex count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: hard-coders count: 7 @@ -306,7 +298,7 @@ top_contributors: top_reviewers: - login: Kludex count: 93 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: waynerv count: 47 @@ -324,6 +316,10 @@ top_reviewers: count: 45 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd +- login: cikay + count: 40 + avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 + url: https://github.com/cikay - login: AdrianDeAnda count: 33 avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4 @@ -332,10 +328,6 @@ top_reviewers: count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik -- login: cikay - count: 24 - avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 - url: https://github.com/cikay - login: dmontagu count: 23 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 @@ -356,6 +348,18 @@ top_reviewers: count: 19 avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4 url: https://github.com/0417taehyun +- login: BilalAlpaslan + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 + url: https://github.com/BilalAlpaslan +- login: zy7y + count: 17 + avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4 + url: https://github.com/zy7y +- login: yezz123 + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 + url: https://github.com/yezz123 - login: yanever count: 16 avatarUrl: https://avatars.githubusercontent.com/u/21978760?v=4 @@ -392,10 +396,6 @@ top_reviewers: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 url: https://github.com/RunningIkkyu -- login: yezz123 - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 - url: https://github.com/yezz123 - login: sh0nk count: 12 avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4 @@ -412,6 +412,10 @@ top_reviewers: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4 url: https://github.com/maoyibo +- login: solomein-sv + count: 10 + avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 + url: https://github.com/solomein-sv - login: graingert count: 9 avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4 @@ -424,26 +428,26 @@ top_reviewers: count: 9 avatarUrl: https://avatars.githubusercontent.com/u/49435654?v=4 url: https://github.com/kty4119 -- login: zy7y - count: 9 - avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4 - url: https://github.com/zy7y - login: bezaca count: 9 avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4 url: https://github.com/bezaca -- login: solomein-sv - count: 9 - avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 - url: https://github.com/solomein-sv - login: blt232018 count: 8 avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4 url: https://github.com/blt232018 +- login: rogerbrinkmann + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/5690226?v=4 + url: https://github.com/rogerbrinkmann - login: ComicShrimp count: 8 avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 url: https://github.com/ComicShrimp +- login: dimaqq + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4 + url: https://github.com/dimaqq - login: Serrones count: 7 avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 @@ -456,10 +460,6 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv -- login: BilalAlpaslan - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 - url: https://github.com/BilalAlpaslan - login: NastasiaSaby count: 7 avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4 @@ -472,31 +472,23 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/34248814?v=4 url: https://github.com/krocdort -- login: dimaqq +- login: NinaHwang count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4 - url: https://github.com/dimaqq + avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 + url: https://github.com/NinaHwang - login: jovicon count: 6 avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 url: https://github.com/jovicon -- login: NinaHwang +- login: LorhanSohaky count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 - url: https://github.com/NinaHwang + avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4 + url: https://github.com/LorhanSohaky +- login: peidrao + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=88c2cb42a99e0f50cdeae3606992568184783ee5&v=4 + url: https://github.com/peidrao - login: diogoduartec count: 5 avatarUrl: https://avatars.githubusercontent.com/u/31852339?u=b50fc11c531e9b77922e19edfc9e7233d4d7b92e&v=4 url: https://github.com/diogoduartec -- login: n25a - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=eb3c95338741c78fff7d9d5d7ace9617e53eee4a&v=4 - url: https://github.com/n25a -- login: izaguerreiro - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4 - url: https://github.com/izaguerreiro -- login: israteneda - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/20668624?u=d7b2961d330aca65fbce5bdb26a0800a3d23ed2d&v=4 - url: https://github.com/israteneda From d5d6eebd407f689d3bb52121fd05f750fbcb0633 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Mar 2022 20:20:21 +0000 Subject: [PATCH 410/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bbe6ce221..2a8955a4a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#4699](https://github.com/tiangolo/fastapi/pull/4699) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🐛 Fix FastAPI People generation to include missing file in commit. PR [#4695](https://github.com/tiangolo/fastapi/pull/4695) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Classiq sponsor links. PR [#4688](https://github.com/tiangolo/fastapi/pull/4688) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add Classiq sponsor. PR [#4671](https://github.com/tiangolo/fastapi/pull/4671) by [@tiangolo](https://github.com/tiangolo). From aec2d26baca77857777dd25c6ad5121e1685ac31 Mon Sep 17 00:00:00 2001 From: Sarmast Bilawal Khuhro Date: Thu, 17 Mar 2022 21:24:34 +0100 Subject: [PATCH 411/814] =?UTF-8?q?=E2=9C=8F=20Reword=20sentence=20about?= =?UTF-8?q?=20handling=20errors=20(#1993)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/handling-errors.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/en/docs/tutorial/handling-errors.md b/docs/en/docs/tutorial/handling-errors.md index 89f96176d..82e166266 100644 --- a/docs/en/docs/tutorial/handling-errors.md +++ b/docs/en/docs/tutorial/handling-errors.md @@ -252,9 +252,7 @@ from starlette.exceptions import HTTPException as StarletteHTTPException ### Re-use **FastAPI**'s exception handlers -You could also just want to use the exception somehow, but then use the same default exception handlers from **FastAPI**. - -You can import and re-use the default exception handlers from `fastapi.exception_handlers`: +If you want to use the exception along with the same default exception handlers from **FastAPI**, You can import and re-use the default exception handlers from `fastapi.exception_handlers`: ```Python hl_lines="2-5 15 21" {!../../../docs_src/handling_errors/tutorial006.py!} From bab5c201dae5ffcdd9e7452d2cab4cc51acc556e Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Mar 2022 20:25:09 +0000 Subject: [PATCH 412/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2a8955a4a..c71685fe4 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Reword sentence about handling errors. PR [#1993](https://github.com/tiangolo/fastapi/pull/1993) by [@khuhroproeza](https://github.com/khuhroproeza). * 👥 Update FastAPI People. PR [#4699](https://github.com/tiangolo/fastapi/pull/4699) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🐛 Fix FastAPI People generation to include missing file in commit. PR [#4695](https://github.com/tiangolo/fastapi/pull/4695) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Classiq sponsor links. PR [#4688](https://github.com/tiangolo/fastapi/pull/4688) by [@tiangolo](https://github.com/tiangolo). From 2b6f1585ec8a2084195363d76a0dfeda2d77657e Mon Sep 17 00:00:00 2001 From: Amin Alaee Date: Fri, 18 Mar 2022 17:24:19 +0100 Subject: [PATCH 413/814] =?UTF-8?q?=F0=9F=8C=90=20Start=20Persian/Farsi=20?= =?UTF-8?q?translations=20(#4243)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/az/mkdocs.yml | 3 + docs/de/mkdocs.yml | 3 + docs/en/mkdocs.yml | 3 + docs/es/mkdocs.yml | 3 + docs/fa/docs/index.md | 468 +++++++++++++++++++++++++++++++++++ docs/fa/mkdocs.yml | 132 ++++++++++ docs/fa/overrides/.gitignore | 0 docs/fr/mkdocs.yml | 3 + docs/id/mkdocs.yml | 3 + docs/it/mkdocs.yml | 3 + docs/ja/mkdocs.yml | 3 + docs/ko/mkdocs.yml | 3 + docs/pl/mkdocs.yml | 3 + docs/pt/mkdocs.yml | 3 + docs/ru/mkdocs.yml | 3 + docs/sq/mkdocs.yml | 3 + docs/tr/mkdocs.yml | 3 + docs/uk/mkdocs.yml | 3 + docs/zh/mkdocs.yml | 3 + 19 files changed, 648 insertions(+) create mode 100644 docs/fa/docs/index.md create mode 100644 docs/fa/mkdocs.yml create mode 100644 docs/fa/overrides/.gitignore diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index 66220f63e..06aad80c4 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -97,6 +98,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 360fa8c4a..80b360028 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -98,6 +99,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index e2a779872..12ced5f92 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -204,6 +205,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index a4bc41154..c3b26dcc2 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -107,6 +108,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/fa/docs/index.md b/docs/fa/docs/index.md new file mode 100644 index 000000000..0070de179 --- /dev/null +++ b/docs/fa/docs/index.md @@ -0,0 +1,468 @@ + +{!../../../docs/missing-translation.md!} + + +

+ FastAPI +

+

+ FastAPI framework, high performance, easy to learn, fast to code, ready for production +

+

+ + Test + + + Coverage + + + Package version + + + Supported Python versions + +

+ +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: https://github.com/tiangolo/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. + +The key features are: + +* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). + +* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * +* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. + +* estimation based on tests on an internal development team, building production applications. + +## Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + +## Opinions + +"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" + +
Kabir Khan - Microsoft (ref)
+ +--- + +"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" + +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
+ +--- + +"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" + +
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
+ +--- + +"_I’m over the moon excited about **FastAPI**. It’s so fun!_" + +
Brian Okken - Python Bytes podcast host (ref)
+ +--- + +"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" + +
Timothy Crosley - Hug creator (ref)
+ +--- + +"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" + +"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" + +
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +## **Typer**, the FastAPI of CLIs + + + +If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. + +**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 + +## Requirements + +Python 3.6+ + +FastAPI stands on the shoulders of giants: + +* Starlette for the web parts. +* Pydantic for the data parts. + +## Installation + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+ +You will also need an ASGI server, for production such as Uvicorn or Hypercorn. + +
+ +```console +$ pip install "uvicorn[standard]" + +---> 100% +``` + +
+ +## Example + +### Create it + +* Create a file `main.py` with: + +```Python +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +
+Or use async def... + +If your code uses `async` / `await`, use `async def`: + +```Python hl_lines="9 14" +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +**Note**: + +If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. + +
+ +### Run it + +Run the server with: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+About the command uvicorn main:app --reload... + +The command `uvicorn main:app` refers to: + +* `main`: the file `main.py` (the Python "module"). +* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. +* `--reload`: make the server restart after code changes. Only do this for development. + +
+ +### Check it + +Open your browser at http://127.0.0.1:8000/items/5?q=somequery. + +You will see the JSON response as: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +You already created an API that: + +* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. +* Both _paths_ take `GET` operations (also known as HTTP _methods_). +* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. +* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. + +### Interactive API docs + +Now go to http://127.0.0.1:8000/docs. + +You will see the automatic interactive API documentation (provided by Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Alternative API docs + +And now, go to http://127.0.0.1:8000/redoc. + +You will see the alternative automatic documentation (provided by ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Example upgrade + +Now modify the file `main.py` to receive a body from a `PUT` request. + +Declare the body using standard Python types, thanks to Pydantic. + +```Python hl_lines="4 9-12 25-27" +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Optional[bool] = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} +``` + +The server should reload automatically (because you added `--reload` to the `uvicorn` command above). + +### Interactive API docs upgrade + +Now go to http://127.0.0.1:8000/docs. + +* The interactive API documentation will be automatically updated, including the new body: + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) + +* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) + +### Alternative API docs upgrade + +And now, go to http://127.0.0.1:8000/redoc. + +* The alternative documentation will also reflect the new query parameter and body: + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Recap + +In summary, you declare **once** the types of parameters, body, etc. as function parameters. + +You do that with standard modern Python types. + +You don't have to learn a new syntax, the methods or classes of a specific library, etc. + +Just standard **Python 3.6+**. + +For example, for an `int`: + +```Python +item_id: int +``` + +or for a more complex `Item` model: + +```Python +item: Item +``` + +...and with that single declaration you get: + +* Editor support, including: + * Completion. + * Type checks. +* Validation of data: + * Automatic and clear errors when the data is invalid. + * Validation even for deeply nested JSON objects. +* Conversion of input data: coming from the network to Python data and types. Reading from: + * JSON. + * Path parameters. + * Query parameters. + * Cookies. + * Headers. + * Forms. + * Files. +* Conversion of output data: converting from Python data and types to network data (as JSON): + * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). + * `datetime` objects. + * `UUID` objects. + * Database models. + * ...and many more. +* Automatic interactive API documentation, including 2 alternative user interfaces: + * Swagger UI. + * ReDoc. + +--- + +Coming back to the previous code example, **FastAPI** will: + +* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. +* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. + * If it is not, the client will see a useful, clear error. +* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. + * As the `q` parameter is declared with `= None`, it is optional. + * Without the `None` it would be required (as is the body in the case with `PUT`). +* For `PUT` requests to `/items/{item_id}`, Read the body as JSON: + * Check that it has a required attribute `name` that should be a `str`. + * Check that it has a required attribute `price` that has to be a `float`. + * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. + * All this would also work for deeply nested JSON objects. +* Convert from and to JSON automatically. +* Document everything with OpenAPI, that can be used by: + * Interactive documentation systems. + * Automatic client code generation systems, for many languages. +* Provide 2 interactive documentation web interfaces directly. + +--- + +We just scratched the surface, but you already get the idea of how it all works. + +Try changing the line with: + +```Python + return {"item_name": item.name, "item_id": item_id} +``` + +...from: + +```Python + ... "item_name": item.name ... +``` + +...to: + +```Python + ... "item_price": item.price ... +``` + +...and see how your editor will auto-complete the attributes and know their types: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +For a more complete example including more features, see the Tutorial - User Guide. + +**Spoiler alert**: the tutorial - user guide includes: + +* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. +* How to set **validation constraints** as `maximum_length` or `regex`. +* A very powerful and easy to use **Dependency Injection** system. +* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. +* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). +* **GraphQL** integration with Strawberry and other libraries. +* Many extra features (thanks to Starlette) as: + * **WebSockets** + * extremely easy tests based on `requests` and `pytest` + * **CORS** + * **Cookie Sessions** + * ...and more. + +## Performance + +Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) + +To understand more about it, see the section Benchmarks. + +## Optional Dependencies + +Used by Pydantic: + +* ujson - for faster JSON "parsing". +* email_validator - for email validation. + +Used by Starlette: + +* requests - Required if you want to use the `TestClient`. +* jinja2 - Required if you want to use the default template configuration. +* python-multipart - Required if you want to support form "parsing", with `request.form()`. +* itsdangerous - Required for `SessionMiddleware` support. +* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). +* ujson - Required if you want to use `UJSONResponse`. + +Used by FastAPI / Starlette: + +* uvicorn - for the server that loads and serves your application. +* orjson - Required if you want to use `ORJSONResponse`. + +You can install all of these with `pip install "fastapi[all]"`. + +## License + +This project is licensed under the terms of the MIT license. diff --git a/docs/fa/mkdocs.yml b/docs/fa/mkdocs.yml new file mode 100644 index 000000000..83cf81e22 --- /dev/null +++ b/docs/fa/mkdocs.yml @@ -0,0 +1,132 @@ +site_name: FastAPI +site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production +site_url: https://fastapi.tiangolo.com/fa/ +theme: + name: material + custom_dir: overrides + palette: + - scheme: default + primary: teal + accent: amber + toggle: + icon: material/lightbulb + name: Switch to light mode + - scheme: slate + primary: teal + accent: amber + toggle: + icon: material/lightbulb-outline + name: Switch to dark mode + features: + - search.suggest + - search.highlight + - content.tabs.link + icon: + repo: fontawesome/brands/github-alt + logo: https://fastapi.tiangolo.com/img/icon-white.svg + favicon: https://fastapi.tiangolo.com/img/favicon.png + language: fa +repo_name: tiangolo/fastapi +repo_url: https://github.com/tiangolo/fastapi +edit_uri: '' +google_analytics: +- UA-133183413-1 +- auto +plugins: +- search +- markdownextradata: + data: data +nav: +- FastAPI: index.md +- Languages: + - en: / + - az: /az/ + - de: /de/ + - es: /es/ + - fa: /fa/ + - fr: /fr/ + - id: /id/ + - it: /it/ + - ja: /ja/ + - ko: /ko/ + - pl: /pl/ + - pt: /pt/ + - ru: /ru/ + - sq: /sq/ + - tr: /tr/ + - uk: /uk/ + - zh: /zh/ +markdown_extensions: +- toc: + permalink: true +- markdown.extensions.codehilite: + guess_lang: false +- mdx_include: + base_path: docs +- admonition +- codehilite +- extra +- pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format '' +- pymdownx.tabbed +extra: + social: + - icon: fontawesome/brands/github-alt + link: https://github.com/tiangolo/fastapi + - icon: fontawesome/brands/discord + link: https://discord.gg/VQjSZaeJmf + - icon: fontawesome/brands/twitter + link: https://twitter.com/fastapi + - icon: fontawesome/brands/linkedin + link: https://www.linkedin.com/in/tiangolo + - icon: fontawesome/brands/dev + link: https://dev.to/tiangolo + - icon: fontawesome/brands/medium + link: https://medium.com/@tiangolo + - icon: fontawesome/solid/globe + link: https://tiangolo.com + alternate: + - link: / + name: en - English + - link: /az/ + name: az + - link: /de/ + name: de + - link: /es/ + name: es - español + - link: /fa/ + name: fa + - link: /fr/ + name: fr - français + - link: /id/ + name: id + - link: /it/ + name: it - italiano + - link: /ja/ + name: ja - 日本語 + - link: /ko/ + name: ko - 한국어 + - link: /pl/ + name: pl + - link: /pt/ + name: pt - português + - link: /ru/ + name: ru - русский язык + - link: /sq/ + name: sq - shqip + - link: /tr/ + name: tr - Türkçe + - link: /uk/ + name: uk - українська мова + - link: /zh/ + name: zh - 汉语 +extra_css: +- https://fastapi.tiangolo.com/css/termynal.css +- https://fastapi.tiangolo.com/css/custom.css +- https://fastapi.tiangolo.com/css/rtl.css +extra_javascript: +- https://fastapi.tiangolo.com/js/termynal.js +- https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/fa/overrides/.gitignore b/docs/fa/overrides/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index ff16e1d78..b14764c66 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -112,6 +113,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index d70d2b3c3..e40218422 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -97,6 +98,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index e6d01fbde..da1ac00b7 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -97,6 +98,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 39fd8a211..832078186 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -137,6 +138,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 1d4d30913..8b7cb9c06 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -107,6 +108,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 3c1351a12..da68165c7 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -97,6 +98,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index f202f306d..522b3c86a 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -117,6 +118,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 6e17c287e..643f0aa70 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -97,6 +98,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index d9c3dad4c..e4a1724c3 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -97,6 +98,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index f6ed7f5b9..041c11b97 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -100,6 +101,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index d0de8cc0e..2d704b989 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -97,6 +98,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 1d050fddd..f424b117b 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -40,6 +40,7 @@ nav: - az: /az/ - de: /de/ - es: /es/ + - fa: /fa/ - fr: /fr/ - id: /id/ - it: /it/ @@ -148,6 +149,8 @@ extra: name: de - link: /es/ name: es - español + - link: /fa/ + name: fa - link: /fr/ name: fr - français - link: /id/ From bd94d313c910e505b00a2338505272992de1769a Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 18 Mar 2022 16:24:54 +0000 Subject: [PATCH 414/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c71685fe4..d71a1d094 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Start Persian/Farsi translations. PR [#4243](https://github.com/tiangolo/fastapi/pull/4243) by [@aminalaee](https://github.com/aminalaee). * ✏ Reword sentence about handling errors. PR [#1993](https://github.com/tiangolo/fastapi/pull/1993) by [@khuhroproeza](https://github.com/khuhroproeza). * 👥 Update FastAPI People. PR [#4699](https://github.com/tiangolo/fastapi/pull/4699) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🐛 Fix FastAPI People generation to include missing file in commit. PR [#4695](https://github.com/tiangolo/fastapi/pull/4695) by [@tiangolo](https://github.com/tiangolo). From d820267cde66b3f4e42f509a03e8ffb464d443bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 18 Mar 2022 11:37:14 -0500 Subject: [PATCH 415/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20configuration=20to?= =?UTF-8?q?=20notify=20Dutch=20translations=20(#4702)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/notify-translations/app/translations.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/notify-translations/app/translations.yml b/.github/actions/notify-translations/app/translations.yml index decd63498..f0bccd470 100644 --- a/.github/actions/notify-translations/app/translations.yml +++ b/.github/actions/notify-translations/app/translations.yml @@ -13,3 +13,4 @@ pl: 3169 de: 3716 id: 3717 az: 3994 +nl: 4701 From fc96370ce30b7646fbb0637e7bae57f5caff6900 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 18 Mar 2022 16:37:49 +0000 Subject: [PATCH 416/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d71a1d094..da1cd5c32 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add configuration to notify Dutch translations. PR [#4702](https://github.com/tiangolo/fastapi/pull/4702) by [@tiangolo](https://github.com/tiangolo). * 🌐 Start Persian/Farsi translations. PR [#4243](https://github.com/tiangolo/fastapi/pull/4243) by [@aminalaee](https://github.com/aminalaee). * ✏ Reword sentence about handling errors. PR [#1993](https://github.com/tiangolo/fastapi/pull/1993) by [@khuhroproeza](https://github.com/khuhroproeza). * 👥 Update FastAPI People. PR [#4699](https://github.com/tiangolo/fastapi/pull/4699) by [@github-actions[bot]](https://github.com/apps/github-actions). From 5c842586c239e565d44a5f0e0a0e48fb88303925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 18 Mar 2022 11:47:54 -0500 Subject: [PATCH 417/814] =?UTF-8?q?=F0=9F=8C=90=20Start=20Dutch=20translat?= =?UTF-8?q?ions=20(#4703)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/az/mkdocs.yml | 3 + docs/de/mkdocs.yml | 3 + docs/en/mkdocs.yml | 3 + docs/es/mkdocs.yml | 3 + docs/fa/mkdocs.yml | 13 +- docs/fr/mkdocs.yml | 3 + docs/id/mkdocs.yml | 3 + docs/it/mkdocs.yml | 3 + docs/ja/mkdocs.yml | 3 + docs/ko/mkdocs.yml | 3 + docs/nl/docs/index.md | 468 +++++++++++++++++++++++++++++++++++ docs/nl/mkdocs.yml | 135 ++++++++++ docs/nl/overrides/.gitignore | 0 docs/pl/mkdocs.yml | 3 + docs/pt/mkdocs.yml | 3 + docs/ru/mkdocs.yml | 3 + docs/sq/mkdocs.yml | 3 + docs/tr/mkdocs.yml | 3 + docs/uk/mkdocs.yml | 3 + docs/zh/mkdocs.yml | 3 + 20 files changed, 659 insertions(+), 5 deletions(-) create mode 100644 docs/nl/docs/index.md create mode 100644 docs/nl/mkdocs.yml create mode 100644 docs/nl/overrides/.gitignore diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index 06aad80c4..58bbb0758 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -110,6 +111,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 80b360028..1242af504 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -111,6 +112,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 12ced5f92..e7aa40def 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -217,6 +218,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index c3b26dcc2..eb7538cf4 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -120,6 +121,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/fa/mkdocs.yml b/docs/fa/mkdocs.yml index 83cf81e22..6fb3891b7 100644 --- a/docs/fa/mkdocs.yml +++ b/docs/fa/mkdocs.yml @@ -29,9 +29,6 @@ theme: repo_name: tiangolo/fastapi repo_url: https://github.com/tiangolo/fastapi edit_uri: '' -google_analytics: -- UA-133183413-1 -- auto plugins: - search - markdownextradata: @@ -49,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -71,8 +69,12 @@ markdown_extensions: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed +- pymdownx.tabbed: + alternate_style: true extra: + analytics: + provider: google + property: UA-133183413-1 social: - icon: fontawesome/brands/github-alt link: https://github.com/tiangolo/fastapi @@ -109,6 +111,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ @@ -126,7 +130,6 @@ extra: extra_css: - https://fastapi.tiangolo.com/css/termynal.css - https://fastapi.tiangolo.com/css/custom.css -- https://fastapi.tiangolo.com/css/rtl.css extra_javascript: - https://fastapi.tiangolo.com/js/termynal.js - https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index b14764c66..d2681f8d5 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -125,6 +126,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index e40218422..0c60fecd9 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -110,6 +111,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index da1ac00b7..3bf3d7396 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -110,6 +111,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 832078186..f972eb0ff 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -150,6 +151,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 8b7cb9c06..1e7d60dbd 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -120,6 +121,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/nl/docs/index.md b/docs/nl/docs/index.md new file mode 100644 index 000000000..0070de179 --- /dev/null +++ b/docs/nl/docs/index.md @@ -0,0 +1,468 @@ + +{!../../../docs/missing-translation.md!} + + +

+ FastAPI +

+

+ FastAPI framework, high performance, easy to learn, fast to code, ready for production +

+

+ + Test + + + Coverage + + + Package version + + + Supported Python versions + +

+ +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: https://github.com/tiangolo/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. + +The key features are: + +* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). + +* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * +* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. + +* estimation based on tests on an internal development team, building production applications. + +## Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + +## Opinions + +"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" + +
Kabir Khan - Microsoft (ref)
+ +--- + +"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" + +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
+ +--- + +"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" + +
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
+ +--- + +"_I’m over the moon excited about **FastAPI**. It’s so fun!_" + +
Brian Okken - Python Bytes podcast host (ref)
+ +--- + +"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" + +
Timothy Crosley - Hug creator (ref)
+ +--- + +"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" + +"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" + +
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +## **Typer**, the FastAPI of CLIs + + + +If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. + +**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 + +## Requirements + +Python 3.6+ + +FastAPI stands on the shoulders of giants: + +* Starlette for the web parts. +* Pydantic for the data parts. + +## Installation + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+ +You will also need an ASGI server, for production such as Uvicorn or Hypercorn. + +
+ +```console +$ pip install "uvicorn[standard]" + +---> 100% +``` + +
+ +## Example + +### Create it + +* Create a file `main.py` with: + +```Python +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +
+Or use async def... + +If your code uses `async` / `await`, use `async def`: + +```Python hl_lines="9 14" +from typing import Optional + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} +``` + +**Note**: + +If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. + +
+ +### Run it + +Run the server with: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+About the command uvicorn main:app --reload... + +The command `uvicorn main:app` refers to: + +* `main`: the file `main.py` (the Python "module"). +* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. +* `--reload`: make the server restart after code changes. Only do this for development. + +
+ +### Check it + +Open your browser at http://127.0.0.1:8000/items/5?q=somequery. + +You will see the JSON response as: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +You already created an API that: + +* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. +* Both _paths_ take `GET` operations (also known as HTTP _methods_). +* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. +* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. + +### Interactive API docs + +Now go to http://127.0.0.1:8000/docs. + +You will see the automatic interactive API documentation (provided by Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Alternative API docs + +And now, go to http://127.0.0.1:8000/redoc. + +You will see the alternative automatic documentation (provided by ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Example upgrade + +Now modify the file `main.py` to receive a body from a `PUT` request. + +Declare the body using standard Python types, thanks to Pydantic. + +```Python hl_lines="4 9-12 25-27" +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Optional[bool] = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Optional[str] = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} +``` + +The server should reload automatically (because you added `--reload` to the `uvicorn` command above). + +### Interactive API docs upgrade + +Now go to http://127.0.0.1:8000/docs. + +* The interactive API documentation will be automatically updated, including the new body: + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) + +* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) + +### Alternative API docs upgrade + +And now, go to http://127.0.0.1:8000/redoc. + +* The alternative documentation will also reflect the new query parameter and body: + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Recap + +In summary, you declare **once** the types of parameters, body, etc. as function parameters. + +You do that with standard modern Python types. + +You don't have to learn a new syntax, the methods or classes of a specific library, etc. + +Just standard **Python 3.6+**. + +For example, for an `int`: + +```Python +item_id: int +``` + +or for a more complex `Item` model: + +```Python +item: Item +``` + +...and with that single declaration you get: + +* Editor support, including: + * Completion. + * Type checks. +* Validation of data: + * Automatic and clear errors when the data is invalid. + * Validation even for deeply nested JSON objects. +* Conversion of input data: coming from the network to Python data and types. Reading from: + * JSON. + * Path parameters. + * Query parameters. + * Cookies. + * Headers. + * Forms. + * Files. +* Conversion of output data: converting from Python data and types to network data (as JSON): + * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). + * `datetime` objects. + * `UUID` objects. + * Database models. + * ...and many more. +* Automatic interactive API documentation, including 2 alternative user interfaces: + * Swagger UI. + * ReDoc. + +--- + +Coming back to the previous code example, **FastAPI** will: + +* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. +* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. + * If it is not, the client will see a useful, clear error. +* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. + * As the `q` parameter is declared with `= None`, it is optional. + * Without the `None` it would be required (as is the body in the case with `PUT`). +* For `PUT` requests to `/items/{item_id}`, Read the body as JSON: + * Check that it has a required attribute `name` that should be a `str`. + * Check that it has a required attribute `price` that has to be a `float`. + * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. + * All this would also work for deeply nested JSON objects. +* Convert from and to JSON automatically. +* Document everything with OpenAPI, that can be used by: + * Interactive documentation systems. + * Automatic client code generation systems, for many languages. +* Provide 2 interactive documentation web interfaces directly. + +--- + +We just scratched the surface, but you already get the idea of how it all works. + +Try changing the line with: + +```Python + return {"item_name": item.name, "item_id": item_id} +``` + +...from: + +```Python + ... "item_name": item.name ... +``` + +...to: + +```Python + ... "item_price": item.price ... +``` + +...and see how your editor will auto-complete the attributes and know their types: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +For a more complete example including more features, see the Tutorial - User Guide. + +**Spoiler alert**: the tutorial - user guide includes: + +* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. +* How to set **validation constraints** as `maximum_length` or `regex`. +* A very powerful and easy to use **Dependency Injection** system. +* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. +* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). +* **GraphQL** integration with Strawberry and other libraries. +* Many extra features (thanks to Starlette) as: + * **WebSockets** + * extremely easy tests based on `requests` and `pytest` + * **CORS** + * **Cookie Sessions** + * ...and more. + +## Performance + +Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) + +To understand more about it, see the section Benchmarks. + +## Optional Dependencies + +Used by Pydantic: + +* ujson - for faster JSON "parsing". +* email_validator - for email validation. + +Used by Starlette: + +* requests - Required if you want to use the `TestClient`. +* jinja2 - Required if you want to use the default template configuration. +* python-multipart - Required if you want to support form "parsing", with `request.form()`. +* itsdangerous - Required for `SessionMiddleware` support. +* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). +* ujson - Required if you want to use `UJSONResponse`. + +Used by FastAPI / Starlette: + +* uvicorn - for the server that loads and serves your application. +* orjson - Required if you want to use `ORJSONResponse`. + +You can install all of these with `pip install "fastapi[all]"`. + +## License + +This project is licensed under the terms of the MIT license. diff --git a/docs/nl/mkdocs.yml b/docs/nl/mkdocs.yml new file mode 100644 index 000000000..c853216f5 --- /dev/null +++ b/docs/nl/mkdocs.yml @@ -0,0 +1,135 @@ +site_name: FastAPI +site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production +site_url: https://fastapi.tiangolo.com/nl/ +theme: + name: material + custom_dir: overrides + palette: + - scheme: default + primary: teal + accent: amber + toggle: + icon: material/lightbulb + name: Switch to light mode + - scheme: slate + primary: teal + accent: amber + toggle: + icon: material/lightbulb-outline + name: Switch to dark mode + features: + - search.suggest + - search.highlight + - content.tabs.link + icon: + repo: fontawesome/brands/github-alt + logo: https://fastapi.tiangolo.com/img/icon-white.svg + favicon: https://fastapi.tiangolo.com/img/favicon.png + language: nl +repo_name: tiangolo/fastapi +repo_url: https://github.com/tiangolo/fastapi +edit_uri: '' +plugins: +- search +- markdownextradata: + data: data +nav: +- FastAPI: index.md +- Languages: + - en: / + - az: /az/ + - de: /de/ + - es: /es/ + - fa: /fa/ + - fr: /fr/ + - id: /id/ + - it: /it/ + - ja: /ja/ + - ko: /ko/ + - nl: /nl/ + - pl: /pl/ + - pt: /pt/ + - ru: /ru/ + - sq: /sq/ + - tr: /tr/ + - uk: /uk/ + - zh: /zh/ +markdown_extensions: +- toc: + permalink: true +- markdown.extensions.codehilite: + guess_lang: false +- mdx_include: + base_path: docs +- admonition +- codehilite +- extra +- pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format '' +- pymdownx.tabbed: + alternate_style: true +extra: + analytics: + provider: google + property: UA-133183413-1 + social: + - icon: fontawesome/brands/github-alt + link: https://github.com/tiangolo/fastapi + - icon: fontawesome/brands/discord + link: https://discord.gg/VQjSZaeJmf + - icon: fontawesome/brands/twitter + link: https://twitter.com/fastapi + - icon: fontawesome/brands/linkedin + link: https://www.linkedin.com/in/tiangolo + - icon: fontawesome/brands/dev + link: https://dev.to/tiangolo + - icon: fontawesome/brands/medium + link: https://medium.com/@tiangolo + - icon: fontawesome/solid/globe + link: https://tiangolo.com + alternate: + - link: / + name: en - English + - link: /az/ + name: az + - link: /de/ + name: de + - link: /es/ + name: es - español + - link: /fa/ + name: fa + - link: /fr/ + name: fr - français + - link: /id/ + name: id + - link: /it/ + name: it - italiano + - link: /ja/ + name: ja - 日本語 + - link: /ko/ + name: ko - 한국어 + - link: /nl/ + name: nl + - link: /pl/ + name: pl + - link: /pt/ + name: pt - português + - link: /ru/ + name: ru - русский язык + - link: /sq/ + name: sq - shqip + - link: /tr/ + name: tr - Türkçe + - link: /uk/ + name: uk - українська мова + - link: /zh/ + name: zh - 汉语 +extra_css: +- https://fastapi.tiangolo.com/css/termynal.css +- https://fastapi.tiangolo.com/css/custom.css +extra_javascript: +- https://fastapi.tiangolo.com/js/termynal.js +- https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/nl/overrides/.gitignore b/docs/nl/overrides/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index da68165c7..67b41fe53 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -110,6 +111,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 522b3c86a..4861602e4 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -130,6 +131,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 643f0aa70..213f941d7 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -110,6 +111,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index e4a1724c3..a61f49bc9 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -110,6 +111,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 041c11b97..dd52d7fcc 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -113,6 +114,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index 2d704b989..971a182db 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -110,6 +111,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index f424b117b..408166489 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -46,6 +46,7 @@ nav: - it: /it/ - ja: /ja/ - ko: /ko/ + - nl: /nl/ - pl: /pl/ - pt: /pt/ - ru: /ru/ @@ -161,6 +162,8 @@ extra: name: ja - 日本語 - link: /ko/ name: ko - 한국어 + - link: /nl/ + name: nl - link: /pl/ name: pl - link: /pt/ From eddbae948f04e13fe412dc45a569d10e34b698a4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 18 Mar 2022 16:48:49 +0000 Subject: [PATCH 418/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index da1cd5c32..b0445a4ef 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Start Dutch translations. PR [#4703](https://github.com/tiangolo/fastapi/pull/4703) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add configuration to notify Dutch translations. PR [#4702](https://github.com/tiangolo/fastapi/pull/4702) by [@tiangolo](https://github.com/tiangolo). * 🌐 Start Persian/Farsi translations. PR [#4243](https://github.com/tiangolo/fastapi/pull/4243) by [@aminalaee](https://github.com/aminalaee). * ✏ Reword sentence about handling errors. PR [#1993](https://github.com/tiangolo/fastapi/pull/1993) by [@khuhroproeza](https://github.com/khuhroproeza). From e1d0e3874b86bc2d12c0fb720fd35719b985abae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 1 Apr 2022 18:01:51 -0500 Subject: [PATCH 419/814] =?UTF-8?q?=E2=9E=96=20Temporarily=20remove=20type?= =?UTF-8?q?r-cli=20from=20dependencies=20and=20upgrade=20Black=20(#4754)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 6 ++++-- tests/test_tutorial/test_request_files/test_tutorial001.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 77c01322f..46a655a48 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ test = [ "pytest-cov >=2.12.0,<4.0.0", "mypy ==0.910", "flake8 >=3.8.3,<4.0.0", - "black ==21.9b0", + "black == 22.3.0", "isort >=5.0.6,<6.0.0", "requests >=2.24.0,<3.0.0", "httpx >=0.14.0,<0.19.0", @@ -74,7 +74,9 @@ doc = [ "mkdocs-material >=8.1.4,<9.0.0", "mdx-include >=1.4.1,<2.0.0", "mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0", - "typer-cli >=0.0.12,<0.0.13", + # TODO: upgrade and enable typer-cli once it supports Click 8.x.x + # "typer-cli >=0.0.12,<0.0.13", + "typer >=0.4.1,<0.5.0", "pyyaml >=5.3.1,<6.0.0" ] dev = [ diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py index c1537f445..841116e30 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001.py @@ -162,7 +162,7 @@ def test_post_file(tmp_path): def test_post_large_file(tmp_path): - default_pydantic_max_size = 2 ** 16 + default_pydantic_max_size = 2**16 path = tmp_path / "test.txt" path.write_bytes(b"x" * (default_pydantic_max_size + 1)) From 233214795a93178518292c87f5dd90baa7fcb76b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Apr 2022 18:02:17 -0500 Subject: [PATCH 420/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#4752)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/github_sponsors.yml | 42 ++++-------------- docs/en/data/people.yml | 74 ++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 66 deletions(-) diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml index 1d8dc9984..42339d262 100644 --- a/docs/en/data/github_sponsors.yml +++ b/docs/en/data/github_sponsors.yml @@ -38,21 +38,18 @@ sponsors: - login: BoostryJP avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4 url: https://github.com/BoostryJP -- - login: bolau - avatarUrl: https://avatars.githubusercontent.com/u/488733?u=902c9f9b85db0e21aca11bf30d904ee8e87fffef&v=4 - url: https://github.com/bolau - - login: johnadjei +- - login: johnadjei avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4 url: https://github.com/johnadjei - login: HiredScore avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4 url: https://github.com/HiredScore + - login: spackle0 + avatarUrl: https://avatars.githubusercontent.com/u/6148423?u=750e21b7366c0de69c305a8bcda1365d921ae477&v=4 + url: https://github.com/spackle0 - login: wdwinslow avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 url: https://github.com/wdwinslow -- - login: orvad - avatarUrl: https://avatars.githubusercontent.com/u/7700522?v=4 - url: https://github.com/orvad - - login: moellenbeck avatarUrl: https://avatars.githubusercontent.com/u/169372?v=4 url: https://github.com/moellenbeck @@ -65,9 +62,6 @@ sponsors: - login: tizz98 avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4 url: https://github.com/tizz98 - - login: mntolia - avatarUrl: https://avatars.githubusercontent.com/u/10390224?v=4 - url: https://github.com/mntolia - login: jmaralc avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4 url: https://github.com/jmaralc @@ -83,6 +77,9 @@ sponsors: - login: A-Edge avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4 url: https://github.com/A-Edge +- - login: hcristea + avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=61d7a4fcf846983a4606788eac25e1c6c1209ba8&v=4 + url: https://github.com/hcristea - - login: samuelcolvin avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4 url: https://github.com/samuelcolvin @@ -278,9 +275,6 @@ sponsors: - login: dudikbender avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4 url: https://github.com/dudikbender - - login: jorge4larcon - avatarUrl: https://avatars.githubusercontent.com/u/54189123?v=4 - url: https://github.com/jorge4larcon - login: daisuke8000 avatarUrl: https://avatars.githubusercontent.com/u/55035595?u=5025e379cd3655ae1a96039efc85223a873d2e38&v=4 url: https://github.com/daisuke8000 @@ -314,9 +308,6 @@ sponsors: - - login: '837477' avatarUrl: https://avatars.githubusercontent.com/u/37999795?u=543b0bd0e8f283db0fc50754e5d13f6afba8cbea&v=4 url: https://github.com/837477 - - login: naheedroomy - avatarUrl: https://avatars.githubusercontent.com/u/46345736?v=4 - url: https://github.com/naheedroomy - - login: linux-china avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4 url: https://github.com/linux-china @@ -333,7 +324,7 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/144028?u=defda4f90e93429221cc667500944abde60ebe4a&v=4 url: https://github.com/bryanculbertson - login: yourkin - avatarUrl: https://avatars.githubusercontent.com/u/178984?u=163b8c6d9b2d240164ade467cbc9efb16d2432e4&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/178984?u=fa7c3503b47bf16405b96d21554bc59f07a65523&v=4 url: https://github.com/yourkin - login: slafs avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4 @@ -404,9 +395,6 @@ sponsors: - login: unredundant avatarUrl: https://avatars.githubusercontent.com/u/5607577?u=57dd0023365bec03f4fc566df6b81bc0a264a47d&v=4 url: https://github.com/unredundant - - login: Baghdady92 - avatarUrl: https://avatars.githubusercontent.com/u/5708590?v=4 - url: https://github.com/Baghdady92 - login: holec avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4 url: https://github.com/holec @@ -423,7 +411,7 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/9358572?u=4a38ef72dd39e8b262bd5ab819992128b55c52b4&v=4 url: https://github.com/VivianSolide - login: xncbf - avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=ded074228b35b46a76b980d2dda522e45277f96d&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=866a1311e4bd3ec5ae84185c4fcc99f397c883d7&v=4 url: https://github.com/xncbf - login: DMantis avatarUrl: https://avatars.githubusercontent.com/u/9536869?v=4 @@ -473,21 +461,12 @@ sponsors: - login: askurihin avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4 url: https://github.com/askurihin - - login: JitPackJoyride - avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=cfad4285914e018af72a3f3c16d8ac11321201e3&v=4 - url: https://github.com/JitPackJoyride - - login: es3n1n - avatarUrl: https://avatars.githubusercontent.com/u/40367813?u=cfaaedfb5da6c2c00330f8ebb041cd39c6a6273d&v=4 - url: https://github.com/es3n1n - login: ilias-ant avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4 url: https://github.com/ilias-ant - login: arrrrrmin avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=fee5739394fea074cb0b66929d070114a5067aae&v=4 url: https://github.com/arrrrrmin - - login: 4heck - avatarUrl: https://avatars.githubusercontent.com/u/45015299?u=7dfb2aca55bff66849396588828a90e090212f81&v=4 - url: https://github.com/4heck - login: igorezersky avatarUrl: https://avatars.githubusercontent.com/u/46680020?u=a20a595c881dbe5658c906fecc7eff125efb4fd4&v=4 url: https://github.com/igorezersky @@ -527,6 +506,3 @@ sponsors: - login: danburonline avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4 url: https://github.com/danburonline - - login: foryourselfand - avatarUrl: https://avatars.githubusercontent.com/u/43334967?u=8abd999f94bc0852d035b765155d5138a88288ce&v=4 - url: https://github.com/foryourselfand diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 591800a35..2f05b3e6b 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,7 +1,7 @@ maintainers: - login: tiangolo answers: 1240 - prs: 289 + prs: 291 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=5cad72c846b7aba2e960546af490edc7375dafc4&v=4 url: https://github.com/tiangolo experts: @@ -54,7 +54,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 url: https://github.com/Dustyposa - login: includeamin - count: 38 + count: 39 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 url: https://github.com/includeamin - login: STeveShary @@ -81,14 +81,14 @@ experts: count: 29 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes +- login: chbndrhnns + count: 26 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: panla count: 26 avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 url: https://github.com/panla -- login: chbndrhnns - count: 25 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns - login: ghandic count: 25 avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 @@ -101,6 +101,10 @@ experts: count: 24 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak +- login: jgould22 + count: 23 + avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 + url: https://github.com/jgould22 - login: acnebs count: 22 avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4 @@ -113,14 +117,14 @@ experts: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 url: https://github.com/chris-allnutt -- login: jgould22 - count: 20 - avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 - url: https://github.com/jgould22 - login: retnikt count: 19 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 url: https://github.com/retnikt +- login: acidjunk + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 + url: https://github.com/acidjunk - login: Hultner count: 18 avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 @@ -133,10 +137,10 @@ experts: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4 url: https://github.com/nkhitrov -- login: acidjunk - count: 16 - avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 - url: https://github.com/acidjunk +- login: harunyasar + count: 17 + avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 + url: https://github.com/harunyasar - login: waynerv count: 16 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 @@ -145,10 +149,6 @@ experts: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 url: https://github.com/dstlny -- login: harunyasar - count: 16 - avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 - url: https://github.com/harunyasar - login: rafsaf count: 15 avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 @@ -199,25 +199,33 @@ experts: url: https://github.com/n8sty last_month_active: - login: yinziyan1206 - count: 7 + count: 5 avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4 url: https://github.com/yinziyan1206 - login: Kludex - count: 6 + count: 5 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex +- login: jd-0001 + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/47495003?u=322eedc0931b62827cf5f239654f77bfaff76b46&v=4 + url: https://github.com/jd-0001 +- login: harunyasar + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 + url: https://github.com/harunyasar +- login: wmcgee3 + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/61711986?u=c51ebfaf8a995019fda8288690f4a009ecf070f0&v=4 + url: https://github.com/wmcgee3 +- login: tasercake + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/13855549?v=4 + url: https://github.com/tasercake - login: jgould22 count: 3 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 url: https://github.com/jgould22 -- login: rafsaf - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 - url: https://github.com/rafsaf -- login: gmanny - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/1166296?v=4 - url: https://github.com/gmanny top_contributors: - login: waynerv count: 25 @@ -317,7 +325,7 @@ top_reviewers: avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 url: https://github.com/ycd - login: cikay - count: 40 + count: 41 avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 url: https://github.com/cikay - login: AdrianDeAnda @@ -328,6 +336,10 @@ top_reviewers: count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 url: https://github.com/ArcLightSlavik +- login: BilalAlpaslan + count: 28 + avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 + url: https://github.com/BilalAlpaslan - login: dmontagu count: 23 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 @@ -348,10 +360,6 @@ top_reviewers: count: 19 avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4 url: https://github.com/0417taehyun -- login: BilalAlpaslan - count: 18 - avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 - url: https://github.com/BilalAlpaslan - login: zy7y count: 17 avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4 From 2c31667407fde305ea52046882879b6547a51b43 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 1 Apr 2022 23:02:28 +0000 Subject: [PATCH 421/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b0445a4ef..4383a4bd5 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ➖ Temporarily remove typer-cli from dependencies and upgrade Black. PR [#4754](https://github.com/tiangolo/fastapi/pull/4754) by [@tiangolo](https://github.com/tiangolo). * 🌐 Start Dutch translations. PR [#4703](https://github.com/tiangolo/fastapi/pull/4703) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add configuration to notify Dutch translations. PR [#4702](https://github.com/tiangolo/fastapi/pull/4702) by [@tiangolo](https://github.com/tiangolo). * 🌐 Start Persian/Farsi translations. PR [#4243](https://github.com/tiangolo/fastapi/pull/4243) by [@aminalaee](https://github.com/aminalaee). From 3fefc83d421a775bca4c0caf1b33ed17fb190978 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 1 Apr 2022 23:02:53 +0000 Subject: [PATCH 422/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4383a4bd5..12bf7f006 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#4752](https://github.com/tiangolo/fastapi/pull/4752) by [@github-actions[bot]](https://github.com/apps/github-actions). * ➖ Temporarily remove typer-cli from dependencies and upgrade Black. PR [#4754](https://github.com/tiangolo/fastapi/pull/4754) by [@tiangolo](https://github.com/tiangolo). * 🌐 Start Dutch translations. PR [#4703](https://github.com/tiangolo/fastapi/pull/4703) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add configuration to notify Dutch translations. PR [#4702](https://github.com/tiangolo/fastapi/pull/4702) by [@tiangolo](https://github.com/tiangolo). From 9e018c322cd05f0fc5e52804efe577e847c8731d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 1 Apr 2022 18:05:06 -0500 Subject: [PATCH 423/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 12bf7f006..d75a220cb 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,12 +2,17 @@ ## Latest Changes -* 👥 Update FastAPI People. PR [#4752](https://github.com/tiangolo/fastapi/pull/4752) by [@github-actions[bot]](https://github.com/apps/github-actions). -* ➖ Temporarily remove typer-cli from dependencies and upgrade Black. PR [#4754](https://github.com/tiangolo/fastapi/pull/4754) by [@tiangolo](https://github.com/tiangolo). +### Translations + * 🌐 Start Dutch translations. PR [#4703](https://github.com/tiangolo/fastapi/pull/4703) by [@tiangolo](https://github.com/tiangolo). -* 🔧 Add configuration to notify Dutch translations. PR [#4702](https://github.com/tiangolo/fastapi/pull/4702) by [@tiangolo](https://github.com/tiangolo). * 🌐 Start Persian/Farsi translations. PR [#4243](https://github.com/tiangolo/fastapi/pull/4243) by [@aminalaee](https://github.com/aminalaee). * ✏ Reword sentence about handling errors. PR [#1993](https://github.com/tiangolo/fastapi/pull/1993) by [@khuhroproeza](https://github.com/khuhroproeza). + +### Internal + +* 👥 Update FastAPI People. PR [#4752](https://github.com/tiangolo/fastapi/pull/4752) by [@github-actions[bot]](https://github.com/apps/github-actions). +* ➖ Temporarily remove typer-cli from dependencies and upgrade Black to unblock Pydantic CI. PR [#4754](https://github.com/tiangolo/fastapi/pull/4754) by [@tiangolo](https://github.com/tiangolo). +* 🔧 Add configuration to notify Dutch translations. PR [#4702](https://github.com/tiangolo/fastapi/pull/4702) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#4699](https://github.com/tiangolo/fastapi/pull/4699) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🐛 Fix FastAPI People generation to include missing file in commit. PR [#4695](https://github.com/tiangolo/fastapi/pull/4695) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Classiq sponsor links. PR [#4688](https://github.com/tiangolo/fastapi/pull/4688) by [@tiangolo](https://github.com/tiangolo). From 26f725d259c5dbe3654f221e608b14412c6b40da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 1 Apr 2022 18:05:52 -0500 Subject: [PATCH 424/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.75?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d75a220cb..4b0ba6c04 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.75.1 + ### Translations * 🌐 Start Dutch translations. PR [#4703](https://github.com/tiangolo/fastapi/pull/4703) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 4bce5f017..0ce2ef720 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.75.0" +__version__ = "0.75.1" from starlette import status as status From cc57bfcf6053aa419e80e12296ed8a053c65128b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 16 Apr 2022 10:18:08 +0200 Subject: [PATCH 425/814] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20Codecov?= =?UTF-8?q?=20GitHub=20Action=20(#4801)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 21ea7c1a8..aee3a994d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,4 +38,4 @@ jobs: - name: Test run: bash scripts/test.sh - name: Upload coverage - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v2 From c4f361c0c47cdb3b0de036ddffe21fce9d031180 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 16 Apr 2022 08:18:43 +0000 Subject: [PATCH 426/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4b0ba6c04..fc23da85d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade Codecov GitHub Action. PR [#4801](https://github.com/tiangolo/fastapi/pull/4801) by [@tiangolo](https://github.com/tiangolo). ## 0.75.1 From acf8a91c258003f3ff487bed0974c479f7136333 Mon Sep 17 00:00:00 2001 From: Alan Wright <31636206+RAlanWright@users.noreply.github.com> Date: Sun, 17 Apr 2022 09:47:14 -0500 Subject: [PATCH 427/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20Swagger=20UI=20-?= =?UTF-8?q?=20swagger-ui-dist@4=20(#4347)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/openapi/docs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py index 1be90d188..d6af17a85 100644 --- a/fastapi/openapi/docs.py +++ b/fastapi/openapi/docs.py @@ -17,8 +17,8 @@ def get_swagger_ui_html( *, openapi_url: str, title: str, - swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui-bundle.js", - swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css", + swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js", + swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css", swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png", oauth2_redirect_url: Optional[str] = None, init_oauth: Optional[Dict[str, Any]] = None, From e1135eddb5d6dbd8a16d699b90e353b04c2700d3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 17 Apr 2022 14:47:55 +0000 Subject: [PATCH 428/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fc23da85d..a449e10a1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade Swagger UI - swagger-ui-dist@4. PR [#4347](https://github.com/tiangolo/fastapi/pull/4347) by [@RAlanWright](https://github.com/RAlanWright). * ⬆️ Upgrade Codecov GitHub Action. PR [#4801](https://github.com/tiangolo/fastapi/pull/4801) by [@tiangolo](https://github.com/tiangolo). ## 0.75.1 From 75af47202907da4ca5969c48b08c94dcfe0036ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 17 Apr 2022 16:55:37 +0200 Subject: [PATCH 429/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a449e10a1..9d9c2a802 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,7 @@ ## Latest Changes -* ⬆ Upgrade Swagger UI - swagger-ui-dist@4. PR [#4347](https://github.com/tiangolo/fastapi/pull/4347) by [@RAlanWright](https://github.com/RAlanWright). +* ⬆ Upgrade Swagger UI - swagger-ui-dist@4. This handles a security issue in Swagger UI itself where it could be possible to inject HTML into Swagger UI. Please upgrade as soon as you can, in particular if you expose your Swagger UI (`/docs`) publicly to non-expert users. PR [#4347](https://github.com/tiangolo/fastapi/pull/4347) by [@RAlanWright](https://github.com/RAlanWright). * ⬆️ Upgrade Codecov GitHub Action. PR [#4801](https://github.com/tiangolo/fastapi/pull/4801) by [@tiangolo](https://github.com/tiangolo). ## 0.75.1 From 02fae6a38ea492dcd789e835c17c26a93b0697a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 17 Apr 2022 17:51:42 +0200 Subject: [PATCH 430/814] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20dependen?= =?UTF-8?q?cies=20upper=20range=20for=20extras=20"all"=20(#4803)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test.yml | 2 +- pyproject.toml | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aee3a994d..f0a82344e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test + key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test-v02 - name: Install Flit if: steps.cache.outputs.cache-hit != 'true' run: pip install flit diff --git a/pyproject.toml b/pyproject.toml index 46a655a48..9e928beff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,15 +59,15 @@ test = [ "peewee >=3.13.3,<4.0.0", "databases[sqlite] >=0.3.2,<0.6.0", "orjson >=3.2.1,<4.0.0", - "ujson >=4.0.1,<5.0.0", + "ujson >=4.0.1,<6.0.0", "python-multipart >=0.0.5,<0.0.6", "flask >=1.1.2,<3.0.0", "anyio[trio] >=3.2.1,<4.0.0", # types - "types-ujson ==0.1.1", - "types-orjson ==3.6.0", - "types-dataclasses ==0.1.7; python_version<'3.7'", + "types-ujson ==4.2.1", + "types-orjson ==3.6.2", + "types-dataclasses ==0.6.5; python_version<'3.7'", ] doc = [ "mkdocs >=1.1.2,<2.0.0", @@ -77,25 +77,25 @@ doc = [ # TODO: upgrade and enable typer-cli once it supports Click 8.x.x # "typer-cli >=0.0.12,<0.0.13", "typer >=0.4.1,<0.5.0", - "pyyaml >=5.3.1,<6.0.0" + "pyyaml >=5.3.1,<7.0.0", ] dev = [ "python-jose[cryptography] >=3.3.0,<4.0.0", "passlib[bcrypt] >=1.7.2,<2.0.0", "autoflake >=1.4.0,<2.0.0", "flake8 >=3.8.3,<4.0.0", - "uvicorn[standard] >=0.12.0,<0.16.0", + "uvicorn[standard] >=0.12.0,<0.18.0", ] all = [ "requests >=2.24.0,<3.0.0", "jinja2 >=2.11.2,<4.0.0", "python-multipart >=0.0.5,<0.0.6", "itsdangerous >=1.1.0,<3.0.0", - "pyyaml >=5.3.1,<6.0.0", - "ujson >=4.0.1,<5.0.0", + "pyyaml >=5.3.1,<7.0.0", + "ujson >=4.0.1,<6.0.0", "orjson >=3.2.1,<4.0.0", "email_validator >=1.1.1,<2.0.0", - "uvicorn[standard] >=0.12.0,<0.16.0", + "uvicorn[standard] >=0.12.0,<0.18.0", ] [tool.isort] From 0def8382b8386bebc7d04f9e57b638d777228c87 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 17 Apr 2022 15:52:12 +0000 Subject: [PATCH 431/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9d9c2a802..c78b7719a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade dependencies upper range for extras "all". PR [#4803](https://github.com/tiangolo/fastapi/pull/4803) by [@tiangolo](https://github.com/tiangolo). * ⬆ Upgrade Swagger UI - swagger-ui-dist@4. This handles a security issue in Swagger UI itself where it could be possible to inject HTML into Swagger UI. Please upgrade as soon as you can, in particular if you expose your Swagger UI (`/docs`) publicly to non-expert users. PR [#4347](https://github.com/tiangolo/fastapi/pull/4347) by [@RAlanWright](https://github.com/RAlanWright). * ⬆️ Upgrade Codecov GitHub Action. PR [#4801](https://github.com/tiangolo/fastapi/pull/4801) by [@tiangolo](https://github.com/tiangolo). From 3cbfae16cf4f247a8d1940556a43168a04a23fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 17 Apr 2022 18:17:59 +0200 Subject: [PATCH 432/814] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20ujson=20r?= =?UTF-8?q?anges=20for=20CVE-2021-45958=20(#4804)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9e928beff..7856085fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ test = [ "peewee >=3.13.3,<4.0.0", "databases[sqlite] >=0.3.2,<0.6.0", "orjson >=3.2.1,<4.0.0", - "ujson >=4.0.1,<6.0.0", + "ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0", "python-multipart >=0.0.5,<0.0.6", "flask >=1.1.2,<3.0.0", "anyio[trio] >=3.2.1,<4.0.0", @@ -92,7 +92,7 @@ all = [ "python-multipart >=0.0.5,<0.0.6", "itsdangerous >=1.1.0,<3.0.0", "pyyaml >=5.3.1,<7.0.0", - "ujson >=4.0.1,<6.0.0", + "ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0", "orjson >=3.2.1,<4.0.0", "email_validator >=1.1.1,<2.0.0", "uvicorn[standard] >=0.12.0,<0.18.0", From cb4da936437d7e9fbc544f7f8c3237e01a6e2312 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 17 Apr 2022 16:18:35 +0000 Subject: [PATCH 433/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c78b7719a..e4830181f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Update ujson ranges for CVE-2021-45958. PR [#4804](https://github.com/tiangolo/fastapi/pull/4804) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade dependencies upper range for extras "all". PR [#4803](https://github.com/tiangolo/fastapi/pull/4803) by [@tiangolo](https://github.com/tiangolo). * ⬆ Upgrade Swagger UI - swagger-ui-dist@4. This handles a security issue in Swagger UI itself where it could be possible to inject HTML into Swagger UI. Please upgrade as soon as you can, in particular if you expose your Swagger UI (`/docs`) publicly to non-expert users. PR [#4347](https://github.com/tiangolo/fastapi/pull/4347) by [@RAlanWright](https://github.com/RAlanWright). * ⬆️ Upgrade Codecov GitHub Action. PR [#4801](https://github.com/tiangolo/fastapi/pull/4801) by [@tiangolo](https://github.com/tiangolo). From d81c9081324758e4dd830b15e7abbb1817322b76 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sun, 17 Apr 2022 19:21:53 +0200 Subject: [PATCH 434/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20support=20for=20pr?= =?UTF-8?q?efix=20on=20APIRouter=20WebSockets=20(#2640)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/routing.py | 2 +- tests/test_ws_router.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/fastapi/routing.py b/fastapi/routing.py index 0f416ac42..7a15f3965 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -649,7 +649,7 @@ class APIRouter(routing.Router): self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None ) -> None: route = APIWebSocketRoute( - path, + self.prefix + path, endpoint=endpoint, name=name, dependency_overrides_provider=self.dependency_overrides_provider, diff --git a/tests/test_ws_router.py b/tests/test_ws_router.py index bd7c3c53d..fbca104a2 100644 --- a/tests/test_ws_router.py +++ b/tests/test_ws_router.py @@ -3,6 +3,7 @@ from fastapi.testclient import TestClient router = APIRouter() prefix_router = APIRouter() +native_prefix_route = APIRouter(prefix="/native") app = FastAPI() @@ -47,8 +48,16 @@ async def router_ws_decorator_depends( await websocket.close() +@native_prefix_route.websocket("/") +async def router_native_prefix_ws(websocket: WebSocket): + await websocket.accept() + await websocket.send_text("Hello, router with native prefix!") + await websocket.close() + + app.include_router(router) app.include_router(prefix_router, prefix="/prefix") +app.include_router(native_prefix_route) def test_app(): @@ -72,6 +81,13 @@ def test_prefix_router(): assert data == "Hello, router with prefix!" +def test_native_prefix_router(): + client = TestClient(app) + with client.websocket_connect("/native/") as websocket: + data = websocket.receive_text() + assert data == "Hello, router with native prefix!" + + def test_router2(): client = TestClient(app) with client.websocket_connect("/router2") as websocket: From 1d8d81a6d5ba28f809ed9143a92f71fa31af3969 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 17 Apr 2022 17:22:26 +0000 Subject: [PATCH 435/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e4830181f..772d6a0d8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix support for prefix on APIRouter WebSockets. PR [#2640](https://github.com/tiangolo/fastapi/pull/2640) by [@Kludex](https://github.com/Kludex). * ⬆️ Update ujson ranges for CVE-2021-45958. PR [#4804](https://github.com/tiangolo/fastapi/pull/4804) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade dependencies upper range for extras "all". PR [#4803](https://github.com/tiangolo/fastapi/pull/4803) by [@tiangolo](https://github.com/tiangolo). * ⬆ Upgrade Swagger UI - swagger-ui-dist@4. This handles a security issue in Swagger UI itself where it could be possible to inject HTML into Swagger UI. Please upgrade as soon as you can, in particular if you expose your Swagger UI (`/docs`) publicly to non-expert users. PR [#4347](https://github.com/tiangolo/fastapi/pull/4347) by [@RAlanWright](https://github.com/RAlanWright). From c449ae5c74d7908b837a7ecf601f30cbfa246f72 Mon Sep 17 00:00:00 2001 From: dconathan Date: Sun, 17 Apr 2022 12:41:46 -0500 Subject: [PATCH 436/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20JSON=20Schema=20fo?= =?UTF-8?q?r=20`ValidationError`=20at=20field=20`loc`=20(#3810)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Devin Conathan --- fastapi/openapi/utils.py | 6 +++++- tests/test_additional_properties.py | 2 +- tests/test_additional_responses_custom_model_in_callback.py | 2 +- tests/test_additional_responses_default_validationerror.py | 2 +- tests/test_application.py | 2 +- tests/test_dependency_duplicates.py | 2 +- tests/test_extra_routes.py | 2 +- tests/test_filter_pydantic_sub_model.py | 2 +- tests/test_get_request_body.py | 2 +- tests/test_include_router_defaults_overrides.py | 2 +- tests/test_modules_same_name_body/test_main.py | 2 +- tests/test_multi_body_errors.py | 2 +- tests/test_multi_query_errors.py | 2 +- tests/test_param_in_path_and_dependency.py | 2 +- tests/test_put_no_body.py | 2 +- tests/test_repeated_dependency_schema.py | 2 +- tests/test_schema_extra_examples.py | 2 +- tests/test_security_oauth2.py | 2 +- tests/test_security_oauth2_optional.py | 2 +- tests/test_security_oauth2_optional_description.py | 2 +- tests/test_starlette_exception.py | 2 +- tests/test_sub_callbacks.py | 2 +- .../test_additional_responses/test_tutorial001.py | 2 +- .../test_additional_responses/test_tutorial002.py | 2 +- .../test_additional_responses/test_tutorial003.py | 2 +- .../test_additional_responses/test_tutorial004.py | 2 +- .../test_async_sql_databases/test_tutorial001.py | 2 +- tests/test_tutorial/test_bigger_applications/test_main.py | 2 +- tests/test_tutorial/test_body/test_tutorial001.py | 2 +- tests/test_tutorial/test_body_fields/test_tutorial001.py | 2 +- .../test_body_multiple_params/test_tutorial001.py | 2 +- .../test_body_multiple_params/test_tutorial003.py | 2 +- .../test_body_nested_models/test_tutorial009.py | 2 +- tests/test_tutorial/test_body_updates/test_tutorial001.py | 2 +- tests/test_tutorial/test_cookie_params/test_tutorial001.py | 2 +- tests/test_tutorial/test_dataclasses/test_tutorial001.py | 2 +- tests/test_tutorial/test_dataclasses/test_tutorial003.py | 2 +- tests/test_tutorial/test_dependencies/test_tutorial001.py | 2 +- tests/test_tutorial/test_dependencies/test_tutorial004.py | 2 +- tests/test_tutorial/test_dependencies/test_tutorial006.py | 2 +- tests/test_tutorial/test_dependencies/test_tutorial012.py | 2 +- tests/test_tutorial/test_events/test_tutorial001.py | 2 +- .../test_tutorial/test_extra_data_types/test_tutorial001.py | 2 +- tests/test_tutorial/test_extra_models/test_tutorial003.py | 2 +- .../test_tutorial/test_handling_errors/test_tutorial001.py | 2 +- .../test_tutorial/test_handling_errors/test_tutorial002.py | 2 +- .../test_tutorial/test_handling_errors/test_tutorial003.py | 2 +- .../test_tutorial/test_handling_errors/test_tutorial004.py | 2 +- .../test_tutorial/test_handling_errors/test_tutorial005.py | 2 +- .../test_tutorial/test_handling_errors/test_tutorial006.py | 2 +- tests/test_tutorial/test_header_params/test_tutorial001.py | 2 +- .../test_openapi_callbacks/test_tutorial001.py | 2 +- .../test_tutorial004.py | 2 +- .../test_path_operation_configurations/test_tutorial005.py | 2 +- tests/test_tutorial/test_path_params/test_tutorial004.py | 2 +- tests/test_tutorial/test_path_params/test_tutorial005.py | 4 ++-- tests/test_tutorial/test_query_params/test_tutorial005.py | 2 +- tests/test_tutorial/test_query_params/test_tutorial006.py | 2 +- .../test_query_params_str_validations/test_tutorial001.py | 2 +- .../test_query_params_str_validations/test_tutorial011.py | 2 +- .../test_query_params_str_validations/test_tutorial012.py | 2 +- .../test_query_params_str_validations/test_tutorial013.py | 2 +- tests/test_tutorial/test_request_files/test_tutorial001.py | 2 +- tests/test_tutorial/test_request_files/test_tutorial002.py | 2 +- tests/test_tutorial/test_request_forms/test_tutorial001.py | 2 +- .../test_request_forms_and_files/test_tutorial001.py | 2 +- tests/test_tutorial/test_response_model/test_tutorial003.py | 2 +- tests/test_tutorial/test_response_model/test_tutorial004.py | 2 +- tests/test_tutorial/test_response_model/test_tutorial005.py | 2 +- tests/test_tutorial/test_response_model/test_tutorial006.py | 2 +- .../test_schema_extra_example/test_tutorial004.py | 2 +- tests/test_tutorial/test_security/test_tutorial003.py | 2 +- tests/test_tutorial/test_security/test_tutorial005.py | 2 +- .../test_tutorial/test_sql_databases/test_sql_databases.py | 2 +- .../test_sql_databases/test_sql_databases_middleware.py | 2 +- .../test_sql_databases_peewee/test_sql_databases_peewee.py | 2 +- tests/test_union_body.py | 2 +- tests/test_union_inherited_body.py | 2 +- 78 files changed, 83 insertions(+), 79 deletions(-) diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 58a748d04..4eb727bd4 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -38,7 +38,11 @@ validation_error_definition = { "title": "ValidationError", "type": "object", "properties": { - "loc": {"title": "Location", "type": "array", "items": {"type": "string"}}, + "loc": { + "title": "Location", + "type": "array", + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, + }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, }, diff --git a/tests/test_additional_properties.py b/tests/test_additional_properties.py index 9e15e6ed0..016c1f734 100644 --- a/tests/test_additional_properties.py +++ b/tests/test_additional_properties.py @@ -76,7 +76,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_additional_responses_custom_model_in_callback.py b/tests/test_additional_responses_custom_model_in_callback.py index 36dd0d6db..a1072cc56 100644 --- a/tests/test_additional_responses_custom_model_in_callback.py +++ b/tests/test_additional_responses_custom_model_in_callback.py @@ -119,7 +119,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_additional_responses_default_validationerror.py b/tests/test_additional_responses_default_validationerror.py index 6ea372ce8..cabb536d7 100644 --- a/tests/test_additional_responses_default_validationerror.py +++ b/tests/test_additional_responses_default_validationerror.py @@ -54,7 +54,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_application.py b/tests/test_application.py index 5ba737307..d9194c15c 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -1101,7 +1101,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_dependency_duplicates.py b/tests/test_dependency_duplicates.py index 5e15812b6..33899134e 100644 --- a/tests/test_dependency_duplicates.py +++ b/tests/test_dependency_duplicates.py @@ -177,7 +177,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_extra_routes.py b/tests/test_extra_routes.py index 6aba3e8dd..8f95b7bc9 100644 --- a/tests/test_extra_routes.py +++ b/tests/test_extra_routes.py @@ -292,7 +292,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_filter_pydantic_sub_model.py b/tests/test_filter_pydantic_sub_model.py index 90a372976..8814356a1 100644 --- a/tests/test_filter_pydantic_sub_model.py +++ b/tests/test_filter_pydantic_sub_model.py @@ -116,7 +116,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_get_request_body.py b/tests/test_get_request_body.py index b12f499eb..88b9d839f 100644 --- a/tests/test_get_request_body.py +++ b/tests/test_get_request_body.py @@ -85,7 +85,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_include_router_defaults_overrides.py b/tests/test_include_router_defaults_overrides.py index 5dd7e7098..ccb6c7229 100644 --- a/tests/test_include_router_defaults_overrides.py +++ b/tests/test_include_router_defaults_overrides.py @@ -6612,7 +6612,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_modules_same_name_body/test_main.py b/tests/test_modules_same_name_body/test_main.py index b0d3330c7..8b1aea031 100644 --- a/tests/test_modules_same_name_body/test_main.py +++ b/tests/test_modules_same_name_body/test_main.py @@ -101,7 +101,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_multi_body_errors.py b/tests/test_multi_body_errors.py index c1be82806..31308ea85 100644 --- a/tests/test_multi_body_errors.py +++ b/tests/test_multi_body_errors.py @@ -79,7 +79,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_multi_query_errors.py b/tests/test_multi_query_errors.py index 69ea87a9b..0a15833fa 100644 --- a/tests/test_multi_query_errors.py +++ b/tests/test_multi_query_errors.py @@ -63,7 +63,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_param_in_path_and_dependency.py b/tests/test_param_in_path_and_dependency.py index 0a94c2151..4d85afbce 100644 --- a/tests/test_param_in_path_and_dependency.py +++ b/tests/test_param_in_path_and_dependency.py @@ -71,7 +71,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_put_no_body.py b/tests/test_put_no_body.py index 1c2cfac89..3da294ccf 100644 --- a/tests/test_put_no_body.py +++ b/tests/test_put_no_body.py @@ -57,7 +57,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_repeated_dependency_schema.py b/tests/test_repeated_dependency_schema.py index fd616e12a..00441694e 100644 --- a/tests/test_repeated_dependency_schema.py +++ b/tests/test_repeated_dependency_schema.py @@ -36,7 +36,7 @@ schema = { "ValidationError": { "properties": { "loc": { - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "title": "Location", "type": "array", }, diff --git a/tests/test_schema_extra_examples.py b/tests/test_schema_extra_examples.py index 3e0d846cd..444e350a8 100644 --- a/tests/test_schema_extra_examples.py +++ b/tests/test_schema_extra_examples.py @@ -830,7 +830,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_security_oauth2.py b/tests/test_security_oauth2.py index b7ada7caf..b9ac488ee 100644 --- a/tests/test_security_oauth2.py +++ b/tests/test_security_oauth2.py @@ -117,7 +117,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_security_oauth2_optional.py b/tests/test_security_oauth2_optional.py index ecc766511..a5fd49b8c 100644 --- a/tests/test_security_oauth2_optional.py +++ b/tests/test_security_oauth2_optional.py @@ -121,7 +121,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_security_oauth2_optional_description.py b/tests/test_security_oauth2_optional_description.py index 011db65ec..171f96b76 100644 --- a/tests/test_security_oauth2_optional_description.py +++ b/tests/test_security_oauth2_optional_description.py @@ -122,7 +122,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_starlette_exception.py b/tests/test_starlette_exception.py index 5759a93f4..859169d3c 100644 --- a/tests/test_starlette_exception.py +++ b/tests/test_starlette_exception.py @@ -102,7 +102,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_sub_callbacks.py b/tests/test_sub_callbacks.py index 16644b556..7574d6fbc 100644 --- a/tests/test_sub_callbacks.py +++ b/tests/test_sub_callbacks.py @@ -256,7 +256,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial001.py b/tests/test_tutorial/test_additional_responses/test_tutorial001.py index 8342dd787..1a8acb523 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial001.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial001.py @@ -76,7 +76,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial002.py b/tests/test_tutorial/test_additional_responses/test_tutorial002.py index 57f877978..2adcf15d0 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial002.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial002.py @@ -72,7 +72,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial003.py b/tests/test_tutorial/test_additional_responses/test_tutorial003.py index 37190b36a..8b2167de0 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial003.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial003.py @@ -77,7 +77,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial004.py b/tests/test_tutorial/test_additional_responses/test_tutorial004.py index c44a18f68..990d5235a 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial004.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial004.py @@ -75,7 +75,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py index 90feb0172..1ad625db6 100644 --- a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py +++ b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py @@ -88,7 +88,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py index 7eb675179..cd6d7b5c8 100644 --- a/tests/test_tutorial/test_bigger_applications/test_main.py +++ b/tests/test_tutorial/test_bigger_applications/test_main.py @@ -323,7 +323,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py index 7bf62c907..8dbaf15db 100644 --- a/tests/test_tutorial/test_body/test_tutorial001.py +++ b/tests/test_tutorial/test_body/test_tutorial001.py @@ -63,7 +63,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001.py b/tests/test_tutorial/test_body_fields/test_tutorial001.py index 9de4907c2..fe5a270f3 100644 --- a/tests/test_tutorial/test_body_fields/test_tutorial001.py +++ b/tests/test_tutorial/test_body_fields/test_tutorial001.py @@ -87,7 +87,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py index b11ecddab..8dc710d75 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py @@ -79,7 +79,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py index d98e3e419..64aa9c43b 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py @@ -90,7 +90,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py index 8eb0ad130..c56d41b5b 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py @@ -53,7 +53,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py index 5e92ef7ea..efd0e4676 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py @@ -109,7 +109,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001.py b/tests/test_tutorial/test_cookie_params/test_tutorial001.py index 3451dc19e..edccffec1 100644 --- a/tests/test_tutorial/test_cookie_params/test_tutorial001.py +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001.py @@ -50,7 +50,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial001.py b/tests/test_tutorial/test_dataclasses/test_tutorial001.py index 3e3fc9acf..bf1564194 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial001.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial001.py @@ -71,7 +71,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py index dd0f1f2c0..2d86f7b9a 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py @@ -118,7 +118,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001.py b/tests/test_tutorial/test_dependencies/test_tutorial001.py index 8b53157cd..c3bca5d5b 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001.py @@ -104,7 +104,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004.py b/tests/test_tutorial/test_dependencies/test_tutorial004.py index eb21f6524..f2b1878d5 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial004.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial004.py @@ -62,7 +62,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006.py b/tests/test_tutorial/test_dependencies/test_tutorial006.py index c08992ec8..2916577a2 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial006.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial006.py @@ -55,7 +55,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012.py b/tests/test_tutorial/test_dependencies/test_tutorial012.py index ada83c626..e4e07395d 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial012.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial012.py @@ -102,7 +102,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_events/test_tutorial001.py b/tests/test_tutorial/test_events/test_tutorial001.py index e3587a0e8..d52dd1a04 100644 --- a/tests/test_tutorial/test_events/test_tutorial001.py +++ b/tests/test_tutorial/test_events/test_tutorial001.py @@ -47,7 +47,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py index 68b7d61dc..8522d7b9d 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py @@ -89,7 +89,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py index a2a325c77..f1433470c 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial003.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py @@ -78,7 +78,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial001.py b/tests/test_tutorial/test_handling_errors/test_tutorial001.py index 6b62293d8..ffd79ccff 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial001.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial001.py @@ -49,7 +49,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial002.py b/tests/test_tutorial/test_handling_errors/test_tutorial002.py index d2ce0bf9d..e678499c6 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial002.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial002.py @@ -49,7 +49,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial003.py b/tests/test_tutorial/test_handling_errors/test_tutorial003.py index ca9d94e3c..a01726dc2 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial003.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial003.py @@ -49,7 +49,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial004.py b/tests/test_tutorial/test_handling_errors/test_tutorial004.py index d95debf37..0b5f74798 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial004.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial004.py @@ -49,7 +49,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial005.py b/tests/test_tutorial/test_handling_errors/test_tutorial005.py index cedcaae70..253f3d006 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial005.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial005.py @@ -69,7 +69,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial006.py b/tests/test_tutorial/test_handling_errors/test_tutorial006.py index 8b6c1e7ed..21233d7bb 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial006.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial006.py @@ -49,7 +49,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_header_params/test_tutorial001.py b/tests/test_tutorial/test_header_params/test_tutorial001.py index 0f05b9e8c..273cf3249 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial001.py +++ b/tests/test_tutorial/test_header_params/test_tutorial001.py @@ -51,7 +51,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py index b30427d08..e773e7f8f 100644 --- a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py +++ b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py @@ -143,7 +143,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py index f2ec2c7e5..456e509d5 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py @@ -72,7 +72,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py index d21640946..e587519a0 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py @@ -72,7 +72,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_path_params/test_tutorial004.py b/tests/test_tutorial/test_path_params/test_tutorial004.py index 131bf773b..7f0227ecf 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial004.py +++ b/tests/test_tutorial/test_path_params/test_tutorial004.py @@ -49,7 +49,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_path_params/test_tutorial005.py b/tests/test_tutorial/test_path_params/test_tutorial005.py index ed9d2032b..eae3637be 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial005.py +++ b/tests/test_tutorial/test_path_params/test_tutorial005.py @@ -54,7 +54,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, @@ -138,7 +138,7 @@ openapi_schema2 = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params/test_tutorial005.py b/tests/test_tutorial/test_query_params/test_tutorial005.py index aabc0af4f..07178f8a6 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial005.py +++ b/tests/test_tutorial/test_query_params/test_tutorial005.py @@ -56,7 +56,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params/test_tutorial006.py b/tests/test_tutorial/test_query_params/test_tutorial006.py index 042a0e1f8..73c5302e7 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial006.py +++ b/tests/test_tutorial/test_query_params/test_tutorial006.py @@ -68,7 +68,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py index 709bf6956..f8d7f85c8 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py @@ -59,7 +59,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py index 6ae10296f..ad3645f31 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py @@ -53,7 +53,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py index 724c975f8..d69139dda 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py @@ -54,7 +54,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py index ad5597913..1b2e36354 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py @@ -54,7 +54,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py index 841116e30..166014c71 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001.py @@ -99,7 +99,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py index 4e33ef464..73d1179a1 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002.py @@ -119,7 +119,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001.py b/tests/test_tutorial/test_request_forms/test_tutorial001.py index 3d271b531..215260ffa 100644 --- a/tests/test_tutorial/test_request_forms/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms/test_tutorial001.py @@ -61,7 +61,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py index 10cce5e61..09e232b8e 100644 --- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py @@ -61,7 +61,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_response_model/test_tutorial003.py b/tests/test_tutorial/test_response_model/test_tutorial003.py index 44f2fb7ca..e1bde5d13 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003.py @@ -74,7 +74,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_response_model/test_tutorial004.py b/tests/test_tutorial/test_response_model/test_tutorial004.py index 19303982b..8c98c6de3 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial004.py +++ b/tests/test_tutorial/test_response_model/test_tutorial004.py @@ -71,7 +71,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_response_model/test_tutorial005.py b/tests/test_tutorial/test_response_model/test_tutorial005.py index 9ca5463e6..476b172d3 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial005.py +++ b/tests/test_tutorial/test_response_model/test_tutorial005.py @@ -98,7 +98,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_response_model/test_tutorial006.py b/tests/test_tutorial/test_response_model/test_tutorial006.py index 25eb6e333..38eb31e54 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial006.py +++ b/tests/test_tutorial/test_response_model/test_tutorial006.py @@ -98,7 +98,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py index 89f5b66fd..badf66b3d 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py @@ -103,7 +103,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py index 3fc7f5f40..595107834 100644 --- a/tests/test_tutorial/test_security/test_tutorial003.py +++ b/tests/test_tutorial/test_security/test_tutorial003.py @@ -81,7 +81,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py index a37f2d60a..e8697339f 100644 --- a/tests/test_tutorial/test_security/test_tutorial005.py +++ b/tests/test_tutorial/test_security/test_tutorial005.py @@ -141,7 +141,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases.py b/tests/test_tutorial/test_sql_databases/test_sql_databases.py index c88fd0bcd..09304ff87 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases.py @@ -261,7 +261,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py index b02e1c89e..fbaa8938a 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py @@ -260,7 +260,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py b/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py index 2ebc31b95..d28ea5e76 100644 --- a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py +++ b/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py @@ -318,7 +318,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_union_body.py b/tests/test_union_body.py index d1dfd5efb..3e424de07 100644 --- a/tests/test_union_body.py +++ b/tests/test_union_body.py @@ -84,7 +84,7 @@ item_openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_union_inherited_body.py b/tests/test_union_inherited_body.py index e3d0acc99..60b327ebc 100644 --- a/tests/test_union_inherited_body.py +++ b/tests/test_union_inherited_body.py @@ -96,7 +96,7 @@ inherited_item_openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, From d9e7a541fde953ec08da2b626a9555a80910be11 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 17 Apr 2022 17:42:18 +0000 Subject: [PATCH 437/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 772d6a0d8..33794daea 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix JSON Schema for `ValidationError` at field `loc`. PR [#3810](https://github.com/tiangolo/fastapi/pull/3810) by [@dconathan](https://github.com/dconathan). * 🐛 Fix support for prefix on APIRouter WebSockets. PR [#2640](https://github.com/tiangolo/fastapi/pull/2640) by [@Kludex](https://github.com/Kludex). * ⬆️ Update ujson ranges for CVE-2021-45958. PR [#4804](https://github.com/tiangolo/fastapi/pull/4804) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade dependencies upper range for extras "all". PR [#4803](https://github.com/tiangolo/fastapi/pull/4803) by [@tiangolo](https://github.com/tiangolo). From 197c1d6dd77bedbc90282db9c8d1b93a7a998856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 17 Apr 2022 21:02:49 +0200 Subject: [PATCH 438/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 33794daea..7adad85cf 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,11 +2,21 @@ ## Latest Changes +This release includes upgrades to third-party packages that handle security issues. Although there's a chance these issues don't affect you in particular, please upgrade as soon as possible. + +### Fixes + * 🐛 Fix JSON Schema for `ValidationError` at field `loc`. PR [#3810](https://github.com/tiangolo/fastapi/pull/3810) by [@dconathan](https://github.com/dconathan). * 🐛 Fix support for prefix on APIRouter WebSockets. PR [#2640](https://github.com/tiangolo/fastapi/pull/2640) by [@Kludex](https://github.com/Kludex). + +### Upgrades + * ⬆️ Update ujson ranges for CVE-2021-45958. PR [#4804](https://github.com/tiangolo/fastapi/pull/4804) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade dependencies upper range for extras "all". PR [#4803](https://github.com/tiangolo/fastapi/pull/4803) by [@tiangolo](https://github.com/tiangolo). * ⬆ Upgrade Swagger UI - swagger-ui-dist@4. This handles a security issue in Swagger UI itself where it could be possible to inject HTML into Swagger UI. Please upgrade as soon as you can, in particular if you expose your Swagger UI (`/docs`) publicly to non-expert users. PR [#4347](https://github.com/tiangolo/fastapi/pull/4347) by [@RAlanWright](https://github.com/RAlanWright). + +### Internal + * ⬆️ Upgrade Codecov GitHub Action. PR [#4801](https://github.com/tiangolo/fastapi/pull/4801) by [@tiangolo](https://github.com/tiangolo). ## 0.75.1 From ddd9da3db47e28406bdb5f7ad23cb7b33336e762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 17 Apr 2022 22:55:36 +0200 Subject: [PATCH 439/814] =?UTF-8?q?=E2=9C=85=20Fix=20new/recent=20tests=20?= =?UTF-8?q?with=20new=20fixed=20`ValidationError`=20JSON=20Schema=20(#4806?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_generate_unique_id_function.py | 28 ++++++++++++++----- tests/test_param_include_in_schema.py | 2 +- tests/test_tuples.py | 2 +- .../test_body/test_tutorial001_py310.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial003_py310.py | 2 +- .../test_tutorial009_py39.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial001_py39.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial004_py310.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial003_py310.py | 2 +- .../test_generate_clients/test_tutorial003.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial005_py310.py | 2 +- .../test_tutorial005_py39.py | 2 +- .../test_tutorial006_py310.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial011_py310.py | 2 +- .../test_tutorial011_py39.py | 2 +- .../test_tutorial012_py39.py | 2 +- .../test_tutorial014.py | 2 +- .../test_tutorial014_py310.py | 2 +- .../test_request_files/test_tutorial001_02.py | 2 +- .../test_tutorial001_02_py310.py | 2 +- .../test_request_files/test_tutorial001_03.py | 2 +- .../test_tutorial002_py39.py | 2 +- .../test_request_files/test_tutorial003.py | 2 +- .../test_tutorial003_py39.py | 2 +- .../test_tutorial003_py310.py | 2 +- .../test_tutorial004_py310.py | 2 +- .../test_tutorial004_py39.py | 2 +- .../test_tutorial005_py310.py | 2 +- .../test_tutorial006_py310.py | 2 +- .../test_tutorial004_py310.py | 2 +- .../test_security/test_tutorial003_py310.py | 2 +- .../test_security/test_tutorial005_py310.py | 2 +- .../test_security/test_tutorial005_py39.py | 2 +- .../test_sql_databases_middleware_py310.py | 2 +- .../test_sql_databases_middleware_py39.py | 2 +- .../test_sql_databases_py310.py | 2 +- .../test_sql_databases_py39.py | 2 +- 45 files changed, 65 insertions(+), 51 deletions(-) diff --git a/tests/test_generate_unique_id_function.py b/tests/test_generate_unique_id_function.py index ffc0e3844..0b519f859 100644 --- a/tests/test_generate_unique_id_function.py +++ b/tests/test_generate_unique_id_function.py @@ -217,7 +217,9 @@ def test_top_level_generate_unique_id(): "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, @@ -416,7 +418,9 @@ def test_router_overrides_generate_unique_id(): "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, @@ -615,7 +619,9 @@ def test_router_include_overrides_generate_unique_id(): "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, @@ -887,7 +893,9 @@ def test_subrouter_top_level_include_overrides_generate_unique_id(): "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, @@ -1089,7 +1097,9 @@ def test_router_path_operation_overrides_generate_unique_id(): "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, @@ -1295,7 +1305,9 @@ def test_app_path_operation_overrides_generate_unique_id(): "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, @@ -1579,7 +1591,9 @@ def test_callback_override_generate_unique_id(): "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py index 4eaac72d8..26aa63897 100644 --- a/tests/test_param_include_in_schema.py +++ b/tests/test_param_include_in_schema.py @@ -149,7 +149,7 @@ openapi_shema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tuples.py b/tests/test_tuples.py index 4cd5ee3af..2085dc367 100644 --- a/tests/test_tuples.py +++ b/tests/test_tuples.py @@ -200,7 +200,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body/test_tutorial001_py310.py b/tests/test_tutorial/test_body/test_tutorial001_py310.py index e292b5346..dd9d9911e 100644 --- a/tests/test_tutorial/test_body/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_body/test_tutorial001_py310.py @@ -61,7 +61,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py index d7a525ea7..993e2a91d 100644 --- a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py @@ -84,7 +84,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py index 85ba41ce6..5114ccea2 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py @@ -77,7 +77,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py index f896f7bf5..fc019d8bb 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py @@ -88,7 +88,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py index 17ca29ce5..5b8d82861 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py @@ -52,7 +52,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py index ca1d8c585..49279b320 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py @@ -108,7 +108,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py index f2b184c4f..872530bcf 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py @@ -108,7 +108,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py index 587a328da..5caa5c440 100644 --- a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py @@ -48,7 +48,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py index a7991170e..32a61c821 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py @@ -102,7 +102,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py index f66a36a99..e3ae0c741 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py @@ -60,7 +60,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py index 3d4c1d07d..4efdecc53 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py @@ -87,7 +87,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py index 185bc3a37..56fd83ad3 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py @@ -77,7 +77,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial003.py b/tests/test_tutorial/test_generate_clients/test_tutorial003.py index d79123163..128fcea30 100644 --- a/tests/test_tutorial/test_generate_clients/test_tutorial003.py +++ b/tests/test_tutorial/test_generate_clients/test_tutorial003.py @@ -147,7 +147,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_header_params/test_tutorial001_py310.py b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py index f5ee17428..77a60eb9d 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py @@ -48,7 +48,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py index 1f617da70..43a7a610d 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py @@ -71,7 +71,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py index ffdf05081..62aa73ac5 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py @@ -71,7 +71,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py index 1986d27d0..141525f15 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py +++ b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py @@ -66,7 +66,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py index 66b24017e..298b5d616 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py @@ -57,7 +57,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py index 8894ee1b5..9330037ed 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py @@ -52,7 +52,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py index b10e70af7..11f23be27 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py @@ -52,7 +52,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py index a9cbce02a..b25bb2847 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py @@ -53,7 +53,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py index 98ae5a684..57b8b9d94 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py @@ -53,7 +53,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py index 33f3d5f77..fe54fc080 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py @@ -51,7 +51,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02.py b/tests/test_tutorial/test_request_files/test_tutorial001_02.py index e852a1b31..a254bf3e8 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_02.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02.py @@ -106,7 +106,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py index 62e9f98d0..15b6a8d53 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py @@ -107,7 +107,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03.py b/tests/test_tutorial/test_request_files/test_tutorial001_03.py index ec7509ea2..c34165f18 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_03.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_03.py @@ -120,7 +120,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_files/test_tutorial002_py39.py b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py index bbdf25cd9..de4127057 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002_py39.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py @@ -119,7 +119,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_files/test_tutorial003.py b/tests/test_tutorial/test_request_files/test_tutorial003.py index 943b235ab..83aea66cd 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial003.py +++ b/tests/test_tutorial/test_request_files/test_tutorial003.py @@ -132,7 +132,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_request_files/test_tutorial003_py39.py b/tests/test_tutorial/test_request_files/test_tutorial003_py39.py index d5fbd7889..56aeb54cd 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial003_py39.py +++ b/tests/test_tutorial/test_request_files/test_tutorial003_py39.py @@ -132,7 +132,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_py310.py b/tests/test_tutorial/test_response_model/test_tutorial003_py310.py index ffba11662..9827dab8a 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_py310.py @@ -73,7 +73,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_response_model/test_tutorial004_py310.py b/tests/test_tutorial/test_response_model/test_tutorial004_py310.py index f1508a05d..7fc86fafa 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial004_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial004_py310.py @@ -69,7 +69,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_response_model/test_tutorial004_py39.py b/tests/test_tutorial/test_response_model/test_tutorial004_py39.py index e5d9c8b5f..405fe79f5 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial004_py39.py +++ b/tests/test_tutorial/test_response_model/test_tutorial004_py39.py @@ -69,7 +69,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_response_model/test_tutorial005_py310.py b/tests/test_tutorial/test_response_model/test_tutorial005_py310.py index 6d7366f12..389a302e0 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial005_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial005_py310.py @@ -97,7 +97,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_response_model/test_tutorial006_py310.py b/tests/test_tutorial/test_response_model/test_tutorial006_py310.py index a3d8d204e..f870f3926 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial006_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial006_py310.py @@ -97,7 +97,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py index 4f9a2ff57..d326a5a09 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py @@ -102,7 +102,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_security/test_tutorial003_py310.py b/tests/test_tutorial/test_security/test_tutorial003_py310.py index e621bcd45..26f5c097f 100644 --- a/tests/test_tutorial/test_security/test_tutorial003_py310.py +++ b/tests/test_tutorial/test_security/test_tutorial003_py310.py @@ -80,7 +80,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_security/test_tutorial005_py310.py b/tests/test_tutorial/test_security/test_tutorial005_py310.py index 0c9372e2a..3144a2365 100644 --- a/tests/test_tutorial/test_security/test_tutorial005_py310.py +++ b/tests/test_tutorial/test_security/test_tutorial005_py310.py @@ -134,7 +134,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_security/test_tutorial005_py39.py b/tests/test_tutorial/test_security/test_tutorial005_py39.py index 099ab2526..290136e17 100644 --- a/tests/test_tutorial/test_security/test_tutorial005_py39.py +++ b/tests/test_tutorial/test_security/test_tutorial005_py39.py @@ -134,7 +134,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py index 1d0442eb5..d131b4b6a 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py @@ -263,7 +263,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py index 8764d07a6..470fb52fd 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py @@ -263,7 +263,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py index f7e73dea4..dc6a1db15 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py @@ -263,7 +263,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py index c194c85aa..ebf55ed01 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py @@ -263,7 +263,7 @@ openapi_schema = { "loc": { "title": "Location", "type": "array", - "items": {"type": "string"}, + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, }, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}, From 41d75b6d1c1ed27a733300b11f67a81309aa89fd Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 17 Apr 2022 20:56:09 +0000 Subject: [PATCH 440/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7adad85cf..016bf3469 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✅ Fix new/recent tests with new fixed `ValidationError` JSON Schema. PR [#4806](https://github.com/tiangolo/fastapi/pull/4806) by [@tiangolo](https://github.com/tiangolo). This release includes upgrades to third-party packages that handle security issues. Although there's a chance these issues don't affect you in particular, please upgrade as soon as possible. ### Fixes From 77fc14eb69725f6fb3cdf3e8745a54a4e93d5e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 17 Apr 2022 23:00:49 +0200 Subject: [PATCH 441/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20sponsors,=20add?= =?UTF-8?q?:=20ExoFlare,=20Ines=20Course;=20remove:=20Dropbase,=20Vim.so,?= =?UTF-8?q?=20Calmcode;=20update:=20Striveworks,=20TalkPython=20and=20Test?= =?UTF-8?q?Driven.io=20(#4805)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +--- docs/en/data/sponsors.yml | 21 ++++++++---------- docs/en/data/sponsors_badge.yml | 5 ++--- docs/en/docs/img/sponsors/exoflare.png | Bin 0 -> 5357 bytes .../sponsors/fastapi-course-bundle-banner.png | Bin 0 -> 16235 bytes docs/en/docs/img/sponsors/ines-course.jpg | Bin 0 -> 11727 bytes docs/en/overrides/main.html | 20 +---------------- 7 files changed, 13 insertions(+), 37 deletions(-) create mode 100644 docs/en/docs/img/sponsors/exoflare.png create mode 100644 docs/en/docs/img/sponsors/fastapi-course-bundle-banner.png create mode 100644 docs/en/docs/img/sponsors/ines-course.jpg diff --git a/README.md b/README.md index 0fb25cc7e..a03a98719 100644 --- a/README.md +++ b/README.md @@ -49,15 +49,13 @@ The key features are: - - - + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 65a114584..35eff9d87 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -5,12 +5,6 @@ gold: - url: https://cryptapi.io/ title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway." img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg - - url: https://www.dropbase.io/careers - title: Dropbase - seamlessly collect, clean, and centralize data. - img: https://fastapi.tiangolo.com/img/sponsors/dropbase.svg - - url: https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings - title: https://striveworks.us/careers - img: https://fastapi.tiangolo.com/img/sponsors/striveworks.png - url: https://classiq.link/n4s title: Join the team building a new SaaS platform that will change the computing world img: https://fastapi.tiangolo.com/img/sponsors/classiq.png @@ -21,9 +15,6 @@ silver: - url: https://www.investsuite.com/jobs title: Wealthtech jobs with FastAPI img: https://fastapi.tiangolo.com/img/sponsors/investsuite.svg - - url: https://www.vim.so/?utm_source=FastAPI - title: We help you master vim with interactive exercises - img: https://fastapi.tiangolo.com/img/sponsors/vimso.png - url: https://talkpython.fm/fastapi-sponsor title: FastAPI video courses on demand from people you trust img: https://fastapi.tiangolo.com/img/sponsors/talkpython.png @@ -33,7 +24,13 @@ silver: - url: https://github.com/deepset-ai/haystack/ title: Build powerful search from composable, open source building blocks img: https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg + - url: https://www.udemy.com/course/fastapi-rest/ + title: Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails. + img: https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg bronze: - - url: https://calmcode.io - title: Code. Simply. Clearly. Calmly. - img: https://fastapi.tiangolo.com/img/sponsors/calmcode.jpg + - url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source + title: Biosecurity risk assessments made easy. + img: https://fastapi.tiangolo.com/img/sponsors/exoflare.png + - url: https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings + title: https://striveworks.us/careers + img: https://fastapi.tiangolo.com/img/sponsors/striveworks.png diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index dbf69c1b3..67dd16a8b 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -2,10 +2,9 @@ logins: - jina-ai - deta - investsuite - - vimsoHQ - mikeckennedy - - koaning - deepset-ai - cryptapi - - DropbaseHQ - Striveworks + - xoflare + - InesIvanova diff --git a/docs/en/docs/img/sponsors/exoflare.png b/docs/en/docs/img/sponsors/exoflare.png new file mode 100644 index 0000000000000000000000000000000000000000..3eed3af18a00c01f5940940a85386542b449dfd2 GIT binary patch literal 5357 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 z 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 V=0{$9ew6?K002ovPDHLkV1mi>sMi1h literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/sponsors/ines-course.jpg b/docs/en/docs/img/sponsors/ines-course.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05158b3872caa803c000c3dee1aa3f858ad5534f GIT binary patch literal 11727 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 literal 0 HcmV?d00001 diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 83c26e72a..562bf3079 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -22,16 +22,10 @@
-
@@ -46,18 +40,6 @@
- -
From 1d106bd959b8c43f57aed06c1fd180ec8043281d Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 17 Apr 2022 21:01:21 +0000 Subject: [PATCH 442/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 016bf3469..ba0a8008e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update sponsors, add: ExoFlare, Ines Course; remove: Dropbase, Vim.so, Calmcode; update: Striveworks, TalkPython and TestDriven.io. PR [#4805](https://github.com/tiangolo/fastapi/pull/4805) by [@tiangolo](https://github.com/tiangolo). * ✅ Fix new/recent tests with new fixed `ValidationError` JSON Schema. PR [#4806](https://github.com/tiangolo/fastapi/pull/4806) by [@tiangolo](https://github.com/tiangolo). This release includes upgrades to third-party packages that handle security issues. Although there's a chance these issues don't affect you in particular, please upgrade as soon as possible. From acd2287b576b42e07401adc40b958beea6bafb8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 17 Apr 2022 23:07:27 +0200 Subject: [PATCH 443/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ba0a8008e..951a57daf 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,12 +2,11 @@ ## Latest Changes -* 🔧 Update sponsors, add: ExoFlare, Ines Course; remove: Dropbase, Vim.so, Calmcode; update: Striveworks, TalkPython and TestDriven.io. PR [#4805](https://github.com/tiangolo/fastapi/pull/4805) by [@tiangolo](https://github.com/tiangolo). -* ✅ Fix new/recent tests with new fixed `ValidationError` JSON Schema. PR [#4806](https://github.com/tiangolo/fastapi/pull/4806) by [@tiangolo](https://github.com/tiangolo). This release includes upgrades to third-party packages that handle security issues. Although there's a chance these issues don't affect you in particular, please upgrade as soon as possible. ### Fixes +* ✅ Fix new/recent tests with new fixed `ValidationError` JSON Schema. PR [#4806](https://github.com/tiangolo/fastapi/pull/4806) by [@tiangolo](https://github.com/tiangolo). * 🐛 Fix JSON Schema for `ValidationError` at field `loc`. PR [#3810](https://github.com/tiangolo/fastapi/pull/3810) by [@dconathan](https://github.com/dconathan). * 🐛 Fix support for prefix on APIRouter WebSockets. PR [#2640](https://github.com/tiangolo/fastapi/pull/2640) by [@Kludex](https://github.com/Kludex). @@ -19,6 +18,7 @@ This release includes upgrades to third-party packages that handle security issu ### Internal +* 🔧 Update sponsors, add: ExoFlare, Ines Course; remove: Dropbase, Vim.so, Calmcode; update: Striveworks, TalkPython and TestDriven.io. PR [#4805](https://github.com/tiangolo/fastapi/pull/4805) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade Codecov GitHub Action. PR [#4801](https://github.com/tiangolo/fastapi/pull/4801) by [@tiangolo](https://github.com/tiangolo). ## 0.75.1 From 2b54432a9c78730b0dd69fca8f15d932d5a31d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 17 Apr 2022 23:08:37 +0200 Subject: [PATCH 444/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.75?= =?UTF-8?q?.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 951a57daf..df3a36805 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.75.2 + This release includes upgrades to third-party packages that handle security issues. Although there's a chance these issues don't affect you in particular, please upgrade as soon as possible. ### Fixes diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 0ce2ef720..22d8e51ec 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.75.1" +__version__ = "0.75.2" from starlette import status as status From 7c8383c96b3157ff8e5ada36332714b03b97e9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 24 Apr 2022 17:31:12 +0200 Subject: [PATCH 445/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20sponsors,=20ena?= =?UTF-8?q?ble=20Dropbase=20again,=20update=20TalkPython=20link=20(#4821)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++- docs/en/data/sponsors.yml | 5 ++++- docs/en/data/sponsors_badge.yml | 1 + docs/en/overrides/main.html | 6 ++++++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a03a98719..3756053e8 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,10 @@ The key features are: + - + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 35eff9d87..a216be04d 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -8,6 +8,9 @@ gold: - url: https://classiq.link/n4s title: Join the team building a new SaaS platform that will change the computing world img: https://fastapi.tiangolo.com/img/sponsors/classiq.png + - url: https://www.dropbase.io/careers + title: Dropbase - seamlessly collect, clean, and centralize data. + img: https://fastapi.tiangolo.com/img/sponsors/dropbase.svg silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas @@ -15,7 +18,7 @@ silver: - url: https://www.investsuite.com/jobs title: Wealthtech jobs with FastAPI img: https://fastapi.tiangolo.com/img/sponsors/investsuite.svg - - url: https://talkpython.fm/fastapi-sponsor + - url: https://training.talkpython.fm/fastapi-courses title: FastAPI video courses on demand from people you trust img: https://fastapi.tiangolo.com/img/sponsors/talkpython.png - url: https://testdriven.io/courses/tdd-fastapi/ diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index 67dd16a8b..e0288356a 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -8,3 +8,4 @@ logins: - Striveworks - xoflare - InesIvanova + - DropbaseHQ diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 562bf3079..cac02ca7c 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -46,6 +46,12 @@
+
{% endblock %} From 0fd99ec3378f7330271981b28258208b948cc7f4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 24 Apr 2022 15:31:48 +0000 Subject: [PATCH 446/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index df3a36805..568796dd0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update sponsors, enable Dropbase again, update TalkPython link. PR [#4821](https://github.com/tiangolo/fastapi/pull/4821) by [@tiangolo](https://github.com/tiangolo). ## 0.75.2 From 4642d5bb862627f5653ef666b178689b21f129c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 24 Apr 2022 17:52:31 +0200 Subject: [PATCH 447/814] =?UTF-8?q?=F0=9F=8D=B1=20Update=20sponsor,=20ExoF?= =?UTF-8?q?lare=20badge=20(#4822)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/img/sponsors/exoflare.png | Bin 5357 -> 10556 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/en/docs/img/sponsors/exoflare.png b/docs/en/docs/img/sponsors/exoflare.png index 3eed3af18a00c01f5940940a85386542b449dfd2..b5977d80bedb27d3a17eb16aa919947867750a75 100644 GIT binary patch literal 10556 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 QoP0#6C}<$7k5S8vN%{#z-7Z@%O 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 Date: Sun, 24 Apr 2022 15:53:04 +0000 Subject: [PATCH 448/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 568796dd0..6c995148a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🍱 Update sponsor, ExoFlare badge. PR [#4822](https://github.com/tiangolo/fastapi/pull/4822) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, enable Dropbase again, update TalkPython link. PR [#4821](https://github.com/tiangolo/fastapi/pull/4821) by [@tiangolo](https://github.com/tiangolo). ## 0.75.2 From 1920c3dd16909f00631fde1e71890dac048bf1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 25 Apr 2022 12:01:39 +0200 Subject: [PATCH 449/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20Budget=20Insight?= =?UTF-8?q?=20sponsor=20(#4824)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/en/data/sponsors.yml | 3 +++ docs/en/data/sponsors_badge.yml | 1 + docs/en/docs/img/sponsors/budget-insight.svg | 22 ++++++++++++++++++++ 4 files changed, 27 insertions(+) create mode 100644 docs/en/docs/img/sponsors/budget-insight.svg diff --git a/README.md b/README.md index 3756053e8..9ad50f271 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index a216be04d..ac825193b 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -30,6 +30,9 @@ silver: - url: https://www.udemy.com/course/fastapi-rest/ title: Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails. img: https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg + - url: https://careers.budget-insight.com/ + title: Budget Insight is hiring! + img: https://fastapi.tiangolo.com/img/sponsors/budget-insight.svg bronze: - url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source title: Biosecurity risk assessments made easy. diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index e0288356a..1c8b0cde7 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -9,3 +9,4 @@ logins: - xoflare - InesIvanova - DropbaseHQ + - VincentParedes diff --git a/docs/en/docs/img/sponsors/budget-insight.svg b/docs/en/docs/img/sponsors/budget-insight.svg new file mode 100644 index 000000000..d753727a1 --- /dev/null +++ b/docs/en/docs/img/sponsors/budget-insight.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + From 146f57b8f70c5757dc20edc716dba1b96936a8d6 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 25 Apr 2022 10:02:17 +0000 Subject: [PATCH 450/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6c995148a..44c1b647e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add Budget Insight sponsor. PR [#4824](https://github.com/tiangolo/fastapi/pull/4824) by [@tiangolo](https://github.com/tiangolo). * 🍱 Update sponsor, ExoFlare badge. PR [#4822](https://github.com/tiangolo/fastapi/pull/4822) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, enable Dropbase again, update TalkPython link. PR [#4821](https://github.com/tiangolo/fastapi/pull/4821) by [@tiangolo](https://github.com/tiangolo). From 33d61430cf48a9442c0809b76564827bea6ea9ea Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 6 May 2022 00:19:59 +0200 Subject: [PATCH 451/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20Starlette=20from?= =?UTF-8?q?=200.17.1=20to=200.18.0=20(#4483)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/concurrency.py | 2 +- fastapi/dependencies/utils.py | 11 ++++------- fastapi/routing.py | 2 +- pyproject.toml | 4 +++- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/fastapi/concurrency.py b/fastapi/concurrency.py index 04382c69e..becac3f33 100644 --- a/fastapi/concurrency.py +++ b/fastapi/concurrency.py @@ -25,7 +25,7 @@ async def contextmanager_in_threadpool( try: yield await run_in_threadpool(cm.__enter__) except Exception as e: - ok = await run_in_threadpool(cm.__exit__, type(e), e, None) + ok: bool = await run_in_threadpool(cm.__exit__, type(e), e, None) if not ok: raise e else: diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index d4028d067..9dccd354e 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -462,13 +462,10 @@ async def solve_dependencies( ]: values: Dict[str, Any] = {} errors: List[ErrorWrapper] = [] - response = response or Response( - content=None, - status_code=None, # type: ignore - headers=None, # type: ignore # in Starlette - media_type=None, # type: ignore # in Starlette - background=None, # type: ignore # in Starlette - ) + if response is None: + response = Response() + del response.headers["content-length"] + response.status_code = None # type: ignore dependency_cache = dependency_cache or {} sub_dependant: Dependant for sub_dependant in dependant.dependencies: diff --git a/fastapi/routing.py b/fastapi/routing.py index 7a15f3965..6680c04ed 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -127,7 +127,7 @@ async def serialize_response( if is_coroutine: value, errors_ = field.validate(response_content, {}, loc=("response",)) else: - value, errors_ = await run_in_threadpool( + value, errors_ = await run_in_threadpool( # type: ignore[misc] field.validate, response_content, {}, loc=("response",) ) if isinstance(errors_, ErrorWrapper): diff --git a/pyproject.toml b/pyproject.toml index 7856085fb..1a2610740 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ classifiers = [ "Topic :: Internet :: WWW/HTTP", ] requires = [ - "starlette ==0.17.1", + "starlette ==0.18.0", "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0", ] description-file = "README.md" @@ -140,4 +140,6 @@ filterwarnings = [ "error", # TODO: needed by asyncio in Python 3.9.7 https://bugs.python.org/issue45097, try to remove on 3.9.8 'ignore:The loop argument is deprecated since Python 3\.8, and scheduled for removal in Python 3\.10:DeprecationWarning:asyncio', + # TODO: remove after dropping support for Python 3.6 + 'ignore:Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography and will be removed in a future release.:UserWarning:jose', ] From b44e85ca8a6e6cdf59c4da2541b12de808a0f539 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 5 May 2022 22:20:33 +0000 Subject: [PATCH 452/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 44c1b647e..93e713136 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade Starlette from 0.17.1 to 0.18.0. PR [#4483](https://github.com/tiangolo/fastapi/pull/4483) by [@Kludex](https://github.com/Kludex). * 🔧 Add Budget Insight sponsor. PR [#4824](https://github.com/tiangolo/fastapi/pull/4824) by [@tiangolo](https://github.com/tiangolo). * 🍱 Update sponsor, ExoFlare badge. PR [#4822](https://github.com/tiangolo/fastapi/pull/4822) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, enable Dropbase again, update TalkPython link. PR [#4821](https://github.com/tiangolo/fastapi/pull/4821) by [@tiangolo](https://github.com/tiangolo). From 66f634482034c0bd297b3b7fa9d458b98f74a606 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 May 2022 17:22:25 -0500 Subject: [PATCH 453/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#4847)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/github_sponsors.yml | 116 +++++++++++------------ docs/en/data/people.yml | 156 +++++++++++++++---------------- 2 files changed, 126 insertions(+), 146 deletions(-) diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml index 42339d262..db4a9acc6 100644 --- a/docs/en/data/github_sponsors.yml +++ b/docs/en/data/github_sponsors.yml @@ -5,10 +5,13 @@ sponsors: - login: jina-ai avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4 url: https://github.com/jina-ai -- - login: InesIvanova - avatarUrl: https://avatars.githubusercontent.com/u/22920417?u=409882ec1df6dbd77455788bb383a8de223dbf6f&v=4 - url: https://github.com/InesIvanova -- - login: chaserowbotham + - login: DropbaseHQ + avatarUrl: https://avatars.githubusercontent.com/u/85367855?v=4 + url: https://github.com/DropbaseHQ +- - login: sushi2all + avatarUrl: https://avatars.githubusercontent.com/u/1043732?v=4 + url: https://github.com/sushi2all + - login: chaserowbotham avatarUrl: https://avatars.githubusercontent.com/u/97751084?v=4 url: https://github.com/chaserowbotham - - login: mikeckennedy @@ -26,7 +29,19 @@ sponsors: - login: investsuite avatarUrl: https://avatars.githubusercontent.com/u/73833632?v=4 url: https://github.com/investsuite -- - login: qaas + - login: VincentParedes + avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4 + url: https://github.com/VincentParedes +- - login: plocher + avatarUrl: https://avatars.githubusercontent.com/u/1082871?v=4 + url: https://github.com/plocher +- - login: InesIvanova + avatarUrl: https://avatars.githubusercontent.com/u/22920417?u=409882ec1df6dbd77455788bb383a8de223dbf6f&v=4 + url: https://github.com/InesIvanova +- - login: SendCloud + avatarUrl: https://avatars.githubusercontent.com/u/7831959?v=4 + url: https://github.com/SendCloud + - login: qaas avatarUrl: https://avatars.githubusercontent.com/u/8503759?u=10a6b4391ad6ab4cf9487ce54e3fcb61322d1efc&v=4 url: https://github.com/qaas - login: xoflare @@ -44,9 +59,6 @@ sponsors: - login: HiredScore avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4 url: https://github.com/HiredScore - - login: spackle0 - avatarUrl: https://avatars.githubusercontent.com/u/6148423?u=750e21b7366c0de69c305a8bcda1365d921ae477&v=4 - url: https://github.com/spackle0 - login: wdwinslow avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 url: https://github.com/wdwinslow @@ -57,7 +69,7 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4 url: https://github.com/RodneyU215 - login: grillazz - avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=16d7d0ffa5dfb99f8834f8f76d90e138ba09b94a&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=0b32b7073ae1ab8b7f6d2db0188c2e1e357ff451&v=4 url: https://github.com/grillazz - login: tizz98 avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4 @@ -65,11 +77,8 @@ sponsors: - login: jmaralc avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4 url: https://github.com/jmaralc - - login: Filimoa - avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4 - url: https://github.com/Filimoa - login: marutoraman - avatarUrl: https://avatars.githubusercontent.com/u/33813153?v=4 + avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4 url: https://github.com/marutoraman - login: mainframeindustries avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4 @@ -77,10 +86,10 @@ sponsors: - login: A-Edge avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4 url: https://github.com/A-Edge -- - login: hcristea - avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=61d7a4fcf846983a4606788eac25e1c6c1209ba8&v=4 - url: https://github.com/hcristea -- - login: samuelcolvin +- - login: Kludex + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 + url: https://github.com/Kludex + - login: samuelcolvin avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4 url: https://github.com/samuelcolvin - login: jokull @@ -110,18 +119,12 @@ sponsors: - login: jqueguiner avatarUrl: https://avatars.githubusercontent.com/u/690878?u=e4835b2a985a0f2d52018e4926cb5a58c26a62e8&v=4 url: https://github.com/jqueguiner - - login: Mazyod - avatarUrl: https://avatars.githubusercontent.com/u/860511?v=4 - url: https://github.com/Mazyod - login: ltieman avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4 url: https://github.com/ltieman - login: westonsteimel avatarUrl: https://avatars.githubusercontent.com/u/1593939?u=0f2c0e3647f916fe295d62fa70da7a4c177115e3&v=4 url: https://github.com/westonsteimel - - login: timdrijvers - avatarUrl: https://avatars.githubusercontent.com/u/1694939?v=4 - url: https://github.com/timdrijvers - login: corleyma avatarUrl: https://avatars.githubusercontent.com/u/2080732?u=aed2ff652294a87d666b1c3f6dbe98104db76d26&v=4 url: https://github.com/corleyma @@ -185,15 +188,9 @@ sponsors: - login: Rehket avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4 url: https://github.com/Rehket - - login: christippett - avatarUrl: https://avatars.githubusercontent.com/u/7218120?u=f21f93b9c14edefef75645bf4d64c819b7d4afd7&v=4 - url: https://github.com/christippett - login: hiancdtrsnm avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4 url: https://github.com/hiancdtrsnm - - login: Kludex - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 - url: https://github.com/Kludex - login: Shackelford-Arden avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4 url: https://github.com/Shackelford-Arden @@ -215,9 +212,6 @@ sponsors: - login: robintully avatarUrl: https://avatars.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4 url: https://github.com/robintully - - login: tobiasfeil - avatarUrl: https://avatars.githubusercontent.com/u/17533713?u=bc6b0bec46f342d13c41695db90685d1c58d534e&v=4 - url: https://github.com/tobiasfeil - login: wedwardbeck avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4 url: https://github.com/wedwardbeck @@ -230,21 +224,21 @@ sponsors: - login: RedCarpetUp avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4 url: https://github.com/RedCarpetUp + - login: Filimoa + avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4 + url: https://github.com/Filimoa - login: shuheng-liu avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4 url: https://github.com/shuheng-liu - - login: comoelcometa - avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=c6751efa038561b9bc5fa56d1033d5174e10cd65&v=4 - url: https://github.com/comoelcometa + - login: cometa-haley + avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=cec1a3e0643b785288ae8260cc295a85ab344995&v=4 + url: https://github.com/cometa-haley - login: LarryGF avatarUrl: https://avatars.githubusercontent.com/u/26148349?u=431bb34d36d41c172466252242175281ae132152&v=4 url: https://github.com/LarryGF - login: veprimk avatarUrl: https://avatars.githubusercontent.com/u/29689749?u=f8cb5a15a286e522e5b189bc572d5a1a90217fb2&v=4 url: https://github.com/veprimk - - login: orihomie - avatarUrl: https://avatars.githubusercontent.com/u/29889683?u=6bc2135a52fcb3a49e69e7d50190796618185fda&v=4 - url: https://github.com/orihomie - login: meysam81 avatarUrl: https://avatars.githubusercontent.com/u/30233243?u=64dc9fc62d039892c6fb44d804251cad5537132b&v=4 url: https://github.com/meysam81 @@ -266,6 +260,9 @@ sponsors: - login: ybressler avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=6621dc9ab53b697912ab2a32211bb29ae90a9112&v=4 url: https://github.com/ybressler + - login: iamkarshe + avatarUrl: https://avatars.githubusercontent.com/u/43641892?u=d08c901b359c931784501740610d416558ff3e24&v=4 + url: https://github.com/iamkarshe - login: dbanty avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4 url: https://github.com/dbanty @@ -278,6 +275,9 @@ sponsors: - login: daisuke8000 avatarUrl: https://avatars.githubusercontent.com/u/55035595?u=5025e379cd3655ae1a96039efc85223a873d2e38&v=4 url: https://github.com/daisuke8000 + - login: yakkonaut + avatarUrl: https://avatars.githubusercontent.com/u/60633704?u=90a71fd631aa998ba4a96480788f017c9904e07b&v=4 + url: https://github.com/yakkonaut - login: primer-io avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4 url: https://github.com/primer-io @@ -293,9 +293,6 @@ sponsors: - login: anthonycepeda avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 url: https://github.com/anthonycepeda - - login: abdurrahim84 - avatarUrl: https://avatars.githubusercontent.com/u/79488613?v=4 - url: https://github.com/abdurrahim84 - login: NinaHwang avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 url: https://github.com/NinaHwang @@ -305,9 +302,6 @@ sponsors: - login: pyt3h avatarUrl: https://avatars.githubusercontent.com/u/99658549?v=4 url: https://github.com/pyt3h -- - login: '837477' - avatarUrl: https://avatars.githubusercontent.com/u/37999795?u=543b0bd0e8f283db0fc50754e5d13f6afba8cbea&v=4 - url: https://github.com/837477 - - login: linux-china avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4 url: https://github.com/linux-china @@ -353,9 +347,9 @@ sponsors: - login: hardbyte avatarUrl: https://avatars.githubusercontent.com/u/855189?u=aa29e92f34708814d6b67fcd47ca4cf2ce1c04ed&v=4 url: https://github.com/hardbyte - - login: clstaudt - avatarUrl: https://avatars.githubusercontent.com/u/875194?u=46a92f9f837d0ba150ae0f1d91091dd2f4ebb6cc&v=4 - url: https://github.com/clstaudt + - login: janfilips + avatarUrl: https://avatars.githubusercontent.com/u/870699?u=6034d81731ecb41ae5c717e56a901ed46fc039a8&v=4 + url: https://github.com/janfilips - login: scari avatarUrl: https://avatars.githubusercontent.com/u/964251?v=4 url: https://github.com/scari @@ -398,12 +392,12 @@ sponsors: - login: holec avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4 url: https://github.com/holec + - login: moonape1226 + avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4 + url: https://github.com/moonape1226 - login: davanstrien avatarUrl: https://avatars.githubusercontent.com/u/8995957?u=fb2aad2b52bb4e7b56db6d7c8ecc9ae1eac1b984&v=4 url: https://github.com/davanstrien - - login: and-semakin - avatarUrl: https://avatars.githubusercontent.com/u/9129071?u=ea77ddf7de4bc375d546bf2825ed420eaddb7666&v=4 - url: https://github.com/and-semakin - login: yenchenLiu avatarUrl: https://avatars.githubusercontent.com/u/9199638?u=8cdf5ae507448430d90f6f3518d1665a23afe99b&v=4 url: https://github.com/yenchenLiu @@ -419,6 +413,9 @@ sponsors: - login: hard-coders avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4 url: https://github.com/hard-coders + - login: satwikkansal + avatarUrl: https://avatars.githubusercontent.com/u/10217535?u=b12d6ef74ea297de9e46da6933b1a5b7ba9e6a61&v=4 + url: https://github.com/satwikkansal - login: pheanex avatarUrl: https://avatars.githubusercontent.com/u/10408624?u=5b6bab6ee174aa6e991333e06eb29f628741013d&v=4 url: https://github.com/pheanex @@ -458,18 +455,15 @@ sponsors: - login: d-e-h-i-o avatarUrl: https://avatars.githubusercontent.com/u/36816716?v=4 url: https://github.com/d-e-h-i-o - - login: askurihin - avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4 - url: https://github.com/askurihin - login: ilias-ant avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4 url: https://github.com/ilias-ant - login: arrrrrmin avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=fee5739394fea074cb0b66929d070114a5067aae&v=4 url: https://github.com/arrrrrmin - - login: igorezersky - avatarUrl: https://avatars.githubusercontent.com/u/46680020?u=a20a595c881dbe5658c906fecc7eff125efb4fd4&v=4 - url: https://github.com/igorezersky + - login: Nephilim-Jack + avatarUrl: https://avatars.githubusercontent.com/u/48372168?u=6f2bb405238d7efc467536fe01f58df6779c58a9&v=4 + url: https://github.com/Nephilim-Jack - login: akanz1 avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4 url: https://github.com/akanz1 @@ -488,20 +482,14 @@ sponsors: - login: alessio-proietti avatarUrl: https://avatars.githubusercontent.com/u/67370599?u=8ac73db1e18e946a7681f173abdb640516f88515&v=4 url: https://github.com/alessio-proietti -- - login: spyker77 - avatarUrl: https://avatars.githubusercontent.com/u/4953435?u=03c724c6f8fbab5cd6575b810c0c91c652fa4f79&v=4 - url: https://github.com/spyker77 - - login: backbord +- - login: backbord avatarUrl: https://avatars.githubusercontent.com/u/6814946?v=4 url: https://github.com/backbord - login: sadikkuzu avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4 url: https://github.com/sadikkuzu - - login: MoronVV - avatarUrl: https://avatars.githubusercontent.com/u/24293616?v=4 - url: https://github.com/MoronVV - login: gabrielmbmb - avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=92084ed7242160dee4d20aece923a10c59758ee5&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=6d1e00b5d558e96718312ff910a2318f47cc3145&v=4 url: https://github.com/gabrielmbmb - login: danburonline avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4 diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 2f05b3e6b..92aab109f 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,12 +1,12 @@ maintainers: - login: tiangolo - answers: 1240 - prs: 291 + answers: 1243 + prs: 300 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=5cad72c846b7aba2e960546af490edc7375dafc4&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 330 + count: 335 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: dmontagu @@ -35,7 +35,7 @@ experts: url: https://github.com/raphaelauv - login: ArcLightSlavik count: 71 - avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4 url: https://github.com/ArcLightSlavik - login: falkben count: 58 @@ -57,10 +57,18 @@ experts: count: 39 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 url: https://github.com/includeamin +- login: jgould22 + count: 38 + avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 + url: https://github.com/jgould22 - login: STeveShary count: 37 avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 url: https://github.com/STeveShary +- login: adriangb + count: 36 + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 + url: https://github.com/adriangb - login: prostomarkeloff count: 33 avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4 @@ -69,10 +77,6 @@ experts: count: 31 avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 url: https://github.com/frankie567 -- login: adriangb - count: 31 - avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 - url: https://github.com/adriangb - login: krishnardt count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 @@ -82,7 +86,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes - login: chbndrhnns - count: 26 + count: 28 avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 url: https://github.com/chbndrhnns - login: panla @@ -101,10 +105,6 @@ experts: count: 24 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak -- login: jgould22 - count: 23 - avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 - url: https://github.com/jgould22 - login: acnebs count: 22 avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4 @@ -141,6 +141,10 @@ experts: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 url: https://github.com/harunyasar +- login: rafsaf + count: 17 + avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 + url: https://github.com/rafsaf - login: waynerv count: 16 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 @@ -149,14 +153,14 @@ experts: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 url: https://github.com/dstlny -- login: rafsaf - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 - url: https://github.com/rafsaf - login: haizaar count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar +- login: valentin994 + count: 13 + avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4 + url: https://github.com/valentin994 - login: hellocoldworld count: 12 avatarUrl: https://avatars.githubusercontent.com/u/47581948?v=4 @@ -165,6 +169,14 @@ experts: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4 url: https://github.com/David-Lor +- login: yinziyan1206 + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4 + url: https://github.com/yinziyan1206 +- login: jonatasoli + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4 + url: https://github.com/jonatasoli - login: lowercase00 count: 11 avatarUrl: https://avatars.githubusercontent.com/u/21188280?v=4 @@ -177,55 +189,35 @@ experts: count: 11 avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4 url: https://github.com/juntatalor -- login: valentin994 +- login: n8sty count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4 - url: https://github.com/valentin994 + avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 + url: https://github.com/n8sty - login: aalifadv count: 11 avatarUrl: https://avatars.githubusercontent.com/u/78442260?v=4 url: https://github.com/aalifadv -- login: stefanondisponibile - count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4 - url: https://github.com/stefanondisponibile -- login: oligond - count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/2858306?u=1bb1182a5944e93624b7fb26585f22c8f7a9d76e&v=4 - url: https://github.com/oligond -- login: n8sty - count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 - url: https://github.com/n8sty last_month_active: -- login: yinziyan1206 - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4 - url: https://github.com/yinziyan1206 -- login: Kludex - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 - url: https://github.com/Kludex -- login: jd-0001 - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/47495003?u=322eedc0931b62827cf5f239654f77bfaff76b46&v=4 - url: https://github.com/jd-0001 -- login: harunyasar - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 - url: https://github.com/harunyasar -- login: wmcgee3 - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/61711986?u=c51ebfaf8a995019fda8288690f4a009ecf070f0&v=4 - url: https://github.com/wmcgee3 -- login: tasercake - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/13855549?v=4 - url: https://github.com/tasercake - login: jgould22 - count: 3 + count: 15 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 url: https://github.com/jgould22 +- login: accelleon + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/5001614?v=4 + url: https://github.com/accelleon +- login: jonatasoli + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4 + url: https://github.com/jonatasoli +- login: Kludex + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 + url: https://github.com/Kludex +- login: yinziyan1206 + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4 + url: https://github.com/yinziyan1206 top_contributors: - login: waynerv count: 25 @@ -259,14 +251,14 @@ top_contributors: count: 8 avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 url: https://github.com/Serrones +- login: Kludex + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 + url: https://github.com/Kludex - login: RunningIkkyu count: 7 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 url: https://github.com/RunningIkkyu -- login: Kludex - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 - url: https://github.com/Kludex - login: hard-coders count: 7 avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4 @@ -328,30 +320,34 @@ top_reviewers: count: 41 avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 url: https://github.com/cikay +- login: BilalAlpaslan + count: 40 + avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 + url: https://github.com/BilalAlpaslan - login: AdrianDeAnda count: 33 avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4 url: https://github.com/AdrianDeAnda - login: ArcLightSlavik count: 31 - avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4 url: https://github.com/ArcLightSlavik -- login: BilalAlpaslan - count: 28 - avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 - url: https://github.com/BilalAlpaslan +- login: cassiobotaro + count: 25 + avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 + url: https://github.com/cassiobotaro - login: dmontagu count: 23 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu -- login: cassiobotaro - count: 23 - avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 - url: https://github.com/cassiobotaro - login: komtaki count: 21 avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki +- login: yezz123 + count: 19 + avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 + url: https://github.com/yezz123 - login: hard-coders count: 19 avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4 @@ -364,10 +360,6 @@ top_reviewers: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4 url: https://github.com/zy7y -- login: yezz123 - count: 16 - avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 - url: https://github.com/yezz123 - login: yanever count: 16 avatarUrl: https://avatars.githubusercontent.com/u/21978760?v=4 @@ -452,6 +444,10 @@ top_reviewers: count: 8 avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 url: https://github.com/ComicShrimp +- login: NinaHwang + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 + url: https://github.com/NinaHwang - login: dimaqq count: 8 avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4 @@ -476,14 +472,14 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause +- login: AlexandreBiguet + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/1483079?u=ff926455cd4cab03c6c49441aa5dc2b21df3e266&v=4 + url: https://github.com/AlexandreBiguet - login: krocdort count: 7 avatarUrl: https://avatars.githubusercontent.com/u/34248814?v=4 url: https://github.com/krocdort -- login: NinaHwang - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 - url: https://github.com/NinaHwang - login: jovicon count: 6 avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 @@ -496,7 +492,3 @@ top_reviewers: count: 6 avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=88c2cb42a99e0f50cdeae3606992568184783ee5&v=4 url: https://github.com/peidrao -- login: diogoduartec - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/31852339?u=b50fc11c531e9b77922e19edfc9e7233d4d7b92e&v=4 - url: https://github.com/diogoduartec From 792285a047ec04a073e855368afa485758a606a7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 5 May 2022 22:22:57 +0000 Subject: [PATCH 454/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 93e713136..1ab811704 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#4847](https://github.com/tiangolo/fastapi/pull/4847) by [@github-actions[bot]](https://github.com/apps/github-actions). * ⬆ Upgrade Starlette from 0.17.1 to 0.18.0. PR [#4483](https://github.com/tiangolo/fastapi/pull/4483) by [@Kludex](https://github.com/Kludex). * 🔧 Add Budget Insight sponsor. PR [#4824](https://github.com/tiangolo/fastapi/pull/4824) by [@tiangolo](https://github.com/tiangolo). * 🍱 Update sponsor, ExoFlare badge. PR [#4822](https://github.com/tiangolo/fastapi/pull/4822) by [@tiangolo](https://github.com/tiangolo). From 8df8b037f269b0eacbcf534686ddd2d66668bb4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 5 May 2022 17:25:14 -0500 Subject: [PATCH 455/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1ab811704..27dbe9d52 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,8 +2,13 @@ ## Latest Changes -* 👥 Update FastAPI People. PR [#4847](https://github.com/tiangolo/fastapi/pull/4847) by [@github-actions[bot]](https://github.com/apps/github-actions). +### Upgrades + * ⬆ Upgrade Starlette from 0.17.1 to 0.18.0. PR [#4483](https://github.com/tiangolo/fastapi/pull/4483) by [@Kludex](https://github.com/Kludex). + +### Internal + +* 👥 Update FastAPI People. PR [#4847](https://github.com/tiangolo/fastapi/pull/4847) by [@github-actions[bot]](https://github.com/apps/github-actions). * 🔧 Add Budget Insight sponsor. PR [#4824](https://github.com/tiangolo/fastapi/pull/4824) by [@tiangolo](https://github.com/tiangolo). * 🍱 Update sponsor, ExoFlare badge. PR [#4822](https://github.com/tiangolo/fastapi/pull/4822) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, enable Dropbase again, update TalkPython link. PR [#4821](https://github.com/tiangolo/fastapi/pull/4821) by [@tiangolo](https://github.com/tiangolo). From 9090c771eea9a51b17d0eb76dd060edd9f2e640e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 5 May 2022 17:26:05 -0500 Subject: [PATCH 456/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.76?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 27dbe9d52..3ffb956cd 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.76.0 + ### Upgrades * ⬆ Upgrade Starlette from 0.17.1 to 0.18.0. PR [#4483](https://github.com/tiangolo/fastapi/pull/4483) by [@Kludex](https://github.com/Kludex). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 22d8e51ec..fcd036ee4 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.75.2" +__version__ = "0.76.0" from starlette import status as status From 86fa3cb24ff01578dddef6aa67f28d6abdfcbfce Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Mon, 9 May 2022 20:06:42 +0200 Subject: [PATCH 457/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20Starlette=20from?= =?UTF-8?q?=200.18.0=20to=200.19.0=20(#4488)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/exceptions.py | 5 +++-- pyproject.toml | 3 ++- tests/test_extra_routes.py | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py index f4a837bb4..fcb718748 100644 --- a/fastapi/exceptions.py +++ b/fastapi/exceptions.py @@ -12,8 +12,9 @@ class HTTPException(StarletteHTTPException): detail: Any = None, headers: Optional[Dict[str, Any]] = None, ) -> None: - super().__init__(status_code=status_code, detail=detail) - self.headers = headers + super().__init__( + status_code=status_code, detail=detail, headers=headers # type: ignore + ) RequestErrorModel: Type[BaseModel] = create_model("Request") diff --git a/pyproject.toml b/pyproject.toml index 1a2610740..fc803f8fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ classifiers = [ "Topic :: Internet :: WWW/HTTP", ] requires = [ - "starlette ==0.18.0", + "starlette==0.19.0", "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0", ] description-file = "README.md" @@ -140,6 +140,7 @@ filterwarnings = [ "error", # TODO: needed by asyncio in Python 3.9.7 https://bugs.python.org/issue45097, try to remove on 3.9.8 'ignore:The loop argument is deprecated since Python 3\.8, and scheduled for removal in Python 3\.10:DeprecationWarning:asyncio', + 'ignore:starlette.middleware.wsgi is deprecated and will be removed in a future release\..*:DeprecationWarning:starlette', # TODO: remove after dropping support for Python 3.6 'ignore:Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography and will be removed in a future release.:UserWarning:jose', ] diff --git a/tests/test_extra_routes.py b/tests/test_extra_routes.py index 8f95b7bc9..491ba61c6 100644 --- a/tests/test_extra_routes.py +++ b/tests/test_extra_routes.py @@ -32,12 +32,12 @@ def delete_item(item_id: str, item: Item): @app.head("/items/{item_id}") def head_item(item_id: str): - return JSONResponse(headers={"x-fastapi-item-id": item_id}) + return JSONResponse(None, headers={"x-fastapi-item-id": item_id}) @app.options("/items/{item_id}") def options_item(item_id: str): - return JSONResponse(headers={"x-fastapi-item-id": item_id}) + return JSONResponse(None, headers={"x-fastapi-item-id": item_id}) @app.patch("/items/{item_id}") @@ -47,7 +47,7 @@ def patch_item(item_id: str, item: Item): @app.trace("/items/{item_id}") def trace_item(item_id: str): - return JSONResponse(media_type="message/http") + return JSONResponse(None, media_type="message/http") client = TestClient(app) From ee4e27a94f5b3c8a5e5f64b27e3b9bb209c69f29 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 18:07:21 +0000 Subject: [PATCH 458/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3ffb956cd..e0b44f569 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade Starlette from 0.18.0 to 0.19.0. PR [#4488](https://github.com/tiangolo/fastapi/pull/4488) by [@Kludex](https://github.com/Kludex). ## 0.76.0 From 12342888d6122648f5862375a36560b38efe0a5d Mon Sep 17 00:00:00 2001 From: Jonas Mueller Date: Mon, 9 May 2022 20:16:02 +0200 Subject: [PATCH 459/814] =?UTF-8?q?=F0=9F=8C=90=20Update=20German=20transl?= =?UTF-8?q?ation=20for=20`docs/features.md`=20(#3905)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/de/docs/features.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/de/docs/features.md b/docs/de/docs/features.md index f56257e7e..a92a2bfeb 100644 --- a/docs/de/docs/features.md +++ b/docs/de/docs/features.md @@ -13,7 +13,7 @@ ### Automatische Dokumentation -Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzerschnittstellen. Da FastAPI auf OpenAPI basiert, gibt es hierzu mehrere Optionen, wobei zwei standartmäßig vorhanden sind. +Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzerschnittstellen. Da FastAPI auf OpenAPI basiert, gibt es hierzu mehrere Optionen, wobei zwei standardmäßig vorhanden sind. * Swagger UI, bietet interaktive Exploration: testen und rufen Sie ihre API direkt vom Webbrowser auf. @@ -97,9 +97,9 @@ Hierdurch werden Sie nie wieder einen falschen Schlüsselnamen benutzen und spar ### Kompakt -FastAPI nutzt für alles sensible **Standard-Einstellungen**, welche optional überall konfiguriert werden können. Alle Parameter können ganz genau an Ihre Bedürfnisse angepasst werden, sodass sie genau die API definieren können, die sie brachen. +FastAPI nutzt für alles sinnvolle **Standard-Einstellungen**, welche optional überall konfiguriert werden können. Alle Parameter können ganz genau an Ihre Bedürfnisse angepasst werden, sodass sie genau die API definieren können, die sie brauchen. -Aber standartmäßig, **"funktioniert einfach"** alles. +Aber standardmäßig, **"funktioniert einfach"** alles. ### Validierung @@ -109,7 +109,7 @@ Aber standartmäßig, **"funktioniert einfach"** alles. * Zeichenketten (`str`), mit definierter minimaler und maximaler Länge. * Zahlen (`int`, `float`) mit minimaler und maximaler Größe, usw. -* Validierung für ungewögnliche Typen, wie: +* Validierung für ungewöhnliche Typen, wie: * URL. * Email. * UUID. @@ -142,8 +142,8 @@ FastAPI enthält ein extrem einfaches, aber extrem mächtiges Starlette. Das bedeutet, auch ihr eigner Starlett Quellcode funktioniert. +**FastAPI** ist vollkommen kompatibel (und basiert auf) Starlette. Das bedeutet, auch ihr eigener Starlette Quellcode funktioniert. -`FastAPI` ist eigentlich eine Unterklasse von `Starlette`. Wenn sie also bereits Starlette kennen oder benutzen, können Sie das meiste Ihres Wissen direkt anwenden. +`FastAPI` ist eigentlich eine Unterklasse von `Starlette`. Wenn Sie also bereits Starlette kennen oder benutzen, können Sie das meiste Ihres Wissens direkt anwenden. Mit **FastAPI** bekommen Sie viele von **Starlette**'s Funktionen (da FastAPI nur Starlette auf Steroiden ist): @@ -199,5 +199,5 @@ Mit **FastAPI** bekommen Sie alle Funktionen von **Pydantic** (da FastAPI für d * Validierungen erlauben klare und einfache Datenschemadefinition, überprüft und dokumentiert als JSON Schema. * Sie können stark **verschachtelte JSON** Objekte haben und diese sind trotzdem validiert und annotiert. * **Erweiterbar**: - * Pydantic erlaubt die Definition von eigenen Datentypen oder sie können die Validierung mit einer `validator` dekorierten Methode erweitern.. + * Pydantic erlaubt die Definition von eigenen Datentypen oder Sie können die Validierung mit einer `validator` dekorierten Methode erweitern.. * 100% Testabdeckung. From 65ed4b5433d39bcea1c38e904509332f2c01b5d0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 18:16:44 +0000 Subject: [PATCH 460/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e0b44f569..98ba7a8db 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Update German translation for `docs/features.md`. PR [#3905](https://github.com/tiangolo/fastapi/pull/3905) by [@jomue](https://github.com/jomue). * ⬆ Upgrade Starlette from 0.18.0 to 0.19.0. PR [#4488](https://github.com/tiangolo/fastapi/pull/4488) by [@Kludex](https://github.com/Kludex). ## 0.76.0 From f4620c42cffe3ee57af0fdd35506dfb84dd84534 Mon Sep 17 00:00:00 2001 From: Luccas Mateus Date: Mon, 9 May 2022 15:19:49 -0300 Subject: [PATCH 461/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20of=20`tutorial/extra-data-types.md`=20(#4077)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lorhan Sohaky <16273730+LorhanSohaky@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/extra-data-types.md | 66 +++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 67 insertions(+) create mode 100644 docs/pt/docs/tutorial/extra-data-types.md diff --git a/docs/pt/docs/tutorial/extra-data-types.md b/docs/pt/docs/tutorial/extra-data-types.md new file mode 100644 index 000000000..e4b9913dc --- /dev/null +++ b/docs/pt/docs/tutorial/extra-data-types.md @@ -0,0 +1,66 @@ +# Tipos de dados extras + +Até agora, você tem usado tipos de dados comuns, tais como: + +* `int` +* `float` +* `str` +* `bool` + +Mas você também pode usar tipos de dados mais complexos. + +E você ainda terá os mesmos recursos que viu até agora: + +* Ótimo suporte do editor. +* Conversão de dados das requisições recebidas. +* Conversão de dados para os dados da resposta. +* Validação de dados. +* Anotação e documentação automáticas. + +## Outros tipos de dados + +Aqui estão alguns dos tipos de dados adicionais que você pode usar: + +* `UUID`: + * Um "Identificador Universalmente Único" padrão, comumente usado como ID em muitos bancos de dados e sistemas. + * Em requisições e respostas será representado como uma `str`. +* `datetime.datetime`: + * O `datetime.datetime` do Python. + * Em requisições e respostas será representado como uma `str` no formato ISO 8601, exemplo: `2008-09-15T15:53:00+05:00`. +* `datetime.date`: + * O `datetime.date` do Python. + * Em requisições e respostas será representado como uma `str` no formato ISO 8601, exemplo: `2008-09-15`. +* `datetime.time`: + * O `datetime.time` do Python. + * Em requisições e respostas será representado como uma `str` no formato ISO 8601, exemplo: `14:23:55.003`. +* `datetime.timedelta`: + * O `datetime.timedelta` do Python. + * Em requisições e respostas será representado como um `float` de segundos totais. + * O Pydantic também permite representá-lo como uma "codificação ISO 8601 diferença de tempo", cheque a documentação para mais informações. +* `frozenset`: + * Em requisições e respostas, será tratado da mesma forma que um `set`: + * Nas requisições, uma lista será lida, eliminando duplicadas e convertendo-a em um `set`. + * Nas respostas, o `set` será convertido para uma `list`. + * O esquema gerado vai especificar que os valores do `set` são unicos (usando o `uniqueItems` do JSON Schema). +* `bytes`: + * O `bytes` padrão do Python. + * Em requisições e respostas será representado como uma `str`. + * O esquema gerado vai especificar que é uma `str` com o "formato" `binary`. +* `Decimal`: + * O `Decimal` padrão do Python. + * Em requisições e respostas será representado como um `float`. +* Você pode checar todos os tipos de dados válidos do Pydantic aqui: Tipos de dados do Pydantic. + +## Exemplo + +Aqui está um exemplo de *operação de rota* com parâmetros utilizando-se de alguns dos tipos acima. + +```Python hl_lines="1 3 12-16" +{!../../../docs_src/extra_data_types/tutorial001.py!} +``` + +Note que os parâmetros dentro da função tem seu tipo de dados natural, e você pode, por exemplo, realizar manipulações normais de data, como: + +```Python hl_lines="18-19" +{!../../../docs_src/extra_data_types/tutorial001.py!} +``` diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 4861602e4..29dafa496 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -61,6 +61,7 @@ nav: - tutorial/first-steps.md - tutorial/path-params.md - tutorial/body-fields.md + - tutorial/extra-data-types.md - tutorial/query-params-str-validations.md - Segurança: - tutorial/security/index.md From 260d97ec6f97293c7bc0590209693534f87d6193 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 18:20:27 +0000 Subject: [PATCH 462/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 98ba7a8db..9812de2e3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation of `tutorial/extra-data-types.md`. PR [#4077](https://github.com/tiangolo/fastapi/pull/4077) by [@luccasmmg](https://github.com/luccasmmg). * 🌐 Update German translation for `docs/features.md`. PR [#3905](https://github.com/tiangolo/fastapi/pull/3905) by [@jomue](https://github.com/jomue). * ⬆ Upgrade Starlette from 0.18.0 to 0.19.0. PR [#4488](https://github.com/tiangolo/fastapi/pull/4488) by [@Kludex](https://github.com/Kludex). From 3005c8c7b918c8985a5e5328cd62189aad303444 Mon Sep 17 00:00:00 2001 From: Leandro de Souza <85115541+leandrodesouzadev@users.noreply.github.com> Date: Mon, 9 May 2022 15:25:41 -0300 Subject: [PATCH 463/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/tutorial/body.md`=20(#3960)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marcelo Trylesinski Co-authored-by: Lucas <61513630+lsglucas@users.noreply.github.com> Co-authored-by: Leandro de Souza Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/body.md | 165 ++++++++++++++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 166 insertions(+) create mode 100644 docs/pt/docs/tutorial/body.md diff --git a/docs/pt/docs/tutorial/body.md b/docs/pt/docs/tutorial/body.md new file mode 100644 index 000000000..5891185f3 --- /dev/null +++ b/docs/pt/docs/tutorial/body.md @@ -0,0 +1,165 @@ +# Corpo da Requisição + +Quando você precisa enviar dados de um cliente (como de um navegador web) para sua API, você o envia como um **corpo da requisição**. + +O corpo da **requisição** é a informação enviada pelo cliente para sua API. O corpo da **resposta** é a informação que sua API envia para o cliente. + +Sua API quase sempre irá enviar um corpo na **resposta**. Mas os clientes não necessariamente precisam enviar um corpo em toda **requisição**. + +Para declarar um corpo da **requisição**, você utiliza os modelos do Pydantic com todos os seus poderes e benefícios. + +!!! info "Informação" + Para enviar dados, você deve usar utilizar um dos métodos: `POST` (Mais comum), `PUT`, `DELETE` ou `PATCH`. + + Enviar um corpo em uma requisição `GET` não tem um comportamento definido nas especificações, porém é suportado pelo FastAPI, apenas para casos de uso bem complexos/extremos. + + Como é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição para um `GET`, e proxies que intermediarem podem não suportar o corpo da requisição. + +## Importe o `BaseModel` do Pydantic + +Primeiro, você precisa importar `BaseModel` do `pydantic`: + +```Python hl_lines="4" +{!../../../docs_src/body/tutorial001.py!} +``` + +## Crie seu modelo de dados + +Então você declara seu modelo de dados como uma classe que herda `BaseModel`. + +Utilize os tipos Python padrão para todos os atributos: + +```Python hl_lines="7-11" +{!../../../docs_src/body/tutorial001.py!} +``` + +Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele se torna opcional. Caso contrário, se torna obrigatório. Use `None` para torná-lo opcional. + +Por exemplo, o modelo acima declara um JSON "`object`" (ou `dict` no Python) como esse: + +```JSON +{ + "name": "Foo", + "description": "Uma descrição opcional", + "price": 45.2, + "tax": 3.5 +} +``` + +...como `description` e `tax` são opcionais (Com um valor padrão de `None`), esse JSON "`object`" também é válido: + +```JSON +{ + "name": "Foo", + "price": 45.2 +} +``` + +## Declare como um parâmetro + +Para adicionar o corpo na *função de operação de rota*, declare-o da mesma maneira que você declarou parâmetros de rota e consulta: + +```Python hl_lines="18" +{!../../../docs_src/body/tutorial001.py!} +``` + +...E declare o tipo como o modelo que você criou, `Item`. + +## Resultados + +Apenas com esse declaração de tipos do Python, o **FastAPI** irá: + +* Ler o corpo da requisição como um JSON. +* Converter os tipos correspondentes (se necessário). +* Validar os dados. + * Se algum dados for inválido, irá retornar um erro bem claro, indicando exatamente onde e o que está incorreto. +* Entregar a você a informação recebida no parâmetro `item`. + * Como você o declarou na função como do tipo `Item`, você também terá o suporte do editor (completação, etc) para todos os atributos e seus tipos. +* Gerar um Esquema JSON com as definições do seu modelo, você também pode utilizá-lo em qualquer lugar que quiser, se fizer sentido para seu projeto. +* Esses esquemas farão parte do esquema OpenAPI, e utilizados nas UIs de documentação automática. + +## Documentação automática + +Os esquemas JSON dos seus modelos farão parte do esquema OpenAPI gerado para sua aplicação, e aparecerão na documentação interativa da API: + + + +E também serão utilizados em cada *função de operação de rota* que utilizá-los: + + + +## Suporte do editor de texto: + +No seu editor de texto, dentro da função você receberá dicas de tipos e completação em todo lugar (isso não aconteceria se você recebesse um `dict` em vez de um modelo Pydantic): + + + +Você também poderá receber verificações de erros para operações de tipos incorretas: + + + +Isso não é por acaso, todo o framework foi construído em volta deste design. + +E foi imensamente testado na fase de design, antes de qualquer implementação, para garantir que funcionaria para todos os editores de texto. + +Houveram mudanças no próprio Pydantic para que isso fosse possível. + +As capturas de tela anteriores foram capturas no Visual Studio Code. + +Mas você terá o mesmo suporte do editor no PyCharm e na maioria dos editores Python: + + + +!!! tip "Dica" + Se você utiliza o PyCharm como editor, você pode utilizar o Plugin do Pydantic para o PyCharm . + + Melhora o suporte do editor para seus modelos Pydantic com:: + + * completação automática + * verificação de tipos + * refatoração + * buscas + * inspeções + +## Use o modelo + +Dentro da função, você pode acessar todos os atributos do objeto do modelo diretamente: + +```Python hl_lines="21" +{!../../../docs_src/body/tutorial002.py!} +``` + +## Corpo da requisição + parâmetros de rota + +Você pode declarar parâmetros de rota e corpo da requisição ao mesmo tempo. + +O **FastAPI** irá reconhecer que os parâmetros da função que combinam com parâmetros de rota devem ser **retirados da rota**, e parâmetros da função que são declarados como modelos Pydantic sejam **retirados do corpo da requisição**. + +```Python hl_lines="17-18" +{!../../../docs_src/body/tutorial003.py!} +``` + +## Corpo da requisição + parâmetros de rota + parâmetros de consulta + +Você também pode declarar parâmetros de **corpo**, **rota** e **consulta**, ao mesmo tempo. + +O **FastAPI** irá reconhecer cada um deles e retirar a informação do local correto. + +```Python hl_lines="18" +{!../../../docs_src/body/tutorial004.py!} +``` + +Os parâmetros da função serão reconhecidos conforme abaixo: + +* Se o parâmetro também é declarado na **rota**, será utilizado como um parâmetro de rota. +* Se o parâmetro é de um **tipo único** (como `int`, `float`, `str`, `bool`, etc) será interpretado como um parâmetro de **consulta**. +* Se o parâmetro é declarado como um **modelo Pydantic**, será interpretado como o **corpo** da requisição. + +!!! note "Observação" + O FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`. + + O `Optional` em `Optional[str]` não é utilizado pelo FastAPI, mas permite ao seu editor de texto lhe dar um suporte melhor e detectar erros. + +## Sem o Pydantic + +Se você não quer utilizar os modelos Pydantic, você também pode utilizar o parâmetro **Body**. Veja a documentação para [Body - Parâmetros múltiplos: Valores singulares no body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 29dafa496..f6bcdcf02 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -60,6 +60,7 @@ nav: - tutorial/index.md - tutorial/first-steps.md - tutorial/path-params.md + - tutorial/body.md - tutorial/body-fields.md - tutorial/extra-data-types.md - tutorial/query-params-str-validations.md From b7d57467733805e004e8315ed56a910ec192e9ee Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 18:26:23 +0000 Subject: [PATCH 464/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9812de2e3..3c706ce5c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/tutorial/body.md`. PR [#3960](https://github.com/tiangolo/fastapi/pull/3960) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). * 🌐 Add Portuguese translation of `tutorial/extra-data-types.md`. PR [#4077](https://github.com/tiangolo/fastapi/pull/4077) by [@luccasmmg](https://github.com/luccasmmg). * 🌐 Update German translation for `docs/features.md`. PR [#3905](https://github.com/tiangolo/fastapi/pull/3905) by [@jomue](https://github.com/jomue). * ⬆ Upgrade Starlette from 0.18.0 to 0.19.0. PR [#4488](https://github.com/tiangolo/fastapi/pull/4488) by [@Kludex](https://github.com/Kludex). From e0962d0b54e401287ba69e6d1570b9b7ea302e33 Mon Sep 17 00:00:00 2001 From: Makarov Andrey Date: Mon, 9 May 2022 21:30:19 +0300 Subject: [PATCH 465/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Russian=20translat?= =?UTF-8?q?ion=20for=20`docs/async.md`=20(#4036)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/ru/docs/async.md | 505 ++++++++++++++++++++++++++++++++++++++++++ docs/ru/mkdocs.yml | 1 + 2 files changed, 506 insertions(+) create mode 100644 docs/ru/docs/async.md diff --git a/docs/ru/docs/async.md b/docs/ru/docs/async.md new file mode 100644 index 000000000..fc5e44471 --- /dev/null +++ b/docs/ru/docs/async.md @@ -0,0 +1,505 @@ +# Конкурентность и async / await + +Здесь приведена подробная информация об использовании синтаксиса `async def` при написании *функций обработки пути*, а также рассмотрены основы асинхронного программирования, конкурентности и параллелизма. + +## Нет времени? + +TL;DR: + +Допустим, вы используете сторонюю библиотеку, которая требует вызова с ключевым словом `await`: + +```Python +results = await some_library() +``` + +В этом случае *функции обработки пути* необходимо объявлять с использованием синтаксиса `async def`: + +```Python hl_lines="2" +@app.get('/') +async def read_results(): + results = await some_library() + return results +``` + +!!! note + `await` можно использовать только внутри функций, объявленных с использованием `async def`. + +--- + +Если вы обращаетесь к сторонней библиотеке, которая с чем-то взаимодействует +(с базой данных, API, файловой системой и т. д.), и не имеет поддержки синтаксиса `await` +(что относится сейчас к большинству библиотек для работы с базами данных), то +объявляйте *функции обработки пути* обычным образом с помощью `def`, например: + +```Python hl_lines="2" +@app.get('/') +def results(): + results = some_library() + return results +``` + +--- + +Если вашему приложению (странным образом) не нужно ни с чем взаимодействовать и, соответственно, +ожидать ответа, используйте `async def`. + +--- + +Если вы не уверены, используйте обычный синтаксис `def`. + +--- + +**Примечание**: при необходимости можно смешивать `def` и `async def` в *функциях обработки пути* +и использовать в каждом случае наиболее подходящий синтаксис. А FastAPI сделает с этим всё, что нужно. + +В любом из описанных случаев FastAPI работает асинхронно и очень быстро. + +Однако придерживаясь указанных советов, можно получить дополнительную оптимизацию производительности. + +## Технические подробности + +Современные версии Python поддерживают разработку так называемого **"асинхронного кода"** посредством написания **"сопрограмм"** с использованием синтаксиса **`async` и `await`**. + +Ниже разберём эту фразу по частям: + +* **Асинхронный код** +* **`async` и `await`** +* **Сопрограммы** + +## Асинхронный код + +Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖, +что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝. + +И пока мы ждём завершения работы с "медленным файлом" 📝, компьютер может переключиться для выполнения других задач. + +Но при каждой возможности компьютер / программа 🤖 будет возвращаться обратно. Например, если он 🤖 опять окажется в режиме ожидания, или когда закончит всю работу. В этом случае компьютер 🤖 проверяет, не завершена ли какая-нибудь из текущих задач. + +Потом он 🤖 берёт первую выполненную задачу (допустим, наш "медленный файл" 📝) и продолжает работу, производя с ней необходимые действия. + +Вышеупомянутое "что-то ещё", завершения которого приходится ожидать, обычно относится к достаточно "медленным" операциям I/O (по сравнению со скоростью работы процессора и оперативной памяти), например: + +* отправка данных от клиента по сети +* получение клиентом данных, отправленных вашей программой по сети +* чтение системой содержимого файла с диска и передача этих данных программе +* запись на диск данных, которые программа передала системе +* обращение к удалённому API +* ожидание завершения операции с базой данных +* получение результатов запроса к базе данных +* и т. д. + +Поскольку в основном время тратится на ожидание выполнения операций I/O, +их обычно называют операциями, ограниченными скоростью ввода-вывода. + +Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и, +будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу. + +Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд), +пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться, +забрать результаты выполнения и начать их обрабатывать. + +"Синхронное" исполнение (в противовес "асинхронному") также называют "последовательным", +потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче, +даже если в процессе приходится ждать. + +### Конкурентность и бургеры + +Тот **асинхронный** код, о котором идёт речь выше, иногда называют **"конкурентностью"**. Она отличается от **"параллелизма"**. + +Да, **конкурентность** и **параллелизм** подразумевают, что разные вещи происходят примерно в одно время. + +Но внутреннее устройство **конкурентности** и **параллелизма** довольно разное. + +Чтобы это понять, представьте такую картину: + +### Конкурентные бургеры + + + +Вы идёте со своей возлюбленной 😍 в фастфуд 🍔 и становитесь в очередь, в это время кассир 💁 принимает заказы у посетителей перед вами. + +Когда наконец подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔, один для своей возлюбленной 😍, а другой себе. + +Отдаёте деньги 💸. + +Кассир 💁 что-то говорит поварам на кухне 👨‍🍳, теперь они знают, какие бургеры нужно будет приготовить 🍔 +(но пока они заняты бургерами предыдущих клиентов). + +Кассир 💁 отдаёт вам чек с номером заказа. + +В ожидании еды вы идёте со своей возлюбленной 😍 выбрать столик, садитесь и довольно продолжительное время общаетесь 😍 +(поскольку ваши бургеры самые навороченные, готовятся они не так быстро ✨🍔✨). + +Сидя за столиком с возлюбленной 😍 в ожидании бургеров 🍔, вы отлично проводите время, +восхищаясь её великолепием, красотой и умом ✨😍✨. + +Всё ещё ожидая заказ и болтая со своей возлюбленной 😍, время от времени вы проверяете, +какой номер горит над прилавком, и не подошла ли уже ваша очередь. + +И вот наконец настаёт этот момент, и вы идёте к стойке, чтобы забрать бургеры 🍔 и вернуться за столик. + +Вы со своей возлюбленной 😍 едите бургеры 🍔 и отлично проводите время ✨. + +--- + +А теперь представьте, что в этой небольшой истории вы компьютер / программа 🤖. + +В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете. +Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного. + +Когда подходит очередь вы наконец предпринимаете "продуктивные" действия 🤓: просматриваете меню, выбираете в нём что-то, узнаёте, что хочет ваша возлюбленная 😍, собираетесь оплатить 💸, смотрите, какую достали карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д. + +И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸, +поскольку теперь нужно ждать 🕙, когда заказ приготовят. + +Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание +на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень +"продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍. + +В какой-то момент кассир 💁 поместит на табло ваш номер, подразумевая, что бургеры готовы 🍔, но вы не станете подскакивать как умалишённый, лишь только увидев на экране свою очередь. Вы уверены, что ваши бургеры 🍔 никто не утащит, ведь у вас свой номерок, а у других свой. + +Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓), +и мило улыбнувшись, скажете, что идёте забирать заказ ⏸. + +И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹. +В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹. + +### Параллельные бургеры + +Теперь представим, что вместо бургерной "Конкурентные бургеры" вы решили сходить в "Параллельные бургеры". + +И вот вы идёте со своей возлюбленной 😍 отведать параллельного фастфуда 🍔. + +Вы становитесь в очередь пока несколько (пусть будет 8) кассиров, которые по совместительству ещё и повары 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, принимают заказы у посетителей перед вами. + +При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый +из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ. + +Наконец настаёт ваша очередь, и вы просите два самых навороченных бургера 🍔, один для дамы сердца 😍, а другой себе. + +Ни о чём не жалея, расплачиваетесь 💸. + +И кассир уходит на кухню 👨‍🍳. + +Вам приходится ждать перед стойкой 🕙, чтобы никто по случайности не забрал ваши бургеры 🍔, ведь никаких номерков у вас нет. + +Поскольку вы с возлюбленной 😍 хотите получить заказ вовремя 🕙, и следите за тем, чтобы никто не вклинился в очередь, +у вас не получается уделять должного внимание своей даме сердца 😞. + +Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨‍🍳. Приходится ждать 🕙 у стойки, +когда кассир/повар 👨‍🍳 закончит делать бургеры 🍔 и вручит вам заказ, иначе его случайно может забрать кто-то другой. + +Наконец кассир/повар 👨‍🍳 возвращается с бургерами 🍔 после невыносимо долгого ожидания 🕙 за стойкой. + +Вы скорее забираете заказ 🍔 и идёте с возлюбленной 😍 за столик. + +Там вы просто едите эти бургеры, и на этом всё 🍔 ⏹. + +Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞. + +--- + +В описанном сценарии вы компьютер / программа 🤖 с двумя исполнителями (вы и ваша возлюбленная 😍), +на протяжении долгого времени 🕙 вы оба уделяете всё внимание ⏯ задаче "ждать на кассе". + +В этом ресторане быстрого питания 8 исполнителей (кассиров/поваров) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳. +Хотя в бургерной конкурентного типа было всего два (один кассир и один повар) 💁 👨‍🍳. + +Несмотря на обилие работников, опыт в итоге получился не из лучших 😞. + +--- + +Так бы выглядел аналог истории про бургерную 🍔 в "параллельном" мире. + +Вот более реалистичный пример. Представьте себе банк. + +До недавних пор в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙. + +Каждый кассир обслуживал одного клиента, потом следующего 👨‍💼⏯. + +Нужно было долгое время 🕙 стоять перед окошком вместе со всеми, иначе пропустишь свою очередь. + +Сомневаюсь, что у вас бы возникло желание прийти с возлюбленной 😍 в банк 🏦 оплачивать налоги. + +### Выводы о бургерах + +В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙, +поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯. + +И то же самое с большинством веб-приложений. + +Пользователей очень много, но ваш сервер всё равно вынужден ждать 🕙 запросы по их слабому интернет-соединению. + +Потом снова ждать 🕙, пока вернётся ответ. + + +Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени. + +Вот почему есть смысл использовать асинхронное ⏸🔀⏯ программирование при построении веб-API. + +Большинство популярных фреймворков (включая Flask и Django) создавались +до появления в Python новых возможностей асинхронного программирования. Поэтому +их можно разворачивать с поддержкой параллельного исполнения или асинхронного +программирования старого типа, которое не настолько эффективно. + +При том, что основная спецификация асинхронного взаимодействия Python с веб-сервером +(ASGI) +была разработана командой Django для внедрения поддержки веб-сокетов. + +Именно асинхронность сделала NodeJS таким популярным (несмотря на то, что он не параллельный), +и в этом преимущество Go как языка программирования. + +И тот же уровень производительности даёт **FastAPI**. + +Поскольку можно использовать преимущества параллелизма и асинхронности вместе, +вы получаете производительность лучше, чем у большинства протестированных NodeJS фреймворков +и на уровне с Go, который является компилируемым языком близким к C (всё благодаря Starlette). + +### Получается, конкурентность лучше параллелизма? + +Нет! Мораль истории совсем не в этом. + +Конкурентность отличается от параллелизма. Она лучше в **конкретных** случаях, где много времени приходится на ожидание. +Вот почему она зачастую лучше параллелизма при разработке веб-приложений. Но это не значит, что конкурентность лучше в любых сценариях. + +Давайте посмотрим с другой стороны, представьте такую картину: + +> Вам нужно убраться в большом грязном доме. + +*Да, это вся история*. + +--- + +Тут не нужно нигде ждать 🕙, просто есть куча работы в разных частях дома. + +Можно организовать очередь как в примере с бургерами, сначала гостиная, потом кухня, +но это ни на что не повлияет, поскольку вы нигде не ждёте 🕙, а просто трёте да моете. + +И понадобится одинаковое количество времени с очередью (конкурентностью) и без неё, +и работы будет сделано тоже одинаковое количество. + +Однако в случае, если бы вы могли привести 8 бывших кассиров/поваров, а ныне уборщиков 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, +и каждый из них (вместе с вами) взялся бы за свой участок дома, +с такой помощью вы бы закончили намного быстрее, делая всю работу **параллельно**. + +В описанном сценарии каждый уборщик (включая вас) был бы исполнителем, занятым на своём участке работы. + +И поскольку большую часть времени выполнения занимает реальная работа (а не ожидание), +а работу в компьютере делает ЦП, +такие задачи называют ограниченными производительностью процессора. + +--- + +Ограничение по процессору проявляется в операциях, где требуется выполнять сложные математические вычисления. + +Например: + +* Обработка **звука** или **изображений**. +* **Компьютерное зрение**: изображение состоит из миллионов пикселей, в каждом пикселе 3 составляющих цвета, +обработка обычно требует проведения расчётов по всем пикселям сразу. +* **Машинное обучение**: здесь обычно требуется умножение "матриц" и "векторов". +Представьте гигантскую таблицу с числами в Экселе, и все их надо одновременно перемножить. +* **Глубокое обучение**: это область *машинного обучения*, поэтому сюда подходит то же описание. +Просто у вас будет не одна таблица в Экселе, а множество. В ряде случаев используется +специальный процессор для создания и / или использования построенных таким образом моделей. + +### Конкурентность + параллелизм: Веб + машинное обучение + +**FastAPI** предоставляет возможности конкуретного программирования, +которое очень распространено в веб-разработке (именно этим славится NodeJS). + +Кроме того вы сможете использовать все преимущества параллелизма и +многопроцессорности (когда несколько процессов работают параллельно), +если рабочая нагрузка предполагает **ограничение по процессору**, +как, например, в системах машинного обучения. + +Необходимо также отметить, что Python является главным языком в области +**дата-сайенс**, +машинного обучения и, особенно, глубокого обучения. Всё это делает FastAPI +отличным вариантом (среди многих других) для разработки веб-API и приложений +в области дата-сайенс / машинного обучения. + +Как добиться такого параллелизма в эксплуатации описано в разделе [Развёртывание](deployment/index.md){.internal-link target=_blank}. + +## `async` и `await` + +В современных версиях Python разработка асинхронного кода реализована очень интуитивно. +Он выглядит как обычный "последовательный" код и самостоятельно выполняет "ожидание", когда это необходимо. + +Если некая операция требует ожидания перед тем, как вернуть результат, и +поддерживает современные возможности Python, код можно написать следующим образом: + +```Python +burgers = await get_burgers(2) +``` + +Главное здесь слово `await`. Оно сообщает интерпретатору, что необходимо дождаться ⏸ +пока `get_burgers(2)` закончит свои дела 🕙, и только после этого сохранить результат в `burgers`. +Зная это, Python может пока переключиться на выполнение других задач 🔀 ⏯ +(например получение следующего запроса). + +Чтобы ключевое слово `await` сработало, оно должно находиться внутри функции, +которая поддерживает асинхронность. Для этого вам просто нужно объявить её как `async def`: + +```Python hl_lines="1" +async def get_burgers(number: int): + # Готовим бургеры по специальному асинхронному рецепту + return burgers +``` + +...вместо `def`: + +```Python hl_lines="2" +# Это не асинхронный код +def get_sequential_burgers(number: int): + # Готовим бургеры последовательно по шагам + return burgers +``` + +Объявление `async def` указывает интерпретатору, что внутри этой функции +следует ожидать выражений `await`, и что можно поставить выполнение такой функции на "паузу" ⏸ и +переключиться на другие задачи 🔀, с тем чтобы вернуться сюда позже. + +Если вы хотите вызвать функцию с `async def`, вам нужно "ожидать" её. +Поэтому такое не сработает: + +```Python +# Это не заработает, поскольку get_burgers объявлена с использованием async def +burgers = get_burgers(2) +``` + +--- + +Если сторонняя библиотека требует вызывать её с ключевым словом `await`, +необходимо писать *функции обработки пути* с использованием `async def`, например: + +```Python hl_lines="2-3" +@app.get('/burgers') +async def read_burgers(): + burgers = await get_burgers(2) + return burgers +``` + +### Технические подробности + +Как вы могли заметить, `await` может применяться только в функциях, объявленных с использованием `async def`. + + +Но выполнение такой функции необходимо "ожидать" с помощью `await`. +Это означает, что её можно вызвать только из другой функции, которая тоже объявлена с `async def`. + +Но как же тогда появилась первая курица? В смысле... как нам вызвать первую асинхронную функцию? + +При работе с **FastAPI** просто не думайте об этом, потому что "первой" функцией является ваша *функция обработки пути*, +и дальше с этим разберётся FastAPI. + +Кроме того, если хотите, вы можете использовать синтаксис `async` / `await` и без FastAPI. + +### Пишите свой асинхронный код + +Starlette (и **FastAPI**) основаны на AnyIO, что делает их совместимыми как со стандартной библиотекой asyncio в Python, так и с Trio. + +В частности, вы можете напрямую использовать AnyIO в тех проектах, где требуется более сложная логика работы с конкурентностью. + +Даже если вы не используете FastAPI, вы можете писать асинхронные приложения с помощью AnyIO, чтобы они были максимально совместимыми и получали его преимущества (например *структурную конкурентность*). + +### Другие виды асинхронного программирования + +Стиль написания кода с `async` и `await` появился в языке Python относительно недавно. + +Но он сильно облегчает работу с асинхронным кодом. + +Ровно такой же синтаксис (ну или почти такой же) недавно был включён в современные версии JavaScript (в браузере и NodeJS). + +До этого поддержка асинхронного кода была реализована намного сложнее, и его было труднее воспринимать. + +В предыдущих версиях Python для этого использовались потоки или Gevent. Но такой код намного сложнее понимать, отлаживать и мысленно представлять. + +Что касается JavaScript (в браузере и NodeJS), раньше там использовали для этой цели +"обратные вызовы". Что выливалось в +ад обратных вызовов. + +## Сопрограммы + +**Корути́на** (или же сопрограмма) — это крутое словечко для именования той сущности, +которую возвращает функция `async def`. Python знает, что её можно запустить, как и обычную функцию, +но кроме того сопрограмму можно поставить на паузу ⏸ в том месте, где встретится слово `await`. + +Всю функциональность асинхронного программирования с использованием `async` и `await` +часто обобщают словом "корутины". Они аналогичны "горутинам", ключевой особенности +языка Go. + +## Заключение + +В самом начале была такая фраза: + +> Современные версии Python поддерживают разработку так называемого +**"асинхронного кода"** посредством написания **"сопрограмм"** с использованием +синтаксиса **`async` и `await`**. + +Теперь всё должно звучать понятнее. ✨ + +На этом основана работа FastAPI (посредством Starlette), и именно это +обеспечивает его высокую производительность. + +## Очень технические подробности + +!!! warning + Этот раздел читать не обязательно. + + Здесь приводятся подробности внутреннего устройства **FastAPI**. + + Но если вы обладаете техническими знаниями (корутины, потоки, блокировка и т. д.) + и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычных `def`, + читайте дальше. + +### Функции обработки пути + +Когда вы объявляете *функцию обработки пути* обычным образом с ключевым словом `def` +вместо `async def`, FastAPI ожидает её выполнения, запустив функцию во внешнем +пуле потоков, а не напрямую (это бы заблокировало сервер). + +Если ранее вы использовали другой асинхронный фреймворк, который работает иначе, +и привыкли объявлять простые вычислительные *функции* через `def` ради +незначительного прироста скорости (порядка 100 наносекунд), обратите внимание, +что с **FastAPI** вы получите противоположный эффект. В таком случае больше подходит +`async def`, если только *функция обработки пути* не использует код, приводящий +к блокировке I/O. + + + +Но в любом случае велика вероятность, что **FastAPI** [окажется быстрее](/#performance){.internal-link target=_blank} +другого фреймворка (или хотя бы на уровне с ним). + +### Зависимости + +То же относится к зависимостям. Если это обычная функция `def`, а не `async def`, +она запускается во внешнем пуле потоков. + +### Подзависимости + +Вы можете объявить множество ссылающихся друг на друга зависимостей и подзависимостей +(в виде параметров при определении функции). Какие-то будут созданы с помощью `async def`, +другие обычным образом через `def`, и такая схема вполне работоспособна. Функции, +объявленные с помощью `def` будут запускаться на внешнем потоке (из пула), +а не с помощью `await`. + +### Другие служебные функции + +Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять +с использованием `def` или `async def`. FastAPI не будет влиять на то, как вы +их запускаете. + +Этим они отличаются от функций, которые FastAPI вызывает самостоятельно: +*функции обработки пути* и зависимости. + +Если служебная функция объявлена с помощью `def`, она будет вызвана напрямую +(как вы и написали в коде), а не в отдельном потоке. Если же она объявлена с +помощью `async def`, её вызов должен осуществляться с ожиданием через `await`. + +--- + + +Ещё раз повторим, что все эти технические подробности полезны, только если вы специально их искали. + +В противном случае просто ознакомьтесь с основными принципами в разделе выше: Нет времени?. diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 213f941d7..0f8f00411 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -54,6 +54,7 @@ nav: - tr: /tr/ - uk: /uk/ - zh: /zh/ +- async.md markdown_extensions: - toc: permalink: true From df50d7c13f53c5ef06742ebc1d128c8da47ae2f1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 18:30:57 +0000 Subject: [PATCH 466/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3c706ce5c..2b2eb3dec 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Russian translation for `docs/async.md`. PR [#4036](https://github.com/tiangolo/fastapi/pull/4036) by [@Winand](https://github.com/Winand). * 🌐 Add Portuguese translation for `docs/tutorial/body.md`. PR [#3960](https://github.com/tiangolo/fastapi/pull/3960) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). * 🌐 Add Portuguese translation of `tutorial/extra-data-types.md`. PR [#4077](https://github.com/tiangolo/fastapi/pull/4077) by [@luccasmmg](https://github.com/luccasmmg). * 🌐 Update German translation for `docs/features.md`. PR [#3905](https://github.com/tiangolo/fastapi/pull/3905) by [@jomue](https://github.com/jomue). From 8724c493d9be1ea157d78099451c61bcb4a033cb Mon Sep 17 00:00:00 2001 From: Lucas <61513630+lsglucas@users.noreply.github.com> Date: Mon, 9 May 2022 15:34:42 -0300 Subject: [PATCH 467/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/deployment/deta.md`=20(#4442)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lorhan Sohaky Co-authored-by: Izabela Guerreiro Co-authored-by: Sebastián Ramírez --- docs/pt/docs/deployment/deta.md | 258 ++++++++++++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 259 insertions(+) create mode 100644 docs/pt/docs/deployment/deta.md diff --git a/docs/pt/docs/deployment/deta.md b/docs/pt/docs/deployment/deta.md new file mode 100644 index 000000000..9271bba42 --- /dev/null +++ b/docs/pt/docs/deployment/deta.md @@ -0,0 +1,258 @@ +# Implantação FastAPI na Deta + +Nessa seção você aprenderá sobre como realizar a implantação de uma aplicação **FastAPI** na Deta utilizando o plano gratuito. 🎁 + +Isso tudo levará aproximadamente **10 minutos**. + +!!! info "Informação" + Deta é uma patrocinadora do **FastAPI**. 🎉 + +## Uma aplicação **FastAPI** simples + +* Crie e entre em um diretório para a sua aplicação, por exemplo, `./fastapideta/`. + +### Código FastAPI + +* Crie o arquivo `main.py` com: + +```Python +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int): + return {"item_id": item_id} +``` + +### Requisitos + +Agora, no mesmo diretório crie o arquivo `requirements.txt` com: + +```text +fastapi +``` + +!!! tip "Dica" + Você não precisa instalar Uvicorn para realizar a implantação na Deta, embora provavelmente queira instalá-lo para testar seu aplicativo localmente. + +### Estrutura de diretório + +Agora você terá o diretório `./fastapideta/` com dois arquivos: + +``` +. +└── main.py +└── requirements.txt +``` + +## Crie uma conta gratuita na Deta + +Agora crie uma conta gratuita na Deta, você precisará apenas de um email e senha. + +Você nem precisa de um cartão de crédito. + +## Instale a CLI + +Depois de ter sua conta criada, instale Deta CLI: + +=== "Linux, macOS" + +
+ + ```console + $ curl -fsSL https://get.deta.dev/cli.sh | sh + ``` + +
+ +=== "Windows PowerShell" + +
+ + ```console + $ iwr https://get.deta.dev/cli.ps1 -useb | iex + ``` + +
+ +Após a instalação, abra um novo terminal para que a CLI seja detectada. + +Em um novo terminal, confirme se foi instalado corretamente com: + +
+ +```console +$ deta --help + +Deta command line interface for managing deta micros. +Complete documentation available at https://docs.deta.sh + +Usage: + deta [flags] + deta [command] + +Available Commands: + auth Change auth settings for a deta micro + +... +``` + +
+ +!!! tip "Dica" + Se você tiver problemas ao instalar a CLI, verifique a documentação oficial da Deta. + +## Login pela CLI + +Agora faça login na Deta pela CLI com: + +
+ +```console +$ deta login + +Please, log in from the web page. Waiting.. +Logged in successfully. +``` + +
+ +Isso abrirá um navegador da Web e autenticará automaticamente. + +## Implantação com Deta + +Em seguida, implante seu aplicativo com a Deta CLI: + +
+ +```console +$ deta new + +Successfully created a new micro + +// Notice the "endpoint" 🔍 + +{ + "name": "fastapideta", + "runtime": "python3.7", + "endpoint": "https://qltnci.deta.dev", + "visor": "enabled", + "http_auth": "enabled" +} + +Adding dependencies... + + +---> 100% + + +Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 +``` + +
+ +Você verá uma mensagem JSON semelhante a: + +```JSON hl_lines="4" +{ + "name": "fastapideta", + "runtime": "python3.7", + "endpoint": "https://qltnci.deta.dev", + "visor": "enabled", + "http_auth": "enabled" +} +``` + +!!! tip "Dica" + Sua implantação terá um URL `"endpoint"` diferente. + +## Confira + +Agora, abra seu navegador na URL do `endpoint`. No exemplo acima foi `https://qltnci.deta.dev`, mas o seu será diferente. + +Você verá a resposta JSON do seu aplicativo FastAPI: + +```JSON +{ + "Hello": "World" +} +``` + +Agora vá para o `/docs` da sua API, no exemplo acima seria `https://qltnci.deta.dev/docs`. + +Ele mostrará sua documentação como: + + + +## Permitir acesso público + +Por padrão, a Deta lidará com a autenticação usando cookies para sua conta. + +Mas quando estiver pronto, você pode torná-lo público com: + +
+ +```console +$ deta auth disable + +Successfully disabled http auth +``` + +
+ +Agora você pode compartilhar essa URL com qualquer pessoa e elas conseguirão acessar sua API. 🚀 + +## HTTPS + +Parabéns! Você realizou a implantação do seu app FastAPI na Deta! 🎉 🍰 + +Além disso, observe que a Deta lida corretamente com HTTPS para você, para que você não precise cuidar disso e tenha a certeza de que seus clientes terão uma conexão criptografada segura. ✅ 🔒 + +## Verifique o Visor + +Na UI da sua documentação (você estará em um URL como `https://qltnci.deta.dev/docs`) envie um request para *operação de rota* `/items/{item_id}`. + +Por exemplo com ID `5`. + +Agora vá para https://web.deta.sh. + +Você verá que há uma seção à esquerda chamada "Micros" com cada um dos seus apps. + +Você verá uma aba com "Detalhes", e também a aba "Visor", vá para "Visor". + +Lá você pode inspecionar as solicitações recentes enviadas ao seu aplicativo. + +Você também pode editá-los e reproduzi-los novamente. + + + +## Saiba mais + +Em algum momento, você provavelmente desejará armazenar alguns dados para seu aplicativo de uma forma que persista ao longo do tempo. Para isso você pode usar Deta Base, que também tem um generoso **nível gratuito**. + +Você também pode ler mais na documentação da Deta. + +## Conceitos de implantação + +Voltando aos conceitos que discutimos em [Deployments Concepts](./concepts.md){.internal-link target=_blank}, veja como cada um deles seria tratado com a Deta: + +* **HTTPS**: Realizado pela Deta, eles fornecerão um subdomínio e lidarão com HTTPS automaticamente. +* **Executando na inicialização**: Realizado pela Deta, como parte de seu serviço. +* **Reinicialização**: Realizado pela Deta, como parte de seu serviço. +* **Replicação**: Realizado pela Deta, como parte de seu serviço. +* **Memória**: Limite predefinido pela Deta, você pode contatá-los para aumentá-lo. +* **Etapas anteriores a inicialização**: Não suportado diretamente, você pode fazê-lo funcionar com o sistema Cron ou scripts adicionais. + +!!! note "Nota" + O Deta foi projetado para facilitar (e gratuitamente) a implantação rápida de aplicativos simples. + + Ele pode simplificar vários casos de uso, mas, ao mesmo tempo, não suporta outros, como o uso de bancos de dados externos (além do próprio sistema de banco de dados NoSQL da Deta), máquinas virtuais personalizadas, etc. + + Você pode ler mais detalhes na documentação da Deta para ver se é a escolha certa para você. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index f6bcdcf02..ebcbabe23 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -72,6 +72,7 @@ nav: - deployment/index.md - deployment/versions.md - deployment/https.md + - deployment/deta.md - alternatives.md - history-design-future.md - external-links.md From d07422a07adebe709710c7fc5e008b1c40862ce2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 18:35:27 +0000 Subject: [PATCH 468/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2b2eb3dec..44fb14afd 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/deployment/deta.md`. PR [#4442](https://github.com/tiangolo/fastapi/pull/4442) by [@lsglucas](https://github.com/lsglucas). * 🌐 Add Russian translation for `docs/async.md`. PR [#4036](https://github.com/tiangolo/fastapi/pull/4036) by [@Winand](https://github.com/Winand). * 🌐 Add Portuguese translation for `docs/tutorial/body.md`. PR [#3960](https://github.com/tiangolo/fastapi/pull/3960) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). * 🌐 Add Portuguese translation of `tutorial/extra-data-types.md`. PR [#4077](https://github.com/tiangolo/fastapi/pull/4077) by [@luccasmmg](https://github.com/luccasmmg). From 2ef0b9896e1ea243b8dc70ea0963e6a56a0cba59 Mon Sep 17 00:00:00 2001 From: Izabela Guerreiro Date: Mon, 9 May 2022 20:44:32 -0300 Subject: [PATCH 469/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/pt/docs/tutorial/background-tasks.md`=20(#?= =?UTF-8?q?2170)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lorhan Sohaky <16273730+LorhanSohaky@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/background-tasks.md | 94 +++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 docs/pt/docs/tutorial/background-tasks.md diff --git a/docs/pt/docs/tutorial/background-tasks.md b/docs/pt/docs/tutorial/background-tasks.md new file mode 100644 index 000000000..625fa2b11 --- /dev/null +++ b/docs/pt/docs/tutorial/background-tasks.md @@ -0,0 +1,94 @@ +# Tarefas em segundo plano + +Você pode definir tarefas em segundo plano a serem executadas _ após _ retornar uma resposta. + +Isso é útil para operações que precisam acontecer após uma solicitação, mas que o cliente realmente não precisa esperar a operação ser concluída para receber a resposta. + +Isso inclui, por exemplo: + +- Envio de notificações por email após a realização de uma ação: + - Como conectar-se a um servidor de e-mail e enviar um e-mail tende a ser "lento" (vários segundos), você pode retornar a resposta imediatamente e enviar a notificação por e-mail em segundo plano. +- Processando dados: + - Por exemplo, digamos que você receba um arquivo que deve passar por um processo lento, você pode retornar uma resposta de "Aceito" (HTTP 202) e processá-lo em segundo plano. + +## Usando `BackgroundTasks` + +Primeiro, importe `BackgroundTasks` e defina um parâmetro em sua _função de operação de caminho_ com uma declaração de tipo de `BackgroundTasks`: + +```Python hl_lines="1 13" +{!../../../docs_src/background_tasks/tutorial001.py!} +``` + +O **FastAPI** criará o objeto do tipo `BackgroundTasks` para você e o passará como esse parâmetro. + +## Criar uma função de tarefa + +Crie uma função a ser executada como tarefa em segundo plano. + +É apenas uma função padrão que pode receber parâmetros. + +Pode ser uma função `async def` ou `def` normal, o **FastAPI** saberá como lidar com isso corretamente. + +Nesse caso, a função de tarefa gravará em um arquivo (simulando o envio de um e-mail). + +E como a operação de gravação não usa `async` e `await`, definimos a função com `def` normal: + +```Python hl_lines="6-9" +{!../../../docs_src/background_tasks/tutorial001.py!} +``` + +## Adicionar a tarefa em segundo plano + +Dentro de sua _função de operação de caminho_, passe sua função de tarefa para o objeto _tarefas em segundo plano_ com o método `.add_task()`: + +```Python hl_lines="14" +{!../../../docs_src/background_tasks/tutorial001.py!} +``` + +`.add_task()` recebe como argumentos: + +- Uma função de tarefa a ser executada em segundo plano (`write_notification`). +- Qualquer sequência de argumentos que deve ser passada para a função de tarefa na ordem (`email`). +- Quaisquer argumentos nomeados que devem ser passados ​​para a função de tarefa (`mensagem = "alguma notificação"`). + +## Injeção de dependência + +Usar `BackgroundTasks` também funciona com o sistema de injeção de dependência, você pode declarar um parâmetro do tipo `BackgroundTasks` em vários níveis: em uma _função de operação de caminho_, em uma dependência (confiável), em uma subdependência, etc. + +O **FastAPI** sabe o que fazer em cada caso e como reutilizar o mesmo objeto, de forma que todas as tarefas em segundo plano sejam mescladas e executadas em segundo plano posteriormente: + +```Python hl_lines="13 15 22 25" +{!../../../docs_src/background_tasks/tutorial002.py!} +``` + +Neste exemplo, as mensagens serão gravadas no arquivo `log.txt` _após_ o envio da resposta. + +Se houver uma consulta na solicitação, ela será gravada no log em uma tarefa em segundo plano. + +E então outra tarefa em segundo plano gerada na _função de operação de caminho_ escreverá uma mensagem usando o parâmetro de caminho `email`. + +## Detalhes técnicos + +A classe `BackgroundTasks` vem diretamente de `starlette.background`. + +Ela é importada/incluída diretamente no FastAPI para que você possa importá-la do `fastapi` e evitar a importação acidental da alternativa `BackgroundTask` (sem o `s` no final) de `starlette.background`. + +Usando apenas `BackgroundTasks` (e não `BackgroundTask`), é então possível usá-la como um parâmetro de _função de operação de caminho_ e deixar o **FastAPI** cuidar do resto para você, assim como ao usar o objeto `Request` diretamente. + +Ainda é possível usar `BackgroundTask` sozinho no FastAPI, mas você deve criar o objeto em seu código e retornar uma Starlette `Response` incluindo-o. + +Você pode ver mais detalhes na documentação oficiais da Starlette para tarefas em segundo plano . + +## Ressalva + +Se você precisa realizar cálculos pesados ​​em segundo plano e não necessariamente precisa que seja executado pelo mesmo processo (por exemplo, você não precisa compartilhar memória, variáveis, etc), você pode se beneficiar do uso de outras ferramentas maiores, como Celery . + +Eles tendem a exigir configurações mais complexas, um gerenciador de fila de mensagens/tarefas, como RabbitMQ ou Redis, mas permitem que você execute tarefas em segundo plano em vários processos e, especialmente, em vários servidores. + +Para ver um exemplo, verifique os [Geradores de projeto](../project-generation.md){.internal-link target=\_blank}, todos incluem celery já configurado. + +Mas se você precisa acessar variáveis ​​e objetos do mesmo aplicativo **FastAPI**, ou precisa realizar pequenas tarefas em segundo plano (como enviar uma notificação por e-mail), você pode simplesmente usar `BackgroundTasks`. + +## Recapitulando + +Importe e use `BackgroundTasks` com parâmetros em _funções de operação de caminho_ e dependências para adicionar tarefas em segundo plano. From b1c5b64c2ceb124261c79ab2331ac830ccfaa312 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 23:45:05 +0000 Subject: [PATCH 470/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 44fb14afd..2e90546b3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/background-tasks.md`. PR [#2170](https://github.com/tiangolo/fastapi/pull/2170) by [@izaguerreiro](https://github.com/izaguerreiro). * 🌐 Add Portuguese translation for `docs/deployment/deta.md`. PR [#4442](https://github.com/tiangolo/fastapi/pull/4442) by [@lsglucas](https://github.com/lsglucas). * 🌐 Add Russian translation for `docs/async.md`. PR [#4036](https://github.com/tiangolo/fastapi/pull/4036) by [@Winand](https://github.com/Winand). * 🌐 Add Portuguese translation for `docs/tutorial/body.md`. PR [#3960](https://github.com/tiangolo/fastapi/pull/3960) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). From d286e6a5be4926740df9f906bbc19e71da4e2477 Mon Sep 17 00:00:00 2001 From: a-takahashi223 <69033676+a-takahashi223@users.noreply.github.com> Date: Tue, 10 May 2022 08:48:07 +0900 Subject: [PATCH 471/814] =?UTF-8?q?=F0=9F=8C=90=20Fix=20Japanese=20transla?= =?UTF-8?q?tion=20of=20`docs/ja/docs/tutorial/body.md`=20(#3062)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/ja/docs/tutorial/body.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/docs/tutorial/body.md b/docs/ja/docs/tutorial/body.md index 9367ea257..59388d904 100644 --- a/docs/ja/docs/tutorial/body.md +++ b/docs/ja/docs/tutorial/body.md @@ -162,4 +162,4 @@ APIはほとんどの場合 **レスポンス** ボディを送らなければ ## Pydanticを使わない方法 -もしPydanticモデルを使用したくない場合は、**ボディ**パラメータが利用できます。[Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}を確認してください。 +もしPydanticモデルを使用したくない場合は、**Body**パラメータが利用できます。[Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}を確認してください。 From 3279ef38ed9ca4630b0f3bb0af28e325339b78fa Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 23:48:40 +0000 Subject: [PATCH 472/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2e90546b3..92673f190 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix Japanese translation of `docs/ja/docs/tutorial/body.md`. PR [#3062](https://github.com/tiangolo/fastapi/pull/3062) by [@a-takahashi223](https://github.com/a-takahashi223). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/background-tasks.md`. PR [#2170](https://github.com/tiangolo/fastapi/pull/2170) by [@izaguerreiro](https://github.com/izaguerreiro). * 🌐 Add Portuguese translation for `docs/deployment/deta.md`. PR [#4442](https://github.com/tiangolo/fastapi/pull/4442) by [@lsglucas](https://github.com/lsglucas). * 🌐 Add Russian translation for `docs/async.md`. PR [#4036](https://github.com/tiangolo/fastapi/pull/4036) by [@Winand](https://github.com/Winand). From 944f06a901b80a7ad0239a5959adcf7cb46df7ac Mon Sep 17 00:00:00 2001 From: Sho Nakamura Date: Tue, 10 May 2022 08:54:00 +0900 Subject: [PATCH 473/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Japanese=20transla?= =?UTF-8?q?tion=20for=20`docs/ja/docs/advanced/conditional-openapi.md`=20(?= =?UTF-8?q?#2631)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/ja/docs/advanced/conditional-openapi.md | 58 ++++++++++++++++++++ docs/ja/mkdocs.yml | 1 + 2 files changed, 59 insertions(+) create mode 100644 docs/ja/docs/advanced/conditional-openapi.md diff --git a/docs/ja/docs/advanced/conditional-openapi.md b/docs/ja/docs/advanced/conditional-openapi.md new file mode 100644 index 000000000..b892ed6c6 --- /dev/null +++ b/docs/ja/docs/advanced/conditional-openapi.md @@ -0,0 +1,58 @@ +# 条件付き OpenAPI + +必要であれば、設定と環境変数を利用して、環境に応じて条件付きでOpenAPIを構成することが可能です。また、完全にOpenAPIを無効にすることもできます。 + +## セキュリティとAPI、およびドキュメントについて + +本番環境においてドキュメントのUIを非表示にすることによって、APIを保護しようと *すべきではありません*。 + +それは、APIのセキュリティの強化にはならず、*path operations* は依然として利用可能です。 + +もしセキュリティ上の欠陥がソースコードにあるならば、それは存在したままです。 + +ドキュメンテーションを非表示にするのは、単にあなたのAPIへのアクセス方法を難解にするだけでなく、同時にあなた自身の本番環境でのAPIのデバッグを困難にしてしまう可能性があります。単純に、 Security through obscurity の一つの形態として考えられるでしょう。 + +もしあなたのAPIのセキュリティを強化したいなら、いくつかのよりよい方法があります。例を示すと、 + +* リクエストボディとレスポンスのためのPydanticモデルの定義を見直す。 +* 依存関係に基づきすべての必要なパーミッションとロールを設定する。 +* パスワードを絶対に平文で保存しない。パスワードハッシュのみを保存する。 +* PasslibやJWTトークンに代表される、よく知られた暗号化ツールを使って実装する。 +* そして必要なところでは、もっと細かいパーミッション制御をOAuth2スコープを使って行う。 +* など + +それでも、例えば本番環境のような特定の環境のみで、あるいは環境変数の設定によってAPIドキュメントをどうしても無効にしたいという、非常に特殊なユースケースがあるかもしれません。 + +## 設定と環境変数による条件付き OpenAPI + +生成するOpenAPIとドキュメントUIの構成は、共通のPydanticの設定を使用して簡単に切り替えられます。 + +例えば、 + +```Python hl_lines="6 11" +{!../../../docs_src/conditional_openapi/tutorial001.py!} +``` + +ここでは `openapi_url` の設定を、デフォルトの `"/openapi.json"` のまま宣言しています。 + +そして、これを `FastAPI` appを作る際に使います。 + +それから、以下のように `OPENAPI_URL` という環境変数を空文字列に設定することによってOpenAPI (UIドキュメントを含む) を無効化することができます。 + +
+ +```console +$ OPENAPI_URL= uvicorn main:app + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +すると、以下のように `/openapi.json`, `/docs`, `/redoc` のどのURLにアクセスしても、 `404 Not Found` エラーが返ってくるようになります。 + +```JSON +{ + "detail": "Not Found" +} +``` diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index f972eb0ff..f9f91879b 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -80,6 +80,7 @@ nav: - advanced/additional-status-codes.md - advanced/response-directly.md - advanced/custom-response.md + - advanced/conditional-openapi.md - async.md - デプロイ: - deployment/index.md From 424674a08276b2c343430906607be396d2515b1c Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 23:54:33 +0000 Subject: [PATCH 474/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 92673f190..ea928ed6f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Japanese translation for `docs/ja/docs/advanced/conditional-openapi.md`. PR [#2631](https://github.com/tiangolo/fastapi/pull/2631) by [@sh0nk](https://github.com/sh0nk). * 🌐 Fix Japanese translation of `docs/ja/docs/tutorial/body.md`. PR [#3062](https://github.com/tiangolo/fastapi/pull/3062) by [@a-takahashi223](https://github.com/a-takahashi223). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/background-tasks.md`. PR [#2170](https://github.com/tiangolo/fastapi/pull/2170) by [@izaguerreiro](https://github.com/izaguerreiro). * 🌐 Add Portuguese translation for `docs/deployment/deta.md`. PR [#4442](https://github.com/tiangolo/fastapi/pull/4442) by [@lsglucas](https://github.com/lsglucas). From b017a33ebd4b440ba24cd41cb5eb0d1ae107fe7e Mon Sep 17 00:00:00 2001 From: William Poetra Yoga Date: Tue, 10 May 2022 06:54:51 +0700 Subject: [PATCH 475/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20in=20`docs/en/?= =?UTF-8?q?docs/tutorial/sql-databases.md`=20(#4875)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/tutorial/sql-databases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md index 9dc2f64c6..60c7fb066 100644 --- a/docs/en/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -491,7 +491,7 @@ You can find an example of Alembic in a FastAPI project in the templates from [P ### Create a dependency -Now use the `SessionLocal` class we created in the `sql_app/databases.py` file to create a dependency. +Now use the `SessionLocal` class we created in the `sql_app/database.py` file to create a dependency. We need to have an independent database session/connection (`SessionLocal`) per request, use the same session through all the request and then close it after the request is finished. From 8fc4872c1b56e435886fd23a4a8bcaf32b80575e Mon Sep 17 00:00:00 2001 From: Sam Courtemanche Date: Tue, 10 May 2022 01:55:11 +0200 Subject: [PATCH 476/814] =?UTF-8?q?=F0=9F=8C=90=20Fix=20French=20translati?= =?UTF-8?q?on=20for=20`docs/tutorial/body.md`=20(#4332)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/fr/docs/tutorial/body.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fr/docs/tutorial/body.md b/docs/fr/docs/tutorial/body.md index c0953f49f..304584498 100644 --- a/docs/fr/docs/tutorial/body.md +++ b/docs/fr/docs/tutorial/body.md @@ -111,7 +111,7 @@ Mais vous auriez le même support de l'éditeur avec !!! tip "Astuce" - Si vous utilisez PyCharm comme éditeur, vous pouvez utiliser le Plugin PyCharm. + Si vous utilisez PyCharm comme éditeur, vous pouvez utiliser le Plugin Pydantic PyCharm Plugin. Ce qui améliore le support pour les modèles Pydantic avec : From f2bc8051134bffe373bbf98c5c22aa124f9fd027 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 23:55:28 +0000 Subject: [PATCH 477/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ea928ed6f..605d4aa8d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo in `docs/en/docs/tutorial/sql-databases.md`. PR [#4875](https://github.com/tiangolo/fastapi/pull/4875) by [@wpyoga](https://github.com/wpyoga). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/conditional-openapi.md`. PR [#2631](https://github.com/tiangolo/fastapi/pull/2631) by [@sh0nk](https://github.com/sh0nk). * 🌐 Fix Japanese translation of `docs/ja/docs/tutorial/body.md`. PR [#3062](https://github.com/tiangolo/fastapi/pull/3062) by [@a-takahashi223](https://github.com/a-takahashi223). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/background-tasks.md`. PR [#2170](https://github.com/tiangolo/fastapi/pull/2170) by [@izaguerreiro](https://github.com/izaguerreiro). From c9eda31dd64eb32310f614ca9483806a36c0fa73 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 9 May 2022 23:55:47 +0000 Subject: [PATCH 478/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 605d4aa8d..34db10454 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix French translation for `docs/tutorial/body.md`. PR [#4332](https://github.com/tiangolo/fastapi/pull/4332) by [@Smlep](https://github.com/Smlep). * ✏ Fix typo in `docs/en/docs/tutorial/sql-databases.md`. PR [#4875](https://github.com/tiangolo/fastapi/pull/4875) by [@wpyoga](https://github.com/wpyoga). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/conditional-openapi.md`. PR [#2631](https://github.com/tiangolo/fastapi/pull/2631) by [@sh0nk](https://github.com/sh0nk). * 🌐 Fix Japanese translation of `docs/ja/docs/tutorial/body.md`. PR [#3062](https://github.com/tiangolo/fastapi/pull/3062) by [@a-takahashi223](https://github.com/a-takahashi223). From 4fa4432173dbfcb78f351c704f13a51ac25d7a16 Mon Sep 17 00:00:00 2001 From: Lucas Mendes <80999926+lbmendes@users.noreply.github.com> Date: Mon, 9 May 2022 21:09:54 -0300 Subject: [PATCH 479/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/pt/docs/tutorial/cookie-params.md`=20(#411?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/cookie-params.md | 33 ++++++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 34 insertions(+) create mode 100644 docs/pt/docs/tutorial/cookie-params.md diff --git a/docs/pt/docs/tutorial/cookie-params.md b/docs/pt/docs/tutorial/cookie-params.md new file mode 100644 index 000000000..1a60e3571 --- /dev/null +++ b/docs/pt/docs/tutorial/cookie-params.md @@ -0,0 +1,33 @@ +# Parâmetros de Cookie + +Você pode definir parâmetros de Cookie da mesma maneira que define paramêtros com `Query` e `Path`. + +## Importe `Cookie` + +Primeiro importe `Cookie`: + +```Python hl_lines="3" +{!../../../docs_src/cookie_params/tutorial001.py!} +``` + +## Declare parâmetros de `Cookie` + +Então declare os paramêtros de cookie usando a mesma estrutura que em `Path` e `Query`. + +O primeiro valor é o valor padrão, você pode passar todas as validações adicionais ou parâmetros de anotação: + +```Python hl_lines="9" +{!../../../docs_src/cookie_params/tutorial001.py!} +``` + +!!! note "Detalhes Técnicos" + `Cookie` é uma classe "irmã" de `Path` e `Query`. Ela também herda da mesma classe em comum `Param`. + + Mas lembre-se que quando você importa `Query`, `Path`, `Cookie` e outras de `fastapi`, elas são na verdade funções que retornam classes especiais. + +!!! info "Informação" + Para declarar cookies, você precisa usar `Cookie`, caso contrário, os parâmetros seriam interpretados como parâmetros de consulta. + +## Recapitulando + +Declare cookies com `Cookie`, usando o mesmo padrão comum que utiliza-se em `Query` e `Path`. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index ebcbabe23..9111ef622 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -64,6 +64,7 @@ nav: - tutorial/body-fields.md - tutorial/extra-data-types.md - tutorial/query-params-str-validations.md + - tutorial/cookie-params.md - Segurança: - tutorial/security/index.md - Guia de Usuário Avançado: From 0d1be46481056dc7bface2e4c8da4ad7103d8d8f Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 00:10:27 +0000 Subject: [PATCH 480/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 34db10454..dfb2570f3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/cookie-params.md`. PR [#4112](https://github.com/tiangolo/fastapi/pull/4112) by [@lbmendes](https://github.com/lbmendes). * 🌐 Fix French translation for `docs/tutorial/body.md`. PR [#4332](https://github.com/tiangolo/fastapi/pull/4332) by [@Smlep](https://github.com/Smlep). * ✏ Fix typo in `docs/en/docs/tutorial/sql-databases.md`. PR [#4875](https://github.com/tiangolo/fastapi/pull/4875) by [@wpyoga](https://github.com/wpyoga). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/conditional-openapi.md`. PR [#2631](https://github.com/tiangolo/fastapi/pull/2631) by [@sh0nk](https://github.com/sh0nk). From e5980a71c2be35755e141b14ac8b67395e63a658 Mon Sep 17 00:00:00 2001 From: wakabame <35513518+wakabame@users.noreply.github.com> Date: Tue, 10 May 2022 09:27:05 +0900 Subject: [PATCH 481/814] =?UTF-8?q?=F0=9F=8C=90=20Fix=20live=20docs=20serv?= =?UTF-8?q?er=20for=20translations=20for=20some=20languages=20(#4729)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/fr/docs/fastapi-people.md | 3 +++ docs/ja/docs/fastapi-people.md | 4 ++++ docs/zh/docs/fastapi-people.md | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/docs/fr/docs/fastapi-people.md b/docs/fr/docs/fastapi-people.md index 9ec2718c4..945f0794e 100644 --- a/docs/fr/docs/fastapi-people.md +++ b/docs/fr/docs/fastapi-people.md @@ -114,6 +114,8 @@ Ce sont les **Sponsors**. 😎 Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec GitHub Sponsors. +{% if sponsors %} + {% if sponsors.gold %} ### Gold Sponsors @@ -141,6 +143,7 @@ Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec GitHub Sponsors を介して私の **FastAPI** などに関する活動を支援してくれています。 +{% if sponsors %} + {% if sponsors.gold %} ### Gold Sponsors @@ -142,6 +144,8 @@ FastAPIには、様々なバックグラウンドの人々を歓迎する素晴 {% endfor %} {% endif %} +{% endif %} + ### Individual Sponsors {% if github_sponsors %} diff --git a/docs/zh/docs/fastapi-people.md b/docs/zh/docs/fastapi-people.md index 75651592d..5d7b0923f 100644 --- a/docs/zh/docs/fastapi-people.md +++ b/docs/zh/docs/fastapi-people.md @@ -114,6 +114,8 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋 他们主要通过GitHub Sponsors支持我在 **FastAPI** (和其他项目)的工作。 +{% if sponsors %} + {% if sponsors.gold %} ### 金牌赞助商 @@ -141,6 +143,8 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋 {% endfor %} {% endif %} +{% endif %} + ### 个人赞助 {% if github_sponsors %} From 59fbdefd7fe4c283235e91adefa05891f96fdd9b Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 00:27:42 +0000 Subject: [PATCH 482/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index dfb2570f3..2cedef47a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix live docs server for translations for some languages. PR [#4729](https://github.com/tiangolo/fastapi/pull/4729) by [@wakabame](https://github.com/wakabame). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/cookie-params.md`. PR [#4112](https://github.com/tiangolo/fastapi/pull/4112) by [@lbmendes](https://github.com/lbmendes). * 🌐 Fix French translation for `docs/tutorial/body.md`. PR [#4332](https://github.com/tiangolo/fastapi/pull/4332) by [@Smlep](https://github.com/Smlep). * ✏ Fix typo in `docs/en/docs/tutorial/sql-databases.md`. PR [#4875](https://github.com/tiangolo/fastapi/pull/4875) by [@wpyoga](https://github.com/wpyoga). From 3d201623dde2c19cfb8893bf30eccf87befdd87d Mon Sep 17 00:00:00 2001 From: Cleo Menezes Jr <54215258+CleoMenezesJr@users.noreply.github.com> Date: Mon, 9 May 2022 20:35:48 -0400 Subject: [PATCH 483/814] =?UTF-8?q?=E2=9C=8F=20=F0=9F=8C=90=20Fix=20typo?= =?UTF-8?q?=20in=20Portuguese=20translation=20for=20`docs/pt/docs/tutorial?= =?UTF-8?q?/path-params.md`=20(#4722)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/path-params.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pt/docs/tutorial/path-params.md b/docs/pt/docs/tutorial/path-params.md index 20913a564..5de3756ed 100644 --- a/docs/pt/docs/tutorial/path-params.md +++ b/docs/pt/docs/tutorial/path-params.md @@ -72,7 +72,7 @@ O mesmo erro apareceria se você tivesse fornecido um `float` ao invés de um `i ## Documentação -Quando você abrir o seu navegador em http://127.0.0.1:8000/docs, você verá de forma automática e interativa a documtação da API como: +Quando você abrir o seu navegador em http://127.0.0.1:8000/docs, você verá de forma automática e interativa a documentação da API como: From faf7ce5af51c625fbc638d67a0c4c591ef342a46 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 00:36:22 +0000 Subject: [PATCH 484/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2cedef47a..f9b697b54 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ 🌐 Fix typo in Portuguese translation for `docs/pt/docs/tutorial/path-params.md`. PR [#4722](https://github.com/tiangolo/fastapi/pull/4722) by [@CleoMenezesJr](https://github.com/CleoMenezesJr). * 🌐 Fix live docs server for translations for some languages. PR [#4729](https://github.com/tiangolo/fastapi/pull/4729) by [@wakabame](https://github.com/wakabame). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/cookie-params.md`. PR [#4112](https://github.com/tiangolo/fastapi/pull/4112) by [@lbmendes](https://github.com/lbmendes). * 🌐 Fix French translation for `docs/tutorial/body.md`. PR [#4332](https://github.com/tiangolo/fastapi/pull/4332) by [@Smlep](https://github.com/Smlep). From 262183b534223c7e6316b812671bfce169ac54a5 Mon Sep 17 00:00:00 2001 From: Patryk Cisek Date: Mon, 9 May 2022 17:39:23 -0700 Subject: [PATCH 485/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20in=20`docs/en/?= =?UTF-8?q?docs/async.md`=20(#4726)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/async.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index 8194650fd..71f2e7502 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -116,7 +116,7 @@ The cashier 💁 gives you the number of your turn. While you are waiting, you go with your crush 😍 and pick a table, you sit and talk with your crush 😍 for a long time (as your burgers are very fancy and take some time to prepare ✨🍔✨). -As you are sitting on the table with your crush 😍, while you wait for the burgers 🍔, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨. +As you are sitting at the table with your crush 😍, while you wait for the burgers 🍔, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨. While waiting and talking to your crush 😍, from time to time, you check the number displayed on the counter to see if it's your turn already. @@ -134,7 +134,7 @@ Then, when it's your turn, you do actual "productive" work 🤓, you process the But then, even though you still don't have your burgers 🍔, your work with the cashier 💁 is "on pause" ⏸, because you have to wait 🕙 for your burgers to be ready. -But as you go away from the counter and sit on the table with a number for your turn, you can switch 🔀 your attention to your crush 😍, and "work" ⏯ 🤓 on that. Then you are again doing something very "productive" 🤓, as is flirting with your crush 😍. +But as you go away from the counter and sit at the table with a number for your turn, you can switch 🔀 your attention to your crush 😍, and "work" ⏯ 🤓 on that. Then you are again doing something very "productive" 🤓, as is flirting with your crush 😍. Then the cashier 💁 says "I'm finished with doing the burgers" 🍔 by putting your number on the counter's display, but you don't jump like crazy immediately when the displayed number changes to your turn number. You know no one will steal your burgers 🍔 because you have the number of your turn, and they have theirs. From 8a353ab911fb69a984a12c8ed04781b3aeeb6a05 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 00:39:57 +0000 Subject: [PATCH 486/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f9b697b54..2412b09a4 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo in `docs/en/docs/async.md`. PR [#4726](https://github.com/tiangolo/fastapi/pull/4726) by [@Prezu](https://github.com/Prezu). * ✏ 🌐 Fix typo in Portuguese translation for `docs/pt/docs/tutorial/path-params.md`. PR [#4722](https://github.com/tiangolo/fastapi/pull/4722) by [@CleoMenezesJr](https://github.com/CleoMenezesJr). * 🌐 Fix live docs server for translations for some languages. PR [#4729](https://github.com/tiangolo/fastapi/pull/4729) by [@wakabame](https://github.com/wakabame). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/cookie-params.md`. PR [#4112](https://github.com/tiangolo/fastapi/pull/4112) by [@lbmendes](https://github.com/lbmendes). From c0d6865c10d844526f1a0981c9943bdff3213fc2 Mon Sep 17 00:00:00 2001 From: alm Date: Tue, 10 May 2022 04:07:37 +0300 Subject: [PATCH 487/814] =?UTF-8?q?=F0=9F=8C=90=20Remove=20translation=20d?= =?UTF-8?q?ocs=20references=20to=20aiofiles=20as=20it's=20no=20longer=20ne?= =?UTF-8?q?eded=20since=20AnyIO=20(#3594)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: AlonMenczer Co-authored-by: Sebastián Ramírez --- docs/de/docs/index.md | 1 - docs/es/docs/index.md | 1 - docs/fr/docs/index.md | 1 - docs/id/docs/index.md | 1 - docs/it/docs/index.md | 1 - docs/ja/docs/index.md | 1 - docs/ja/docs/tutorial/static-files.md | 14 -------------- docs/ko/docs/index.md | 1 - docs/pt/docs/index.md | 1 - docs/ru/docs/index.md | 1 - docs/sq/docs/index.md | 1 - docs/tr/docs/index.md | 1 - docs/uk/docs/index.md | 1 - docs/zh/docs/index.md | 1 - 14 files changed, 27 deletions(-) diff --git a/docs/de/docs/index.md b/docs/de/docs/index.md index d09ce70a0..cdce66223 100644 --- a/docs/de/docs/index.md +++ b/docs/de/docs/index.md @@ -446,7 +446,6 @@ Used by Pydantic: Used by Starlette: * requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. diff --git a/docs/es/docs/index.md b/docs/es/docs/index.md index 65eaf75d0..1fa79fdde 100644 --- a/docs/es/docs/index.md +++ b/docs/es/docs/index.md @@ -439,7 +439,6 @@ Usadas por Pydantic: Usados por Starlette: * requests - Requerido si quieres usar el `TestClient`. -* aiofiles - Requerido si quieres usar `FileResponse` o `StaticFiles`. * jinja2 - Requerido si quieres usar la configuración por defecto de templates. * python-multipart - Requerido si quieres dar soporte a "parsing" de formularios, con `request.form()`. * itsdangerous - Requerido para dar soporte a `SessionMiddleware`. diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md index 40e6dfdff..3922d9c77 100644 --- a/docs/fr/docs/index.md +++ b/docs/fr/docs/index.md @@ -447,7 +447,6 @@ Used by Pydantic: Used by Starlette: * requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. diff --git a/docs/id/docs/index.md b/docs/id/docs/index.md index 95fb7ae21..a7af14781 100644 --- a/docs/id/docs/index.md +++ b/docs/id/docs/index.md @@ -447,7 +447,6 @@ Used by Pydantic: Used by Starlette: * requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. diff --git a/docs/it/docs/index.md b/docs/it/docs/index.md index c52f07e59..e9e428561 100644 --- a/docs/it/docs/index.md +++ b/docs/it/docs/index.md @@ -444,7 +444,6 @@ Used by Pydantic: Used by Starlette: * requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. diff --git a/docs/ja/docs/index.md b/docs/ja/docs/index.md index 229361503..5fca78a83 100644 --- a/docs/ja/docs/index.md +++ b/docs/ja/docs/index.md @@ -437,7 +437,6 @@ Pydantic によって使用されるもの: Starlette によって使用されるもの: - requests - `TestClient`を使用するために必要です。 -- aiofiles - `FileResponse` または `StaticFiles`を使用したい場合は必要です。 - jinja2 - デフォルトのテンプレート設定を使用する場合は必要です。 - python-multipart - "parsing"`request.form()`からの変換をサポートしたい場合は必要です。 - itsdangerous - `SessionMiddleware` サポートのためには必要です。 diff --git a/docs/ja/docs/tutorial/static-files.md b/docs/ja/docs/tutorial/static-files.md index fcc3ba924..1d9c434c3 100644 --- a/docs/ja/docs/tutorial/static-files.md +++ b/docs/ja/docs/tutorial/static-files.md @@ -2,20 +2,6 @@ `StaticFiles` を使用して、ディレクトリから静的ファイルを自動的に提供できます。 -## `aiofiles` をインストール - -まず、`aiofiles` をインストールする必要があります: - -
- -```console -$ pip install aiofiles - ----> 100% -``` - -
- ## `StaticFiles` の使用 * `StaticFiles` をインポート。 diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md index d0c236906..284628955 100644 --- a/docs/ko/docs/index.md +++ b/docs/ko/docs/index.md @@ -443,7 +443,6 @@ Pydantic이 사용하는: Starlette이 사용하는: * requests - `TestClient`를 사용하려면 필요. -* aiofiles - `FileResponse` 또는 `StaticFiles`를 사용하려면 필요. * jinja2 - 기본 템플릿 설정을 사용하려면 필요. * python-multipart - `request.form()`과 함께 "parsing"의 지원을 원하면 필요. * itsdangerous - `SessionMiddleware` 지원을 위해 필요. diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md index 848fff08a..97044dd90 100644 --- a/docs/pt/docs/index.md +++ b/docs/pt/docs/index.md @@ -434,7 +434,6 @@ Usados por Pydantic: Usados por Starlette: * requests - Necessário se você quiser utilizar o `TestClient`. -* aiofiles - Necessário se você quiser utilizar o `FileResponse` ou `StaticFiles`. * jinja2 - Necessário se você quiser utilizar a configuração padrão de templates. * python-multipart - Necessário se você quiser suporte com "parsing" de formulário, com `request.form()`. * itsdangerous - Necessário para suporte a `SessionMiddleware`. diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index 0c2506b87..c0a958c3d 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -447,7 +447,6 @@ Used by Pydantic: Used by Starlette: * requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. diff --git a/docs/sq/docs/index.md b/docs/sq/docs/index.md index 95fb7ae21..a7af14781 100644 --- a/docs/sq/docs/index.md +++ b/docs/sq/docs/index.md @@ -447,7 +447,6 @@ Used by Pydantic: Used by Starlette: * requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md index 88660f7eb..19f46fb4c 100644 --- a/docs/tr/docs/index.md +++ b/docs/tr/docs/index.md @@ -455,7 +455,6 @@ Pydantic tarafında kullanılan: Starlette tarafında kullanılan: * requests - Eğer `TestClient` kullanmak istiyorsan gerekli. -* aiofiles - `FileResponse` ya da `StaticFiles` kullanmak istiyorsan gerekli. * jinja2 - Eğer kendine ait template konfigürasyonu oluşturmak istiyorsan gerekli * python-multipart - Form kullanmak istiyorsan gerekli ("dönüşümü"). * itsdangerous - `SessionMiddleware` desteği için gerekli. diff --git a/docs/uk/docs/index.md b/docs/uk/docs/index.md index 95fb7ae21..a7af14781 100644 --- a/docs/uk/docs/index.md +++ b/docs/uk/docs/index.md @@ -447,7 +447,6 @@ Used by Pydantic: Used by Starlette: * requests - Required if you want to use the `TestClient`. -* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. * itsdangerous - Required for `SessionMiddleware` support. diff --git a/docs/zh/docs/index.md b/docs/zh/docs/index.md index 85707e573..20755283d 100644 --- a/docs/zh/docs/index.md +++ b/docs/zh/docs/index.md @@ -443,7 +443,6 @@ item: Item 用于 Starlette: * requests - 使用 `TestClient` 时安装。 -* aiofiles - 使用 `FileResponse` 或 `StaticFiles` 时安装。 * jinja2 - 使用默认模板配置时安装。 * python-multipart - 需要通过 `request.form()` 对表单进行「解析」时安装。 * itsdangerous - 需要 `SessionMiddleware` 支持时安装。 From fa1ffa567702f70d956366ffa6093dd28d8582be Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 01:08:12 +0000 Subject: [PATCH 488/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2412b09a4..4be88c90f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Remove translation docs references to aiofiles as it's no longer needed since AnyIO. PR [#3594](https://github.com/tiangolo/fastapi/pull/3594) by [@alonme](https://github.com/alonme). * ✏ Fix typo in `docs/en/docs/async.md`. PR [#4726](https://github.com/tiangolo/fastapi/pull/4726) by [@Prezu](https://github.com/Prezu). * ✏ 🌐 Fix typo in Portuguese translation for `docs/pt/docs/tutorial/path-params.md`. PR [#4722](https://github.com/tiangolo/fastapi/pull/4722) by [@CleoMenezesJr](https://github.com/CleoMenezesJr). * 🌐 Fix live docs server for translations for some languages. PR [#4729](https://github.com/tiangolo/fastapi/pull/4729) by [@wakabame](https://github.com/wakabame). From 8f90e514f47d57bddc7db2cbedc9409f16956bb1 Mon Sep 17 00:00:00 2001 From: Ben Gamble Date: Mon, 9 May 2022 21:21:29 -0400 Subject: [PATCH 489/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link=20?= =?UTF-8?q?to=20blog=20post=20about=20Kafka,=20FastAPI,=20and=20Ably=20(#4?= =?UTF-8?q?044)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index 0850d9788..a25c3757f 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -12,6 +12,10 @@ articles: author_link: https://pystar.substack.com/ link: https://pystar.substack.com/p/how-to-create-a-fake-certificate title: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI + - author: Ben Gamble + author_link: https://uk.linkedin.com/in/bengamble7 + link: https://ably.com/blog/realtime-ticket-booking-solution-kafka-fastapi-ably + title: Building a realtime ticket booking solution with Kafka, FastAPI, and Ably - author: Shahriyar(Shako) Rzayev author_link: https://www.linkedin.com/in/shahriyar-rzayev/ link: https://www.azepug.az/posts/fastapi/#building-simple-e-commerce-with-nuxtjs-and-fastapi-series From edd38c0230358b35f645fc3df039505f1c0d709f Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 01:22:07 +0000 Subject: [PATCH 490/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4be88c90f..24313be48 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link to blog post about Kafka, FastAPI, and Ably. PR [#4044](https://github.com/tiangolo/fastapi/pull/4044) by [@Ugbot](https://github.com/Ugbot). * 🌐 Remove translation docs references to aiofiles as it's no longer needed since AnyIO. PR [#3594](https://github.com/tiangolo/fastapi/pull/3594) by [@alonme](https://github.com/alonme). * ✏ Fix typo in `docs/en/docs/async.md`. PR [#4726](https://github.com/tiangolo/fastapi/pull/4726) by [@Prezu](https://github.com/Prezu). * ✏ 🌐 Fix typo in Portuguese translation for `docs/pt/docs/tutorial/path-params.md`. PR [#4722](https://github.com/tiangolo/fastapi/pull/4722) by [@CleoMenezesJr](https://github.com/CleoMenezesJr). From 4fa0cd4def62d789f7f61675e21bd7fa4fdb7bf8 Mon Sep 17 00:00:00 2001 From: Yue Chen Date: Tue, 10 May 2022 09:25:28 +0800 Subject: [PATCH 491/814] =?UTF-8?q?=F0=9F=8C=90=20Update=20source=20exampl?= =?UTF-8?q?e=20highlights=20for=20`docs/zh/docs/tutorial/query-params-str-?= =?UTF-8?q?validations.md`=20(#4237)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../docs/tutorial/query-params-str-validations.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/zh/docs/tutorial/query-params-str-validations.md b/docs/zh/docs/tutorial/query-params-str-validations.md index 2a1d41a89..1d1d383d4 100644 --- a/docs/zh/docs/tutorial/query-params-str-validations.md +++ b/docs/zh/docs/tutorial/query-params-str-validations.md @@ -26,7 +26,7 @@ 现在,将 `Query` 用作查询参数的默认值,并将它的 `max_length` 参数设置为 50: -```Python hl_lines="7" +```Python hl_lines="9" {!../../../docs_src/query_params_str_validations/tutorial002.py!} ``` @@ -58,7 +58,7 @@ q: str = Query(None, max_length=50) 你还可以添加 `min_length` 参数: -```Python hl_lines="7" +```Python hl_lines="9" {!../../../docs_src/query_params_str_validations/tutorial003.py!} ``` @@ -66,7 +66,7 @@ q: str = Query(None, max_length=50) 你可以定义一个参数值必须匹配的正则表达式: -```Python hl_lines="8" +```Python hl_lines="10" {!../../../docs_src/query_params_str_validations/tutorial004.py!} ``` @@ -211,13 +211,13 @@ http://localhost:8000/items/ 你可以添加 `title`: -```Python hl_lines="7" +```Python hl_lines="10" {!../../../docs_src/query_params_str_validations/tutorial007.py!} ``` 以及 `description`: -```Python hl_lines="11" +```Python hl_lines="13" {!../../../docs_src/query_params_str_validations/tutorial008.py!} ``` @@ -239,7 +239,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems 这时你可以用 `alias` 参数声明一个别名,该别名将用于在 URL 中查找查询参数值: -```Python hl_lines="7" +```Python hl_lines="9" {!../../../docs_src/query_params_str_validations/tutorial009.py!} ``` @@ -251,7 +251,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems 那么将参数 `deprecated=True` 传入 `Query`: -```Python hl_lines="16" +```Python hl_lines="18" {!../../../docs_src/query_params_str_validations/tutorial010.py!} ``` From 38902407c0599b9547815dedfb47c0a81320765f Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 01:26:01 +0000 Subject: [PATCH 492/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 24313be48..b222d0e57 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Update source example highlights for `docs/zh/docs/tutorial/query-params-str-validations.md`. PR [#4237](https://github.com/tiangolo/fastapi/pull/4237) by [@caimaoy](https://github.com/caimaoy). * 📝 Add external link to blog post about Kafka, FastAPI, and Ably. PR [#4044](https://github.com/tiangolo/fastapi/pull/4044) by [@Ugbot](https://github.com/Ugbot). * 🌐 Remove translation docs references to aiofiles as it's no longer needed since AnyIO. PR [#3594](https://github.com/tiangolo/fastapi/pull/3594) by [@alonme](https://github.com/alonme). * ✏ Fix typo in `docs/en/docs/async.md`. PR [#4726](https://github.com/tiangolo/fastapi/pull/4726) by [@Prezu](https://github.com/Prezu). From 1233a7d93b116422bdc6e87093452a11c1354bc9 Mon Sep 17 00:00:00 2001 From: Rob Gilton Date: Tue, 10 May 2022 02:30:38 +0100 Subject: [PATCH 493/814] =?UTF-8?q?=E2=9C=8F=20Reword=20to=20improve=20leg?= =?UTF-8?q?ibility=20of=20docs=20about=20`TestClient`=20(#4389)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md index 7e2ae84d0..fea5a54f5 100644 --- a/docs/en/docs/tutorial/testing.md +++ b/docs/en/docs/tutorial/testing.md @@ -10,7 +10,7 @@ With it, you can use Date: Tue, 10 May 2022 01:31:28 +0000 Subject: [PATCH 494/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b222d0e57..74123c593 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Reword to improve legibility of docs about `TestClient`. PR [#4389](https://github.com/tiangolo/fastapi/pull/4389) by [@rgilton](https://github.com/rgilton). * 🌐 Update source example highlights for `docs/zh/docs/tutorial/query-params-str-validations.md`. PR [#4237](https://github.com/tiangolo/fastapi/pull/4237) by [@caimaoy](https://github.com/caimaoy). * 📝 Add external link to blog post about Kafka, FastAPI, and Ably. PR [#4044](https://github.com/tiangolo/fastapi/pull/4044) by [@Ugbot](https://github.com/Ugbot). * 🌐 Remove translation docs references to aiofiles as it's no longer needed since AnyIO. PR [#3594](https://github.com/tiangolo/fastapi/pull/3594) by [@alonme](https://github.com/alonme). From f9134fe5e473b2a2f9d8cab6323fa015977686b2 Mon Sep 17 00:00:00 2001 From: Kaustubh Gupta Date: Tue, 10 May 2022 07:02:32 +0530 Subject: [PATCH 495/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link=20?= =?UTF-8?q?to=20article:=205=20Advanced=20Features=20of=20FastAPI=20You=20?= =?UTF-8?q?Should=20Try=20(#4436)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index a25c3757f..26446720d 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: Kaustubh Gupta + author_link: https://medium.com/@kaustubhgupta1828/ + link: https://levelup.gitconnected.com/5-advance-features-of-fastapi-you-should-try-7c0ac7eebb3e + title: 5 Advanced Features of FastAPI You Should Try - author: Kaustubh Gupta author_link: https://medium.com/@kaustubhgupta1828/ link: https://www.analyticsvidhya.com/blog/2021/06/deploying-ml-models-as-api-using-fastapi-and-heroku/ From 4ce27b5d4d98261412df2304733399dbafb444f3 Mon Sep 17 00:00:00 2001 From: silvanmelchior Date: Tue, 10 May 2022 03:33:05 +0200 Subject: [PATCH 496/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link=20?= =?UTF-8?q?to=20article:=20Seamless=20FastAPI=20Configuration=20with=20Con?= =?UTF-8?q?fZ=20(#4414)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index 26446720d..c3afb7012 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: Silvan Melchior + author_link: https://github.com/silvanmelchior + link: https://blog.devgenius.io/seamless-fastapi-configuration-with-confz-90949c14ea12 + title: Seamless FastAPI Configuration with ConfZ - author: Kaustubh Gupta author_link: https://medium.com/@kaustubhgupta1828/ link: https://levelup.gitconnected.com/5-advance-features-of-fastapi-you-should-try-7c0ac7eebb3e From 938b1a35428de2e9bbcb18b9004b42b534963e12 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 01:33:06 +0000 Subject: [PATCH 497/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 74123c593..0d7a4389f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link to article: 5 Advanced Features of FastAPI You Should Try. PR [#4436](https://github.com/tiangolo/fastapi/pull/4436) by [@kaustubhgupta](https://github.com/kaustubhgupta). * ✏ Reword to improve legibility of docs about `TestClient`. PR [#4389](https://github.com/tiangolo/fastapi/pull/4389) by [@rgilton](https://github.com/rgilton). * 🌐 Update source example highlights for `docs/zh/docs/tutorial/query-params-str-validations.md`. PR [#4237](https://github.com/tiangolo/fastapi/pull/4237) by [@caimaoy](https://github.com/caimaoy). * 📝 Add external link to blog post about Kafka, FastAPI, and Ably. PR [#4044](https://github.com/tiangolo/fastapi/pull/4044) by [@Ugbot](https://github.com/Ugbot). From 453471d07b70e95911352fe3161e690de67e8cbf Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 01:33:38 +0000 Subject: [PATCH 498/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0d7a4389f..951e64106 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link to article: Seamless FastAPI Configuration with ConfZ. PR [#4414](https://github.com/tiangolo/fastapi/pull/4414) by [@silvanmelchior](https://github.com/silvanmelchior). * 📝 Add external link to article: 5 Advanced Features of FastAPI You Should Try. PR [#4436](https://github.com/tiangolo/fastapi/pull/4436) by [@kaustubhgupta](https://github.com/kaustubhgupta). * ✏ Reword to improve legibility of docs about `TestClient`. PR [#4389](https://github.com/tiangolo/fastapi/pull/4389) by [@rgilton](https://github.com/rgilton). * 🌐 Update source example highlights for `docs/zh/docs/tutorial/query-params-str-validations.md`. PR [#4237](https://github.com/tiangolo/fastapi/pull/4237) by [@caimaoy](https://github.com/caimaoy). From a145d3d2771736180893f10b0fe33ee78db28460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 9 May 2022 20:39:10 -0500 Subject: [PATCH 499/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 951e64106..96a51544f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,18 +2,28 @@ ## Latest Changes +### Upgrades + +* ⬆ Upgrade Starlette from 0.18.0 to 0.19.0. PR [#4488](https://github.com/tiangolo/fastapi/pull/4488) by [@Kludex](https://github.com/Kludex). + * When creating an explicit `JSONResponse` the `content` argument is now required. + +### Docs + * 📝 Add external link to article: Seamless FastAPI Configuration with ConfZ. PR [#4414](https://github.com/tiangolo/fastapi/pull/4414) by [@silvanmelchior](https://github.com/silvanmelchior). * 📝 Add external link to article: 5 Advanced Features of FastAPI You Should Try. PR [#4436](https://github.com/tiangolo/fastapi/pull/4436) by [@kaustubhgupta](https://github.com/kaustubhgupta). * ✏ Reword to improve legibility of docs about `TestClient`. PR [#4389](https://github.com/tiangolo/fastapi/pull/4389) by [@rgilton](https://github.com/rgilton). -* 🌐 Update source example highlights for `docs/zh/docs/tutorial/query-params-str-validations.md`. PR [#4237](https://github.com/tiangolo/fastapi/pull/4237) by [@caimaoy](https://github.com/caimaoy). * 📝 Add external link to blog post about Kafka, FastAPI, and Ably. PR [#4044](https://github.com/tiangolo/fastapi/pull/4044) by [@Ugbot](https://github.com/Ugbot). -* 🌐 Remove translation docs references to aiofiles as it's no longer needed since AnyIO. PR [#3594](https://github.com/tiangolo/fastapi/pull/3594) by [@alonme](https://github.com/alonme). +* ✏ Fix typo in `docs/en/docs/tutorial/sql-databases.md`. PR [#4875](https://github.com/tiangolo/fastapi/pull/4875) by [@wpyoga](https://github.com/wpyoga). * ✏ Fix typo in `docs/en/docs/async.md`. PR [#4726](https://github.com/tiangolo/fastapi/pull/4726) by [@Prezu](https://github.com/Prezu). + +### Translations + +* 🌐 Update source example highlights for `docs/zh/docs/tutorial/query-params-str-validations.md`. PR [#4237](https://github.com/tiangolo/fastapi/pull/4237) by [@caimaoy](https://github.com/caimaoy). +* 🌐 Remove translation docs references to aiofiles as it's no longer needed since AnyIO. PR [#3594](https://github.com/tiangolo/fastapi/pull/3594) by [@alonme](https://github.com/alonme). * ✏ 🌐 Fix typo in Portuguese translation for `docs/pt/docs/tutorial/path-params.md`. PR [#4722](https://github.com/tiangolo/fastapi/pull/4722) by [@CleoMenezesJr](https://github.com/CleoMenezesJr). * 🌐 Fix live docs server for translations for some languages. PR [#4729](https://github.com/tiangolo/fastapi/pull/4729) by [@wakabame](https://github.com/wakabame). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/cookie-params.md`. PR [#4112](https://github.com/tiangolo/fastapi/pull/4112) by [@lbmendes](https://github.com/lbmendes). * 🌐 Fix French translation for `docs/tutorial/body.md`. PR [#4332](https://github.com/tiangolo/fastapi/pull/4332) by [@Smlep](https://github.com/Smlep). -* ✏ Fix typo in `docs/en/docs/tutorial/sql-databases.md`. PR [#4875](https://github.com/tiangolo/fastapi/pull/4875) by [@wpyoga](https://github.com/wpyoga). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/conditional-openapi.md`. PR [#2631](https://github.com/tiangolo/fastapi/pull/2631) by [@sh0nk](https://github.com/sh0nk). * 🌐 Fix Japanese translation of `docs/ja/docs/tutorial/body.md`. PR [#3062](https://github.com/tiangolo/fastapi/pull/3062) by [@a-takahashi223](https://github.com/a-takahashi223). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/background-tasks.md`. PR [#2170](https://github.com/tiangolo/fastapi/pull/2170) by [@izaguerreiro](https://github.com/izaguerreiro). @@ -22,7 +32,6 @@ * 🌐 Add Portuguese translation for `docs/tutorial/body.md`. PR [#3960](https://github.com/tiangolo/fastapi/pull/3960) by [@leandrodesouzadev](https://github.com/leandrodesouzadev). * 🌐 Add Portuguese translation of `tutorial/extra-data-types.md`. PR [#4077](https://github.com/tiangolo/fastapi/pull/4077) by [@luccasmmg](https://github.com/luccasmmg). * 🌐 Update German translation for `docs/features.md`. PR [#3905](https://github.com/tiangolo/fastapi/pull/3905) by [@jomue](https://github.com/jomue). -* ⬆ Upgrade Starlette from 0.18.0 to 0.19.0. PR [#4488](https://github.com/tiangolo/fastapi/pull/4488) by [@Kludex](https://github.com/Kludex). ## 0.76.0 From 069645444547cdfb083f84e84982f03fb4e597cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 9 May 2022 20:40:03 -0500 Subject: [PATCH 500/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.77?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 96a51544f..64d784916 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.77.0 + ### Upgrades * ⬆ Upgrade Starlette from 0.18.0 to 0.19.0. PR [#4488](https://github.com/tiangolo/fastapi/pull/4488) by [@Kludex](https://github.com/Kludex). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index fcd036ee4..c4c04525b 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.76.0" +__version__ = "0.77.0" from starlette import status as status From f3969120438a104597a2d7e62039b00264360fa3 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Tue, 10 May 2022 05:22:26 +0200 Subject: [PATCH 501/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20Starlette=20from?= =?UTF-8?q?=200.19.0=20to=200.19.1=20(#4819)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/applications.py | 20 ++++++++++++++------ fastapi/exceptions.py | 4 +--- fastapi/routing.py | 10 +++++----- pyproject.toml | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index 132a94c9a..7530ddb9b 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -1,5 +1,16 @@ from enum import Enum -from typing import Any, Callable, Coroutine, Dict, List, Optional, Sequence, Type, Union +from typing import ( + Any, + Awaitable, + Callable, + Coroutine, + Dict, + List, + Optional, + Sequence, + Type, + Union, +) from fastapi import routing from fastapi.datastructures import Default, DefaultPlaceholder @@ -121,11 +132,8 @@ class FastAPI(Starlette): generate_unique_id_function=generate_unique_id_function, ) self.exception_handlers: Dict[ - Union[int, Type[Exception]], - Callable[[Request, Any], Coroutine[Any, Any, Response]], - ] = ( - {} if exception_handlers is None else dict(exception_handlers) - ) + Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]] + ] = ({} if exception_handlers is None else dict(exception_handlers)) self.exception_handlers.setdefault(HTTPException, http_exception_handler) self.exception_handlers.setdefault( RequestValidationError, request_validation_exception_handler diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py index fcb718748..0f50acc6c 100644 --- a/fastapi/exceptions.py +++ b/fastapi/exceptions.py @@ -12,9 +12,7 @@ class HTTPException(StarletteHTTPException): detail: Any = None, headers: Optional[Dict[str, Any]] = None, ) -> None: - super().__init__( - status_code=status_code, detail=detail, headers=headers # type: ignore - ) + super().__init__(status_code=status_code, detail=detail, headers=headers) RequestErrorModel: Type[BaseModel] = create_model("Request") diff --git a/fastapi/routing.py b/fastapi/routing.py index 6680c04ed..db39d3ffd 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -478,11 +478,11 @@ class APIRouter(routing.Router): ), ) -> None: super().__init__( - routes=routes, # type: ignore # in Starlette + routes=routes, redirect_slashes=redirect_slashes, - default=default, # type: ignore # in Starlette - on_startup=on_startup, # type: ignore # in Starlette - on_shutdown=on_shutdown, # type: ignore # in Starlette + default=default, + on_startup=on_startup, + on_shutdown=on_shutdown, ) if prefix: assert prefix.startswith("/"), "A path prefix must start with '/'" @@ -757,7 +757,7 @@ class APIRouter(routing.Router): generate_unique_id_function=current_generate_unique_id, ) elif isinstance(route, routing.Route): - methods = list(route.methods or []) # type: ignore # in Starlette + methods = list(route.methods or []) self.add_route( prefix + route.path, route.endpoint, diff --git a/pyproject.toml b/pyproject.toml index fc803f8fc..b23d0db05 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ classifiers = [ "Topic :: Internet :: WWW/HTTP", ] requires = [ - "starlette==0.19.0", + "starlette==0.19.1", "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0", ] description-file = "README.md" From 9a87c6d8d2da1d8b4feb94e16f030ac24f56b103 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 03:23:03 +0000 Subject: [PATCH 502/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 64d784916..524adcf92 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade Starlette from 0.19.0 to 0.19.1. PR [#4819](https://github.com/tiangolo/fastapi/pull/4819) by [@Kludex](https://github.com/Kludex). ## 0.77.0 From 9262a699f255fe98a1681b16df5d63fc6883efb0 Mon Sep 17 00:00:00 2001 From: Yashasvi Singh Date: Tue, 10 May 2022 09:02:21 +0530 Subject: [PATCH 503/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link=20?= =?UTF-8?q?to=20article:=20Building=20an=20API=20with=20FastAPI=20and=20Su?= =?UTF-8?q?pabase=20and=20Deploying=20on=20Deta=20(#4440)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index c3afb7012..86c0aafcc 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -32,6 +32,10 @@ articles: author_link: https://rodrigo-arenas.medium.com/ link: https://medium.com/analytics-vidhya/serve-a-machine-learning-model-using-sklearn-fastapi-and-docker-85aabf96729b title: "Serve a machine learning model using Sklearn, FastAPI and Docker" + - author: Yashasvi Singh + author_link: https://hashnode.com/@aUnicornDev + link: https://aunicorndev.hashnode.dev/series/supafast-api + title: "Building an API with FastAPI and Supabase and Deploying on Deta" - author: Navule Pavan Kumar Rao author_link: https://www.linkedin.com/in/navule/ link: https://www.tutlinks.com/deploy-fastapi-on-ubuntu-gunicorn-caddy-2/ From 170123a41f140c23ee252c87aff350662d0312f5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 03:32:54 +0000 Subject: [PATCH 504/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 524adcf92..89f0bf037 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link to article: Building an API with FastAPI and Supabase and Deploying on Deta. PR [#4440](https://github.com/tiangolo/fastapi/pull/4440) by [@aUnicornDev](https://github.com/aUnicornDev). * ⬆ Upgrade Starlette from 0.19.0 to 0.19.1. PR [#4819](https://github.com/tiangolo/fastapi/pull/4819) by [@Kludex](https://github.com/Kludex). ## 0.77.0 From 98bb5480a53648dad3daae67fba222689cc7007a Mon Sep 17 00:00:00 2001 From: Mukul Mantosh Date: Tue, 10 May 2022 09:03:51 +0530 Subject: [PATCH 505/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20external=20link:?= =?UTF-8?q?=20PyCharm=20Guide=20to=20FastAPI=20(#4512)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mukul Mantosh Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index 86c0aafcc..6d358089d 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -204,6 +204,10 @@ articles: author_link: https://medium.com/@williamhayes link: https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59 title: FastAPI/Starlette debug vs prod + - author: Mukul Mantosh + author_link: https://twitter.com/MantoshMukul + link: https://www.jetbrains.com/pycharm/guide/tutorials/fastapi-aws-kubernetes/ + title: Developing FastAPI Application using K8s & AWS german: - author: Nico Axtmann author_link: https://twitter.com/_nicoax From 88606940f58a5b8732354954121f280cb5548e3d Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 03:34:23 +0000 Subject: [PATCH 506/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 89f0bf037..ad73f949e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add external link: PyCharm Guide to FastAPI. PR [#4512](https://github.com/tiangolo/fastapi/pull/4512) by [@mukulmantosh](https://github.com/mukulmantosh). * 📝 Add external link to article: Building an API with FastAPI and Supabase and Deploying on Deta. PR [#4440](https://github.com/tiangolo/fastapi/pull/4440) by [@aUnicornDev](https://github.com/aUnicornDev). * ⬆ Upgrade Starlette from 0.19.0 to 0.19.1. PR [#4819](https://github.com/tiangolo/fastapi/pull/4819) by [@Kludex](https://github.com/Kludex). From 6337186ff4add4a612205ba5c30c75f3fff5e0eb Mon Sep 17 00:00:00 2001 From: Kiko Ilievski <64956873+KikoIlievski@users.noreply.github.com> Date: Tue, 10 May 2022 15:35:21 +1200 Subject: [PATCH 507/814] =?UTF-8?q?=E2=9C=8F=20Fix=20small=20typo=20in=20`?= =?UTF-8?q?docs/en/docs/tutorial/security/first-steps.md`=20(#4515)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/security/first-steps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/security/first-steps.md b/docs/en/docs/tutorial/security/first-steps.md index 360d85ae4..45ffaab90 100644 --- a/docs/en/docs/tutorial/security/first-steps.md +++ b/docs/en/docs/tutorial/security/first-steps.md @@ -121,7 +121,7 @@ When we create an instance of the `OAuth2PasswordBearer` class we pass in the `t ``` !!! tip - here `tokenUrl="token"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`. + Here `tokenUrl="token"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`. Because we are using a relative URL, if your API was located at `https://example.com/`, then it would refer to `https://example.com/token`. But if your API was located at `https://example.com/api/v1/`, then it would refer to `https://example.com/api/v1/token`. From cc51b251ddb0439b4bb28c20eeea0b0571761ad3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 03:35:53 +0000 Subject: [PATCH 508/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ad73f949e..bb16b6143 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix small typo in `docs/en/docs/tutorial/security/first-steps.md`. PR [#4515](https://github.com/tiangolo/fastapi/pull/4515) by [@KikoIlievski](https://github.com/KikoIlievski). * 📝 Add external link: PyCharm Guide to FastAPI. PR [#4512](https://github.com/tiangolo/fastapi/pull/4512) by [@mukulmantosh](https://github.com/mukulmantosh). * 📝 Add external link to article: Building an API with FastAPI and Supabase and Deploying on Deta. PR [#4440](https://github.com/tiangolo/fastapi/pull/4440) by [@aUnicornDev](https://github.com/aUnicornDev). * ⬆ Upgrade Starlette from 0.19.0 to 0.19.1. PR [#4819](https://github.com/tiangolo/fastapi/pull/4819) by [@Kludex](https://github.com/Kludex). From 71ea5883cd671e49511e94c845e36b3925aca23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 9 May 2022 23:02:55 -0500 Subject: [PATCH 509/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20notifications=20in?= =?UTF-8?q?=20issue=20for=20Uzbek=20translations=20(#4884)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/notify-translations/app/translations.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/notify-translations/app/translations.yml b/.github/actions/notify-translations/app/translations.yml index f0bccd470..0e5093f3a 100644 --- a/.github/actions/notify-translations/app/translations.yml +++ b/.github/actions/notify-translations/app/translations.yml @@ -14,3 +14,4 @@ de: 3716 id: 3717 az: 3994 nl: 4701 +uz: 4883 From 764703cc564c12bd7edb064a19ff572099432f1c Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 04:03:35 +0000 Subject: [PATCH 510/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bb16b6143..e39b507b6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add notifications in issue for Uzbek translations. PR [#4884](https://github.com/tiangolo/fastapi/pull/4884) by [@tiangolo](https://github.com/tiangolo). * ✏ Fix small typo in `docs/en/docs/tutorial/security/first-steps.md`. PR [#4515](https://github.com/tiangolo/fastapi/pull/4515) by [@KikoIlievski](https://github.com/KikoIlievski). * 📝 Add external link: PyCharm Guide to FastAPI. PR [#4512](https://github.com/tiangolo/fastapi/pull/4512) by [@mukulmantosh](https://github.com/mukulmantosh). * 📝 Add external link to article: Building an API with FastAPI and Supabase and Deploying on Deta. PR [#4440](https://github.com/tiangolo/fastapi/pull/4440) by [@aUnicornDev](https://github.com/aUnicornDev). From 2a91ee945dd9de283ce6f50e34873176f2d39a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCrmeyer?= Date: Tue, 10 May 2022 06:05:10 +0200 Subject: [PATCH 511/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20link=20to=20german?= =?UTF-8?q?=20article:=20REST-API=20Programmieren=20mittels=20Python=20und?= =?UTF-8?q?=20dem=20FastAPI=20Modul=20(#4624)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A beginner article in German to get started with the FastAPI with a small Todo API as an example. Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index 6d358089d..b918c8fd3 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -213,6 +213,10 @@ articles: author_link: https://twitter.com/_nicoax link: https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/ title: Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI + - author: Felix Schürmeyer + author_link: https://hellocoding.de/autor/felix-schuermeyer/ + link: https://hellocoding.de/blog/coding-language/python/fastapi + title: REST-API Programmieren mittels Python und dem FastAPI Modul japanese: - author: '@bee2' author_link: https://qiita.com/bee2 From 86c459d1e86356ddc3d6e751405e999f29358420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateus=20Jos=C3=A9?= Date: Tue, 10 May 2022 01:05:45 -0300 Subject: [PATCH 512/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/pt/docs/help-fastapi.md`=20(#4583)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/pt/docs/help-fastapi.md | 148 +++++++++++++++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 149 insertions(+) create mode 100644 docs/pt/docs/help-fastapi.md diff --git a/docs/pt/docs/help-fastapi.md b/docs/pt/docs/help-fastapi.md new file mode 100644 index 000000000..086273a1d --- /dev/null +++ b/docs/pt/docs/help-fastapi.md @@ -0,0 +1,148 @@ +# Ajuda FastAPI - Obter Ajuda + +Você gosta do **FastAPI**? + +Você gostaria de ajudar o FastAPI, outros usários, e o autor? + +Ou você gostaria de obter ajuda relacionada ao **FastAPI**?? + +Existem métodos muito simples de ajudar (A maioria das ajudas podem ser feitas com um ou dois cliques). + +E também existem vários modos de se conseguir ajuda. + +## Inscreva-se na newsletter + +Você pode se inscrever (pouco frequente) [**FastAPI e amigos** newsletter](/newsletter/){.internal-link target=_blank} para receber atualizações: + +* Notícias sobre FastAPI e amigos 🚀 +* Tutoriais 📝 +* Recursos ✨ +* Mudanças de última hora 🚨 +* Truques e dicas ✅ + +## Siga o FastAPI no twitter + +Siga @fastapi no **Twitter** para receber as últimas notícias sobre o **FastAPI**. 🐦 + +## Favorite o **FastAPI** no GitHub + +Você pode "favoritar" o FastAPI no GitHub (clicando na estrela no canto superior direito): https://github.com/tiangolo/fastapi. ⭐️ + +Favoritando, outros usuários poderão encontrar mais facilmente e verão que já foi útil para muita gente. + +## Acompanhe novos updates no repositorio do GitHub + +Você pode "acompanhar" (watch) o FastAPI no GitHub (clicando no botão com um "olho" no canto superior direito): https://github.com/tiangolo/fastapi. 👀 + +Podendo selecionar apenas "Novos Updates". + +Fazendo isto, serão enviadas notificações (em seu email) sempre que tiver novos updates (uma nova versão) com correções de bugs e novos recursos no **FastAPI** + +## Conect-se com o autor + +Você pode se conectar comigo (Sebastián Ramírez / `tiangolo`), o autor. + +Você pode: + +* Me siga no **GitHub**. + * Ver também outros projetos Open Source criados por mim que podem te ajudar. + * Me seguir para saber quando um novo projeto Open Source for criado. +* Me siga no **Twitter**. + * Me dizer o motivo pelo o qual você está usando o FastAPI(Adoro ouvir esse tipo de comentário). + * Saber quando eu soltar novos anúncios ou novas ferramentas. + * Também é possivel seguir o @fastapi no Twitter (uma conta aparte). +* Conect-se comigo no **Linkedin**. + * Saber quando eu fizer novos anúncios ou novas ferramentas (apesar de que uso o twitter com mais frequência 🤷‍♂). +* Ler meus artigos (ou me seguir) no **Dev.to** ou no **Medium**. + * Ficar por dentro de novas ideias, artigos, e ferramentas criadas por mim. + * Me siga para saber quando eu publicar algo novo. + +## Tweete sobre **FastAPI** + +Tweete sobre o **FastAPI** e compartilhe comigo e com os outros o porque de gostar do FastAPI. 🎉 + +Adoro ouvir sobre como o **FastAPI** é usado, o que você gosta nele, em qual projeto/empresa está sendo usado, etc. + +## Vote no FastAPI + +* Vote no **FastAPI** no Slant. +* Vote no **FastAPI** no AlternativeTo. + +## Responda perguntas no GitHub + +Você pode acompanhar as perguntas existentes e tentar ajudar outros, . 🤓 + +Ajudando a responder as questões de varias pessoas, você pode se tornar um [Expert em FastAPI](fastapi-people.md#experts){.internal-link target=_blank} oficial. 🎉 + +## Acompanhe o repositório do GitHub + +Você pode "acompanhar" (watch) o FastAPI no GitHub (clicando no "olho" no canto superior direito): https://github.com/tiangolo/fastapi. 👀 + +Se você selecionar "Acompanhando" (Watching) em vez de "Apenas Lançamentos" (Releases only) você receberá notificações quando alguém tiver uma nova pergunta. + +Assim podendo tentar ajudar a resolver essas questões. + +## Faça perguntas + +É possível criar uma nova pergunta no repositório do GitHub, por exemplo: + +* Faça uma **pergunta** ou pergunte sobre um **problema**. +* Sugira novos **recursos**. + +**Nota**: Se você fizer uma pergunta, então eu gostaria de pedir que você também ajude os outros com suas respectivas perguntas. 😉 + +## Crie um Pull Request + +É possível [contribuir](contributing.md){.internal-link target=_blank} no código fonte fazendo Pull Requests, por exemplo: + +* Para corrigir um erro de digitação que você encontrou na documentação. +* Para compartilhar um artigo, video, ou podcast criados por você sobre o FastAPI editando este arquivo. + * Não se esqueça de adicionar o link no começo da seção correspondente. +* Para ajudar [traduzir a documentação](contributing.md#translations){.internal-link target=_blank} para sua lingua. + * Também é possivel revisar as traduções já existentes. +* Para propor novas seções na documentação. +* Para corrigir um bug/questão. +* Para adicionar um novo recurso. + +## Entre no chat + +Entre no 👥 server de conversa do Discord 👥 e conheça novas pessoas da comunidade +do FastAPI. + +!!! dica + Para perguntas, pergunte nas questões do GitHub, lá tem um chance maior de você ser ajudado sobre o FastAPI [FastAPI Experts](fastapi-people.md#experts){.internal-link target=_blank}. + + Use o chat apenas para outro tipo de assunto. + +Também existe o chat do Gitter, porém ele não possuí canais e recursos avançados, conversas são mais engessadas, por isso o Discord é mais recomendado. + +### Não faça perguntas no chat + +Tenha em mente que os chats permitem uma "conversa mais livre", dessa forma é muito fácil fazer perguntas que são muito genéricas e dificeís de responder, assim você pode acabar não sendo respondido. + +Nas questões do GitHub o template irá te guiar para que você faça a sua pergunta de um jeito mais correto, fazendo com que você receba respostas mais completas, e até mesmo que você mesmo resolva o problema antes de perguntar. E no GitHub eu garanto que sempre irei responder todas as perguntas, mesmo que leve um tempo. Eu pessoalmente não consigo fazer isso via chat. 😅 + +Conversas no chat não são tão fáceis de serem encontrados quanto no GitHub, então questões e respostas podem se perder dentro da conversa. E apenas as que estão nas questões do GitHub contam para você se tornar um [Expert em FastAPI](fastapi-people.md#experts){.internal-link target=_blank}, então você receberá mais atenção nas questões do GitHub. + +Por outro lado, existem milhares de usuários no chat, então tem uma grande chance de você encontrar alguém para trocar uma idéia por lá em qualquer horário. 😄 + +## Patrocine o autor + +Você também pode ajudar o autor financeiramente (eu) através do GitHub sponsors. + +Lá você pode me pagar um cafézinho ☕️ como agradecimento. 😄 + +E você também pode se tornar um patrocinador Prata ou Ouro do FastAPI. 🏅🎉 + +## Patrocine as ferramente que potencializam o FastAPI + +Como você viu na documentação, o FastAPI se apoia em nos gigantes, Starlette e Pydantic. + +Patrocine também: + +* Samuel Colvin (Pydantic) +* Encode (Starlette, Uvicorn) + +--- + +Muito Obrigado! 🚀 diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 9111ef622..253400800 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -78,6 +78,7 @@ nav: - history-design-future.md - external-links.md - benchmarks.md +- help-fastapi.md markdown_extensions: - toc: permalink: true From 8082b45f24953771d5efc611fa8b0dc6f5c4f486 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 04:05:48 +0000 Subject: [PATCH 513/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e39b507b6..8e123f1e4 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add link to german article: REST-API Programmieren mittels Python und dem FastAPI Modul. PR [#4624](https://github.com/tiangolo/fastapi/pull/4624) by [@fschuermeyer](https://github.com/fschuermeyer). * 🔧 Add notifications in issue for Uzbek translations. PR [#4884](https://github.com/tiangolo/fastapi/pull/4884) by [@tiangolo](https://github.com/tiangolo). * ✏ Fix small typo in `docs/en/docs/tutorial/security/first-steps.md`. PR [#4515](https://github.com/tiangolo/fastapi/pull/4515) by [@KikoIlievski](https://github.com/KikoIlievski). * 📝 Add external link: PyCharm Guide to FastAPI. PR [#4512](https://github.com/tiangolo/fastapi/pull/4512) by [@mukulmantosh](https://github.com/mukulmantosh). From 9b4e6751bbca9ebfdcb588e4e5ce161b5fad5828 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 04:06:19 +0000 Subject: [PATCH 514/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8e123f1e4..5c45b3a56 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/pt/docs/help-fastapi.md`. PR [#4583](https://github.com/tiangolo/fastapi/pull/4583) by [@mateusjs](https://github.com/mateusjs). * 📝 Add link to german article: REST-API Programmieren mittels Python und dem FastAPI Modul. PR [#4624](https://github.com/tiangolo/fastapi/pull/4624) by [@fschuermeyer](https://github.com/fschuermeyer). * 🔧 Add notifications in issue for Uzbek translations. PR [#4884](https://github.com/tiangolo/fastapi/pull/4884) by [@tiangolo](https://github.com/tiangolo). * ✏ Fix small typo in `docs/en/docs/tutorial/security/first-steps.md`. PR [#4515](https://github.com/tiangolo/fastapi/pull/4515) by [@KikoIlievski](https://github.com/KikoIlievski). From b1e691091d85503a44685d72284bbe0ff30b0aaf Mon Sep 17 00:00:00 2001 From: Mohammad Raisul ISlam Date: Tue, 10 May 2022 10:07:45 +0600 Subject: [PATCH 515/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20in=20deploymen?= =?UTF-8?q?t=20(#4629)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: raisul1234 Co-authored-by: Sebastián Ramírez --- docs/en/docs/deployment/manually.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/deployment/manually.md b/docs/en/docs/deployment/manually.md index 7fd1f4d4f..16286533a 100644 --- a/docs/en/docs/deployment/manually.md +++ b/docs/en/docs/deployment/manually.md @@ -59,7 +59,7 @@ You can install an ASGI compatible server with: ## Run the Server Program -You can then your application the same way you have done in the tutorials, but without the `--reload` option, e.g.: +You can then run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.: === "Uvicorn" From d0e40150341f22a793484cd91832ecf9bfcbf30c Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 04:08:22 +0000 Subject: [PATCH 516/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5c45b3a56..ab1107ebd 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo in deployment. PR [#4629](https://github.com/tiangolo/fastapi/pull/4629) by [@raisulislam541](https://github.com/raisulislam541). * 🌐 Add Portuguese translation for `docs/pt/docs/help-fastapi.md`. PR [#4583](https://github.com/tiangolo/fastapi/pull/4583) by [@mateusjs](https://github.com/mateusjs). * 📝 Add link to german article: REST-API Programmieren mittels Python und dem FastAPI Modul. PR [#4624](https://github.com/tiangolo/fastapi/pull/4624) by [@fschuermeyer](https://github.com/fschuermeyer). * 🔧 Add notifications in issue for Uzbek translations. PR [#4884](https://github.com/tiangolo/fastapi/pull/4884) by [@tiangolo](https://github.com/tiangolo). From 350745c54512c132a93235365cfcbc094e6bca23 Mon Sep 17 00:00:00 2001 From: Maciej Kaczkowski Date: Tue, 10 May 2022 06:12:18 +0200 Subject: [PATCH 517/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Polish=20translati?= =?UTF-8?q?on=20for=20`docs/pl/docs/tutorial/index.md`=20(#4516)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/pl/docs/tutorial/index.md | 81 ++++++++++++++++++++++++++++++++++ docs/pl/mkdocs.yml | 2 + 2 files changed, 83 insertions(+) create mode 100644 docs/pl/docs/tutorial/index.md diff --git a/docs/pl/docs/tutorial/index.md b/docs/pl/docs/tutorial/index.md new file mode 100644 index 000000000..1a97214af --- /dev/null +++ b/docs/pl/docs/tutorial/index.md @@ -0,0 +1,81 @@ +# Samouczek - Wprowadzenie + +Ten samouczek pokaże Ci, krok po kroku, jak używać większości funkcji **FastAPI**. + +Każda część korzysta z poprzednich, ale jest jednocześnie osobnym tematem. Możesz przejść bezpośrednio do każdego rozdziału, jeśli szukasz rozwiązania konkretnego problemu. + +Samouczek jest tak zbudowany, żeby służył jako punkt odniesienia w przyszłości. + +Możesz wracać i sprawdzać dokładnie to czego potrzebujesz. + +## Wykonywanie kodu + +Wszystkie fragmenty kodu mogą być skopiowane bezpośrednio i użyte (są poprawnymi i przetestowanymi plikami). + +Żeby wykonać każdy przykład skopiuj kod to pliku `main.py` i uruchom `uvicorn` za pomocą: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +**BARDZO zalecamy** pisanie bądź kopiowanie kodu, edycję, a następnie wykonywanie go lokalnie. + +Użycie w Twoim edytorze jest tym, co pokazuje prawdziwe korzyści z FastAPI, pozwala zobaczyć jak mało kodu musisz napisać, wszystkie funkcje, takie jak kontrola typów, automatyczne uzupełnianie, itd. + +--- + +## Instalacja FastAPI + +Jako pierwszy krok zainstaluj FastAPI. + +Na potrzeby samouczka możesz zainstalować również wszystkie opcjonalne biblioteki: + +
+ +```console +$ pip install "fastapi[all]" + +---> 100% +``` + +
+ +...wliczając w to `uvicorn`, który będzie służył jako serwer wykonujacy Twój kod. + +!!! note + Możesz również wykonać instalację "krok po kroku". + + Prawdopodobnie zechcesz to zrobić, kiedy będziesz wdrażać swoją aplikację w środowisku produkcyjnym: + + ``` + pip install fastapi + ``` + + Zainstaluj też `uvicorn`, który będzie służył jako serwer: + + ``` + pip install "uvicorn[standard]" + ``` + + Tak samo możesz zainstalować wszystkie dodatkowe biblioteki, których chcesz użyć. + +## Zaawansowany poradnik + +Jest też **Zaawansowany poradnik**, który możesz przeczytać po lekturze tego **Samouczka**. + +**Zaawansowany poradnik** opiera się na tym samouczku, używa tych samych pojęć, żeby pokazać Ci kilka dodatkowych funkcji. + +Najpierw jednak powinieneś przeczytać **Samouczek** (czytasz go teraz). + +Ten rozdział jest zaprojektowany tak, że możesz stworzyć kompletną aplikację używając tylko informacji tutaj zawartych, a następnie rozszerzać ją na różne sposoby, w zależności od potrzeb, używając kilku dodatkowych pomysłów z **Zaawansowanego poradnika**. + diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 67b41fe53..932a43da4 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -54,6 +54,8 @@ nav: - tr: /tr/ - uk: /uk/ - zh: /zh/ +- Samouczek: + - tutorial/index.md markdown_extensions: - toc: permalink: true From a7e659e472ad42a3fa42dd3134dc092b2531f04c Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 10 May 2022 04:12:55 +0000 Subject: [PATCH 518/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ab1107ebd..e055ebf99 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Polish translation for `docs/pl/docs/tutorial/index.md`. PR [#4516](https://github.com/tiangolo/fastapi/pull/4516) by [@MKaczkow](https://github.com/MKaczkow). * ✏ Fix typo in deployment. PR [#4629](https://github.com/tiangolo/fastapi/pull/4629) by [@raisulislam541](https://github.com/raisulislam541). * 🌐 Add Portuguese translation for `docs/pt/docs/help-fastapi.md`. PR [#4583](https://github.com/tiangolo/fastapi/pull/4583) by [@mateusjs](https://github.com/mateusjs). * 📝 Add link to german article: REST-API Programmieren mittels Python und dem FastAPI Modul. PR [#4624](https://github.com/tiangolo/fastapi/pull/4624) by [@fschuermeyer](https://github.com/fschuermeyer). From 03cbdd4f745e1c6e235ccf5bb9f86c0cc5786120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 9 May 2022 23:18:03 -0500 Subject: [PATCH 519/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e055ebf99..a64211c95 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,15 +2,26 @@ ## Latest Changes +### Upgrades + +* ⬆ Upgrade Starlette from 0.19.0 to 0.19.1. PR [#4819](https://github.com/tiangolo/fastapi/pull/4819) by [@Kludex](https://github.com/Kludex). + +### Docs + +* 📝 Add link to german article: REST-API Programmieren mittels Python und dem FastAPI Modul. PR [#4624](https://github.com/tiangolo/fastapi/pull/4624) by [@fschuermeyer](https://github.com/fschuermeyer). +* 📝 Add external link: PyCharm Guide to FastAPI. PR [#4512](https://github.com/tiangolo/fastapi/pull/4512) by [@mukulmantosh](https://github.com/mukulmantosh). +* 📝 Add external link to article: Building an API with FastAPI and Supabase and Deploying on Deta. PR [#4440](https://github.com/tiangolo/fastapi/pull/4440) by [@aUnicornDev](https://github.com/aUnicornDev). +* ✏ Fix small typo in `docs/en/docs/tutorial/security/first-steps.md`. PR [#4515](https://github.com/tiangolo/fastapi/pull/4515) by [@KikoIlievski](https://github.com/KikoIlievski). + +### Translations + * 🌐 Add Polish translation for `docs/pl/docs/tutorial/index.md`. PR [#4516](https://github.com/tiangolo/fastapi/pull/4516) by [@MKaczkow](https://github.com/MKaczkow). * ✏ Fix typo in deployment. PR [#4629](https://github.com/tiangolo/fastapi/pull/4629) by [@raisulislam541](https://github.com/raisulislam541). * 🌐 Add Portuguese translation for `docs/pt/docs/help-fastapi.md`. PR [#4583](https://github.com/tiangolo/fastapi/pull/4583) by [@mateusjs](https://github.com/mateusjs). -* 📝 Add link to german article: REST-API Programmieren mittels Python und dem FastAPI Modul. PR [#4624](https://github.com/tiangolo/fastapi/pull/4624) by [@fschuermeyer](https://github.com/fschuermeyer). + +### Internal + * 🔧 Add notifications in issue for Uzbek translations. PR [#4884](https://github.com/tiangolo/fastapi/pull/4884) by [@tiangolo](https://github.com/tiangolo). -* ✏ Fix small typo in `docs/en/docs/tutorial/security/first-steps.md`. PR [#4515](https://github.com/tiangolo/fastapi/pull/4515) by [@KikoIlievski](https://github.com/KikoIlievski). -* 📝 Add external link: PyCharm Guide to FastAPI. PR [#4512](https://github.com/tiangolo/fastapi/pull/4512) by [@mukulmantosh](https://github.com/mukulmantosh). -* 📝 Add external link to article: Building an API with FastAPI and Supabase and Deploying on Deta. PR [#4440](https://github.com/tiangolo/fastapi/pull/4440) by [@aUnicornDev](https://github.com/aUnicornDev). -* ⬆ Upgrade Starlette from 0.19.0 to 0.19.1. PR [#4819](https://github.com/tiangolo/fastapi/pull/4819) by [@Kludex](https://github.com/Kludex). ## 0.77.0 From 2aaac141ddb79d1f9071f8e02d2b2097f3d4589f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 9 May 2022 23:19:32 -0500 Subject: [PATCH 520/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.77?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a64211c95..4d8bacf4c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.77.1 + ### Upgrades * ⬆ Upgrade Starlette from 0.19.0 to 0.19.1. PR [#4819](https://github.com/tiangolo/fastapi/pull/4819) by [@Kludex](https://github.com/Kludex). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index c4c04525b..1a4d00162 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.77.0" +__version__ = "0.77.1" from starlette import status as status From cb5a200a7cd8215c950a37a356cab21e9beb6c3b Mon Sep 17 00:00:00 2001 From: Kinuax Date: Wed, 11 May 2022 19:03:41 +0200 Subject: [PATCH 521/814] =?UTF-8?q?=E2=9C=8F=20Fix=20links=20to=20Pydantic?= =?UTF-8?q?=20docs=20(#4670)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/de/docs/features.md | 2 +- docs/en/docs/features.md | 2 +- docs/en/docs/tutorial/extra-data-types.md | 2 +- docs/en/docs/tutorial/handling-errors.md | 2 +- docs/en/docs/tutorial/sql-databases.md | 2 +- docs/es/docs/features.md | 2 +- docs/fr/docs/features.md | 2 +- docs/ja/docs/features.md | 2 +- docs/pt/docs/features.md | 2 +- docs/tr/docs/features.md | 2 +- docs/zh/docs/features.md | 2 +- docs/zh/docs/tutorial/extra-data-types.md | 2 +- docs/zh/docs/tutorial/handling-errors.md | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/de/docs/features.md b/docs/de/docs/features.md index a92a2bfeb..767a17073 100644 --- a/docs/de/docs/features.md +++ b/docs/de/docs/features.md @@ -193,7 +193,7 @@ Mit **FastAPI** bekommen Sie alle Funktionen von **Pydantic** (da FastAPI für d * Gutes Zusammenspiel mit Ihrer/Ihrem **IDE/linter/Gehirn**: * Weil Datenstrukturen von Pydantic einfach nur Instanzen ihrer definierten Klassen sind, sollten Autovervollständigung, Linting, mypy und ihre Intuition einwandfrei funktionieren. * **Schnell**: - * In Vergleichen ist Pydantic schneller als jede andere getestete Bibliothek. + * In Vergleichen ist Pydantic schneller als jede andere getestete Bibliothek. * Validierung von **komplexen Strukturen**: * Benutzung von hierachischen Pydantic Schemata, Python `typing`’s `List` und `Dict`, etc. * Validierungen erlauben klare und einfache Datenschemadefinition, überprüft und dokumentiert als JSON Schema. diff --git a/docs/en/docs/features.md b/docs/en/docs/features.md index 36f80783a..e4672d532 100644 --- a/docs/en/docs/features.md +++ b/docs/en/docs/features.md @@ -190,7 +190,7 @@ With **FastAPI** you get all of **Pydantic**'s features (as FastAPI is based on * Plays nicely with your **IDE/linter/brain**: * Because pydantic data structures are just instances of classes you define; auto-completion, linting, mypy and your intuition should all work properly with your validated data. * **Fast**: - * in benchmarks Pydantic is faster than all other tested libraries. + * in benchmarks Pydantic is faster than all other tested libraries. * Validate **complex structures**: * Use of hierarchical Pydantic models, Python `typing`’s `List` and `Dict`, etc. * And validators allow complex data schemas to be clearly and easily defined, checked and documented as JSON Schema. diff --git a/docs/en/docs/tutorial/extra-data-types.md b/docs/en/docs/tutorial/extra-data-types.md index a00bd3212..fb3efd318 100644 --- a/docs/en/docs/tutorial/extra-data-types.md +++ b/docs/en/docs/tutorial/extra-data-types.md @@ -36,7 +36,7 @@ Here are some of the additional data types you can use: * `datetime.timedelta`: * A Python `datetime.timedelta`. * In requests and responses will be represented as a `float` of total seconds. - * Pydantic also allows representing it as a "ISO 8601 time diff encoding", see the docs for more info. + * Pydantic also allows representing it as a "ISO 8601 time diff encoding", see the docs for more info. * `frozenset`: * In requests and responses, treated the same as a `set`: * In requests, a list will be read, eliminating duplicates and converting it to a `set`. diff --git a/docs/en/docs/tutorial/handling-errors.md b/docs/en/docs/tutorial/handling-errors.md index 82e166266..8c30326ce 100644 --- a/docs/en/docs/tutorial/handling-errors.md +++ b/docs/en/docs/tutorial/handling-errors.md @@ -163,7 +163,7 @@ path -> item_id !!! warning These are technical details that you might skip if it's not important for you now. -`RequestValidationError` is a sub-class of Pydantic's `ValidationError`. +`RequestValidationError` is a sub-class of Pydantic's `ValidationError`. **FastAPI** uses it so that, if you use a Pydantic model in `response_model`, and your data has an error, you will see the error in your log. diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md index 60c7fb066..15ad71eb5 100644 --- a/docs/en/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -317,7 +317,7 @@ Not only the IDs of those items, but all the data that we defined in the Pydanti Now, in the Pydantic *models* for reading, `Item` and `User`, add an internal `Config` class. -This `Config` class is used to provide configurations to Pydantic. +This `Config` class is used to provide configurations to Pydantic. In the `Config` class, set the attribute `orm_mode = True`. diff --git a/docs/es/docs/features.md b/docs/es/docs/features.md index 945b2cc94..3c59eb88c 100644 --- a/docs/es/docs/features.md +++ b/docs/es/docs/features.md @@ -191,7 +191,7 @@ Con **FastAPI** obtienes todas las características de **Pydantic** (dado que Fa * Interactúa bien con tu **IDE/linter/cerebro**: * Porque las estructuras de datos de Pydantic son solo instances de clases que tu defines, el auto-completado, el linting, mypy y tu intuición deberían funcionar bien con tus datos validados. * **Rápido**: - * En benchmarks Pydantic es más rápido que todas las otras libraries probadas. + * En benchmarks Pydantic es más rápido que todas las otras libraries probadas. * Valida **estructuras complejas**: * Usa modelos jerárquicos de modelos de Pydantic, `typing` de Python, `List` y `Dict`, etc. * Los validadores también permiten que se definan fácil y claramente schemas complejos de datos. Estos son chequeados y documentados como JSON Schema. diff --git a/docs/fr/docs/features.md b/docs/fr/docs/features.md index 4d8f18403..4b00ecb6f 100644 --- a/docs/fr/docs/features.md +++ b/docs/fr/docs/features.md @@ -190,7 +190,7 @@ Avec **FastAPI** vous aurez toutes les fonctionnalités de **Pydantic** (comme * Aide votre **IDE/linter/cerveau**: * Parce que les structures de données de pydantic consistent seulement en une instance de classe que vous définissez; l'auto-complétion, le linting, mypy et votre intuition devrait être largement suffisante pour valider vos données. * **Rapide**: - * Dans les benchmarks Pydantic est plus rapide que toutes les autres librairies testées. + * Dans les benchmarks Pydantic est plus rapide que toutes les autres librairies testées. * Valide les **structures complexes**: * Utilise les modèles hiérarchique de Pydantic, le `typage` Python pour les `Lists`, `Dict`, etc. * Et les validateurs permettent aux schémas de données complexes d'être clairement et facilement définis, validés et documentés sous forme d'un schéma JSON. diff --git a/docs/ja/docs/features.md b/docs/ja/docs/features.md index 2c406f481..5ea68515d 100644 --- a/docs/ja/docs/features.md +++ b/docs/ja/docs/features.md @@ -193,7 +193,7 @@ FastAPIには非常に使いやすく、非常に強力なBenchmarklarda, Pydantic'in diğer bütün test edilmiş bütün kütüphanelerden daha hızlı. + * Benchmarklarda, Pydantic'in diğer bütün test edilmiş bütün kütüphanelerden daha hızlı. * **En kompleks** yapıları bile doğrula: * Hiyerarşik Pydantic modellerinin kullanımı ile beraber, Python `typing`’s `List` and `Dict`, vs gibi şeyleri doğrula. * Doğrulayıcılar en kompleks data şemalarının bile temiz ve kolay bir şekilde tanımlanmasına izin veriyor, ve hepsi JSON şeması olarak dokümante ediliyor diff --git a/docs/zh/docs/features.md b/docs/zh/docs/features.md index 4752947a3..2d5ba2982 100644 --- a/docs/zh/docs/features.md +++ b/docs/zh/docs/features.md @@ -195,7 +195,7 @@ FastAPI 有一个使用非常简单,但是非常强大的Celery. +If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like Celery. They tend to require more complex configurations, a message/job queue manager, like RabbitMQ or Redis, but they allow you to run background tasks in multiple processes, and especially, in multiple servers. diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md index 15ad71eb5..3436543a5 100644 --- a/docs/en/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -616,7 +616,7 @@ And as the code related to SQLAlchemy and the SQLAlchemy models lives in separat The same way, you would be able to use the same SQLAlchemy models and utilities in other parts of your code that are not related to **FastAPI**. -For example, in a background task worker with Celery, RQ, or ARQ. +For example, in a background task worker with Celery, RQ, or ARQ. ## Review all the files diff --git a/docs/fr/docs/tutorial/background-tasks.md b/docs/fr/docs/tutorial/background-tasks.md index 06ef93cd7..bb6afb457 100644 --- a/docs/fr/docs/tutorial/background-tasks.md +++ b/docs/fr/docs/tutorial/background-tasks.md @@ -81,7 +81,7 @@ Plus de détails sont disponibles dans Celery. +Si vous avez besoin de réaliser des traitements lourds en tâche d'arrière-plan et que vous n'avez pas besoin que ces traitements aient lieu dans le même process (par exemple, pas besoin de partager la mémoire, les variables, etc.), il peut s'avérer profitable d'utiliser des outils plus importants tels que Celery. Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et potentiellement, sur plusieurs serveurs. From 643291b9cabaee2008d38fc78d68eee5af42aae3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 11 May 2022 17:35:38 +0000 Subject: [PATCH 526/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1430113e9..4d484843e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Updates links for Celery documentation. PR [#4736](https://github.com/tiangolo/fastapi/pull/4736) by [@sammyzord](https://github.com/sammyzord). * ✏ Fix example code with sets in tutorial for body nested models. PR [#3030](https://github.com/tiangolo/fastapi/pull/3030) by [@hitrust](https://github.com/hitrust). * ✏ Fix links to Pydantic docs. PR [#4670](https://github.com/tiangolo/fastapi/pull/4670) by [@kinuax](https://github.com/kinuax). From a38b0a7facae1c652a02f3ae65650012e021e16b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E4=B8=8A=20=E7=9A=93=E7=99=BB?= Date: Thu, 12 May 2022 02:42:13 +0900 Subject: [PATCH 527/814] =?UTF-8?q?=F0=9F=8C=90=20Fix=20code=20examples=20?= =?UTF-8?q?in=20Japanese=20translation=20for=20`docs/ja/docs/tutorial/test?= =?UTF-8?q?ing.md`=20(#4623)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/ja/docs/tutorial/testing.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/ja/docs/tutorial/testing.md b/docs/ja/docs/tutorial/testing.md index ebd2de37c..3db493294 100644 --- a/docs/ja/docs/tutorial/testing.md +++ b/docs/ja/docs/tutorial/testing.md @@ -74,16 +74,24 @@ これらの *path operation* には `X-Token` ヘッダーが必要です。 -```Python -{!../../../docs_src/app_testing/main_b.py!} -``` +=== "Python 3.6 and above" + + ```Python + {!> ../../../docs_src/app_testing/app_b/main.py!} + ``` + +=== "Python 3.10 and above" + + ```Python + {!> ../../../docs_src/app_testing/app_b_py310/main.py!} + ``` ### 拡張版テストファイル 次に、先程のものに拡張版のテストを加えた、`test_main_b.py` を作成します。 ```Python -{!../../../docs_src/app_testing/test_main_b.py!} +{!> ../../../docs_src/app_testing/app_b/test_main.py!} ``` リクエストに情報を渡せるクライアントが必要で、その方法がわからない場合はいつでも、`requests` での実現方法を検索 (Google) できます。 From 062107159f948ec1cbb2d97e5c749f1ba538fcea Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 11 May 2022 17:42:56 +0000 Subject: [PATCH 528/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4d484843e..583b65acf 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix code examples in Japanese translation for `docs/ja/docs/tutorial/testing.md`. PR [#4623](https://github.com/tiangolo/fastapi/pull/4623) by [@hirotoKirimaru](https://github.com/hirotoKirimaru). * 📝 Updates links for Celery documentation. PR [#4736](https://github.com/tiangolo/fastapi/pull/4736) by [@sammyzord](https://github.com/sammyzord). * ✏ Fix example code with sets in tutorial for body nested models. PR [#3030](https://github.com/tiangolo/fastapi/pull/3030) by [@hitrust](https://github.com/hitrust). * ✏ Fix links to Pydantic docs. PR [#4670](https://github.com/tiangolo/fastapi/pull/4670) by [@kinuax](https://github.com/kinuax). From e9098abe8cd890a96b0e646847e49ef6ee26a192 Mon Sep 17 00:00:00 2001 From: jbrocher Date: Wed, 11 May 2022 19:48:25 +0200 Subject: [PATCH 529/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20link=20to=20extern?= =?UTF-8?q?al=20article:=20Building=20the=20Poll=20App=20From=20Django=20T?= =?UTF-8?q?utorial=20With=20FastAPI=20And=20React=20(#4778)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index b918c8fd3..f73ce4a6c 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: Jean-Baptiste Rocher + author_link: https://hashnode.com/@jibrocher + link: https://dev.indooroutdoor.io/series/fastapi-react-poll-app + title: Building the Poll App From Django Tutorial With FastAPI And React - author: Silvan Melchior author_link: https://github.com/silvanmelchior link: https://blog.devgenius.io/seamless-fastapi-configuration-with-confz-90949c14ea12 From ff2daa0471c7a6360fdedddd409c745fc8538d56 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 11 May 2022 17:49:06 +0000 Subject: [PATCH 530/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 583b65acf..105b4b6a0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add link to external article: Building the Poll App From Django Tutorial With FastAPI And React. PR [#4778](https://github.com/tiangolo/fastapi/pull/4778) by [@jbrocher](https://github.com/jbrocher). * 🌐 Fix code examples in Japanese translation for `docs/ja/docs/tutorial/testing.md`. PR [#4623](https://github.com/tiangolo/fastapi/pull/4623) by [@hirotoKirimaru](https://github.com/hirotoKirimaru). * 📝 Updates links for Celery documentation. PR [#4736](https://github.com/tiangolo/fastapi/pull/4736) by [@sammyzord](https://github.com/sammyzord). * ✏ Fix example code with sets in tutorial for body nested models. PR [#3030](https://github.com/tiangolo/fastapi/pull/3030) by [@hitrust](https://github.com/hitrust). From 35445828c85013c21d4da2370f65e430cbcb0c41 Mon Sep 17 00:00:00 2001 From: Lorenzo Castellino Date: Wed, 11 May 2022 20:49:16 +0200 Subject: [PATCH 531/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20docs=20about=20?= =?UTF-8?q?Swagger=20UI=20self-hosting=20with=20newer=20source=20links=20(?= =?UTF-8?q?#4813)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/extending-openapi.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/advanced/extending-openapi.md b/docs/en/docs/advanced/extending-openapi.md index d1b14bc00..36619696b 100644 --- a/docs/en/docs/advanced/extending-openapi.md +++ b/docs/en/docs/advanced/extending-openapi.md @@ -132,8 +132,8 @@ You can probably right-click each link and select an option similar to `Save lin **Swagger UI** uses the files: -* `swagger-ui-bundle.js` -* `swagger-ui.css` +* `swagger-ui-bundle.js` +* `swagger-ui.css` And **ReDoc** uses the file: From 0f7de452dd3b4040197259c27dd3bc8003884c9d Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 11 May 2022 18:49:56 +0000 Subject: [PATCH 532/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 105b4b6a0..ec3b2807d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update docs about Swagger UI self-hosting with newer source links. PR [#4813](https://github.com/tiangolo/fastapi/pull/4813) by [@Kastakin](https://github.com/Kastakin). * 📝 Add link to external article: Building the Poll App From Django Tutorial With FastAPI And React. PR [#4778](https://github.com/tiangolo/fastapi/pull/4778) by [@jbrocher](https://github.com/jbrocher). * 🌐 Fix code examples in Japanese translation for `docs/ja/docs/tutorial/testing.md`. PR [#4623](https://github.com/tiangolo/fastapi/pull/4623) by [@hirotoKirimaru](https://github.com/hirotoKirimaru). * 📝 Updates links for Celery documentation. PR [#4736](https://github.com/tiangolo/fastapi/pull/4736) by [@sammyzord](https://github.com/sammyzord). From 15dd12629ea4feee52f0ba35e5cc9f9eab8c7d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Victor=20Ribeiro=20Silva?= Date: Wed, 11 May 2022 15:53:57 -0300 Subject: [PATCH 533/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20dark=20mode=20auto?= =?UTF-8?q?=20switch=20to=20docs=20based=20on=20OS=20preference=20(#4869)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/az/mkdocs.yml | 6 ++++-- docs/de/mkdocs.yml | 6 ++++-- docs/en/mkdocs.yml | 6 ++++-- docs/es/mkdocs.yml | 6 ++++-- docs/fa/mkdocs.yml | 6 ++++-- docs/fr/mkdocs.yml | 6 ++++-- docs/id/mkdocs.yml | 6 ++++-- docs/it/mkdocs.yml | 6 ++++-- docs/ja/mkdocs.yml | 6 ++++-- docs/ko/mkdocs.yml | 6 ++++-- docs/nl/mkdocs.yml | 6 ++++-- docs/pl/mkdocs.yml | 6 ++++-- docs/pt/mkdocs.yml | 6 ++++-- docs/ru/mkdocs.yml | 6 ++++-- docs/sq/mkdocs.yml | 6 ++++-- docs/tr/mkdocs.yml | 6 ++++-- docs/uk/mkdocs.yml | 6 ++++-- docs/zh/mkdocs.yml | 6 ++++-- 18 files changed, 72 insertions(+), 36 deletions(-) diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index 58bbb0758..60bd8eaad 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 1242af504..c72f325f6 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index e7aa40def..322de0f2f 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index eb7538cf4..b544f9b38 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/fa/mkdocs.yml b/docs/fa/mkdocs.yml index 6fb3891b7..3966a6026 100644 --- a/docs/fa/mkdocs.yml +++ b/docs/fa/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index d2681f8d5..bf0d2b21c 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index 0c60fecd9..769547d11 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index 3bf3d7396..ebec9a642 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index f9f91879b..055404fea 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 1e7d60dbd..60cf7d30a 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/nl/mkdocs.yml b/docs/nl/mkdocs.yml index c853216f5..9cd1e0401 100644 --- a/docs/nl/mkdocs.yml +++ b/docs/nl/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 932a43da4..0c3d100e7 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 253400800..2bb0b568d 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 0f8f00411..bb0702489 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index a61f49bc9..8914395fe 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index dd52d7fcc..74186033c 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index 971a182db..ddf299d8b 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 408166489..a72ecb657 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -5,13 +5,15 @@ theme: name: material custom_dir: overrides palette: - - scheme: default + - media: "(prefers-color-scheme: light)" + scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: teal accent: amber toggle: From 1bbbdb4b7fe86196b9c4f1d4f69c77818e7bfe95 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 11 May 2022 18:54:33 +0000 Subject: [PATCH 534/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ec3b2807d..6b7d793a0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add dark mode auto switch to docs based on OS preference. PR [#4869](https://github.com/tiangolo/fastapi/pull/4869) by [@ComicShrimp](https://github.com/ComicShrimp). * 📝 Update docs about Swagger UI self-hosting with newer source links. PR [#4813](https://github.com/tiangolo/fastapi/pull/4813) by [@Kastakin](https://github.com/Kastakin). * 📝 Add link to external article: Building the Poll App From Django Tutorial With FastAPI And React. PR [#4778](https://github.com/tiangolo/fastapi/pull/4778) by [@jbrocher](https://github.com/jbrocher). * 🌐 Fix code examples in Japanese translation for `docs/ja/docs/tutorial/testing.md`. PR [#4623](https://github.com/tiangolo/fastapi/pull/4623) by [@hirotoKirimaru](https://github.com/hirotoKirimaru). From 4fcdb31947f23c1bf9aa661dfd86079ea0a433b9 Mon Sep 17 00:00:00 2001 From: Matthew Evans <7916000+ml-evs@users.noreply.github.com> Date: Wed, 11 May 2022 22:43:47 +0100 Subject: [PATCH 535/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20OpenAPI=20warning?= =?UTF-8?q?=20to=20"Body=20-=20Fields"=20docs=20with=20extra=20schema=20ex?= =?UTF-8?q?tensions=20(#4846)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/body-fields.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/tutorial/body-fields.md b/docs/en/docs/tutorial/body-fields.md index 1f38a0c5c..0cfe576d6 100644 --- a/docs/en/docs/tutorial/body-fields.md +++ b/docs/en/docs/tutorial/body-fields.md @@ -57,6 +57,10 @@ You can declare extra information in `Field`, `Query`, `Body`, etc. And it will You will learn more about adding extra information later in the docs, when learning to declare examples. +!!! warning + Extra keys passed to `Field` will also be present in the resulting OpenAPI schema for your application. + As these keys may not necessarily be part of the OpenAPI specification, some OpenAPI tools, for example [the OpenAPI validator](https://validator.swagger.io/), may not work with your generated schema. + ## Recap You can use Pydantic's `Field` to declare extra validations and metadata for model attributes. From f3b04a611880991271173f3694555176f27b4916 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 11 May 2022 21:44:52 +0000 Subject: [PATCH 536/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6b7d793a0..be0048337 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add OpenAPI warning to "Body - Fields" docs with extra schema extensions. PR [#4846](https://github.com/tiangolo/fastapi/pull/4846) by [@ml-evs](https://github.com/ml-evs). * 📝 Add dark mode auto switch to docs based on OS preference. PR [#4869](https://github.com/tiangolo/fastapi/pull/4869) by [@ComicShrimp](https://github.com/ComicShrimp). * 📝 Update docs about Swagger UI self-hosting with newer source links. PR [#4813](https://github.com/tiangolo/fastapi/pull/4813) by [@Kastakin](https://github.com/Kastakin). * 📝 Add link to external article: Building the Poll App From Django Tutorial With FastAPI And React. PR [#4778](https://github.com/tiangolo/fastapi/pull/4778) by [@jbrocher](https://github.com/jbrocher). From 8c593a9cc9e1aa8387a3e004b0e3dc789ab926e9 Mon Sep 17 00:00:00 2001 From: Maxim Martynov Date: Thu, 12 May 2022 01:31:52 +0300 Subject: [PATCH 537/814] =?UTF-8?q?=F0=9F=91=B7=20Disable=20CI=20installin?= =?UTF-8?q?g=20Material=20for=20MkDocs=20in=20forks=20(#4410)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .github/workflows/build-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 2482660f3..bdef6ea8a 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -30,7 +30,7 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' run: python3.7 -m flit install --deps production --extras doc - name: Install Material for MkDocs Insiders - if: github.event.pull_request.head.repo.fork == false && steps.cache.outputs.cache-hit != 'true' + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false && steps.cache.outputs.cache-hit != 'true' run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git - name: Build Docs run: python3.7 ./scripts/docs.py build-all From 9cbd42b13e5686b4bd298af1431b07b75bc477c8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 11 May 2022 22:32:26 +0000 Subject: [PATCH 538/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index be0048337..13348a423 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Disable CI installing Material for MkDocs in forks. PR [#4410](https://github.com/tiangolo/fastapi/pull/4410) by [@dolfinus](https://github.com/dolfinus). * 📝 Add OpenAPI warning to "Body - Fields" docs with extra schema extensions. PR [#4846](https://github.com/tiangolo/fastapi/pull/4846) by [@ml-evs](https://github.com/ml-evs). * 📝 Add dark mode auto switch to docs based on OS preference. PR [#4869](https://github.com/tiangolo/fastapi/pull/4869) by [@ComicShrimp](https://github.com/ComicShrimp). * 📝 Update docs about Swagger UI self-hosting with newer source links. PR [#4813](https://github.com/tiangolo/fastapi/pull/4813) by [@Kastakin](https://github.com/Kastakin). From 3d0f130ff355f3a57a929eadd68f0cc3ab96b2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 11 May 2022 19:06:16 -0500 Subject: [PATCH 539/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20pre-commit=20with?= =?UTF-8?q?=20first=20config=20and=20first=20formatting=20pass=20(#4888)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔧 Add first pre-commit config * 🎨 Format YAML files with pre-commit * 🎨 Format Markdown with pre-commit * 🎨 Format SVGs, drawio, JS, HTML with pre-commit * ➕ Add pre-commit to dev dependencies * ⬇️ Extend pre-commit range to support Python 3.6 --- .github/ISSUE_TEMPLATE/feature-request.yml | 8 ++++---- .github/ISSUE_TEMPLATE/question.yml | 8 ++++---- .github/workflows/latest-changes.yml | 2 +- .github/workflows/people.yml | 2 +- .github/workflows/preview-docs.yml | 2 +- .pre-commit-config.yaml | 14 +++++++++++++ docs/de/docs/features.md | 2 +- docs/de/docs/index.md | 4 ++-- docs/en/data/external_links.yml | 4 ++-- docs/en/docs/advanced/additional-responses.md | 2 +- .../docs/advanced/additional-status-codes.md | 2 +- .../docs/advanced/security/oauth2-scopes.md | 8 ++++---- docs/en/docs/advanced/sql-databases-peewee.md | 2 +- docs/en/docs/alternatives.md | 6 +++--- docs/en/docs/deployment/docker.md | 2 +- docs/en/docs/deployment/manually.md | 4 ++-- .../deployment/concepts/process-ram.drawio | 2 +- .../img/deployment/concepts/process-ram.svg | 2 +- .../en/docs/img/deployment/https/https.drawio | 2 +- docs/en/docs/img/deployment/https/https.svg | 2 +- .../docs/img/deployment/https/https01.drawio | 2 +- docs/en/docs/img/deployment/https/https01.svg | 2 +- .../docs/img/deployment/https/https02.drawio | 2 +- docs/en/docs/img/deployment/https/https02.svg | 2 +- .../docs/img/deployment/https/https03.drawio | 2 +- docs/en/docs/img/deployment/https/https03.svg | 2 +- .../docs/img/deployment/https/https04.drawio | 2 +- docs/en/docs/img/deployment/https/https04.svg | 2 +- .../docs/img/deployment/https/https05.drawio | 2 +- docs/en/docs/img/deployment/https/https05.svg | 2 +- .../docs/img/deployment/https/https06.drawio | 2 +- docs/en/docs/img/deployment/https/https06.svg | 2 +- .../docs/img/deployment/https/https07.drawio | 2 +- docs/en/docs/img/deployment/https/https07.svg | 2 +- .../docs/img/deployment/https/https08.drawio | 2 +- docs/en/docs/img/deployment/https/https08.svg | 2 +- .../bigger-applications/package.drawio | 2 +- .../tutorial/bigger-applications/package.svg | 2 +- docs/en/docs/js/termynal.js | 14 ++++++------- docs/en/docs/python-types.md | 8 ++++---- docs/en/docs/tutorial/bigger-applications.md | 2 +- docs/en/docs/tutorial/body-nested-models.md | 2 +- docs/en/docs/tutorial/body.md | 2 +- .../dependencies/dependencies-with-yield.md | 4 ++-- docs/en/docs/tutorial/request-files.md | 2 +- docs/en/docs/tutorial/request-forms.md | 2 +- docs/en/overrides/main.html | 4 ++-- docs/es/docs/tutorial/first-steps.md | 2 +- docs/fr/docs/alternatives.md | 6 +++--- docs/fr/docs/async.md | 6 +++--- docs/fr/docs/deployment/docker.md | 8 ++++---- docs/fr/docs/features.md | 2 +- docs/fr/docs/index.md | 6 +++--- docs/fr/docs/tutorial/background-tasks.md | 4 ++-- docs/fr/docs/tutorial/body.md | 2 +- docs/fr/docs/tutorial/first-steps.md | 2 +- docs/fr/docs/tutorial/path-params.md | 8 ++++---- docs/fr/docs/tutorial/query-params.md | 4 ++-- docs/id/docs/index.md | 4 ++-- docs/it/docs/index.md | 4 ++-- docs/ja/docs/alternatives.md | 4 ++-- docs/ja/docs/async.md | 2 +- docs/ja/docs/deployment/index.md | 2 +- docs/ja/docs/deployment/manually.md | 2 +- docs/ja/docs/history-design-future.md | 2 +- docs/ja/docs/tutorial/body.md | 4 ++-- docs/ja/docs/tutorial/middleware.md | 2 +- docs/ja/docs/tutorial/path-params.md | 2 +- docs/ja/docs/tutorial/query-params.md | 6 +++--- docs/ja/docs/tutorial/request-forms.md | 2 +- docs/ja/docs/tutorial/testing.md | 4 ++-- docs/ko/docs/deployment/versions.md | 6 +++--- docs/ko/docs/tutorial/header-params.md | 2 +- docs/ko/docs/tutorial/path-params.md | 2 +- docs/ko/docs/tutorial/request-files.md | 10 +++++----- .../docs/tutorial/request-forms-and-files.md | 4 ++-- docs/ko/docs/tutorial/response-status-code.md | 10 +++++----- docs/pl/docs/tutorial/index.md | 1 - docs/pt/docs/alternatives.md | 4 ++-- docs/pt/docs/async.md | 8 ++++---- docs/pt/docs/benchmarks.md | 2 +- docs/pt/docs/help-fastapi.md | 2 +- docs/pt/docs/index.md | 2 +- docs/pt/docs/python-types.md | 1 - docs/pt/docs/tutorial/body.md | 2 +- docs/ru/docs/async.md | 4 ++-- docs/ru/docs/index.md | 4 ++-- docs/ru/docs/python-types.md | 2 +- docs/sq/docs/index.md | 4 ++-- docs/tr/docs/features.md | 7 +++---- docs/tr/docs/index.md | 14 ++++++------- docs/tr/docs/python-types.md | 2 +- docs/uk/docs/index.md | 4 ++-- .../docs/advanced/additional-status-codes.md | 2 +- docs/zh/docs/advanced/custom-response.md | 2 +- docs/zh/docs/advanced/response-directly.md | 3 +-- docs/zh/docs/benchmarks.md | 2 +- docs/zh/docs/contributing.md | 2 +- docs/zh/docs/features.md | 2 +- docs/zh/docs/help-fastapi.md | 5 ++--- docs/zh/docs/tutorial/bigger-applications.md | 4 ++-- docs/zh/docs/tutorial/body-nested-models.md | 2 +- docs/zh/docs/tutorial/body-updates.md | 10 +++++----- ...pendencies-in-path-operation-decorators.md | 6 +++--- .../dependencies/global-dependencies.md | 1 - docs/zh/docs/tutorial/dependencies/index.md | 4 ++-- .../tutorial/dependencies/sub-dependencies.md | 8 ++++---- docs/zh/docs/tutorial/extra-data-types.md | 2 +- docs/zh/docs/tutorial/first-steps.md | 2 +- docs/zh/docs/tutorial/handling-errors.md | 2 +- .../tutorial/path-operation-configuration.md | 4 ++-- .../path-params-numeric-validations.md | 2 +- docs/zh/docs/tutorial/request-files.md | 20 +++++++++---------- .../docs/tutorial/request-forms-and-files.md | 5 ++--- docs/zh/docs/tutorial/request-forms.md | 10 +++++----- docs/zh/docs/tutorial/schema-extra-example.md | 2 +- docs/zh/docs/tutorial/security/index.md | 2 +- docs/zh/docs/tutorial/security/oauth2-jwt.md | 1 - pyproject.toml | 1 + 119 files changed, 228 insertions(+), 221 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 8176602a7..322b6536a 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -8,9 +8,9 @@ body: Thanks for your interest in FastAPI! 🚀 Please follow these instructions, fill every question, and do every step. 🙏 - + I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time. - + I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues. All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others. @@ -18,7 +18,7 @@ body: That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅). By asking questions in a structured way (following this) it will be much easier to help you. - + And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎 As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓 @@ -50,7 +50,7 @@ body: label: Commit to Help description: | After submitting this, I commit to one of: - + * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. * I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. * Implement a Pull Request for a confirmed bug. diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index 5c76fd17e..3b16b4ad0 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -8,9 +8,9 @@ body: Thanks for your interest in FastAPI! 🚀 Please follow these instructions, fill every question, and do every step. 🙏 - + I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time. - + I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues. All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others. @@ -18,7 +18,7 @@ body: That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅). By asking questions in a structured way (following this) it will be much easier to help you. - + And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎 As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓 @@ -50,7 +50,7 @@ body: label: Commit to Help description: | After submitting this, I commit to one of: - + * Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there. * I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future. * Implement a Pull Request for a confirmed bug. diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml index 42236beba..5783c993a 100644 --- a/.github/workflows/latest-changes.yml +++ b/.github/workflows/latest-changes.yml @@ -12,7 +12,7 @@ on: description: PR number required: true 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 default: false diff --git a/.github/workflows/people.yml b/.github/workflows/people.yml index 970813da7..2004ee7b3 100644 --- a/.github/workflows/people.yml +++ b/.github/workflows/people.yml @@ -6,7 +6,7 @@ on: workflow_dispatch: inputs: 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 default: false diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml index 0c0d2ac59..104c2677f 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/preview-docs.yml @@ -3,7 +3,7 @@ on: workflow_run: workflows: - Build Docs - types: + types: - completed jobs: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..2d9dce2d8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,14 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.2.0 + hooks: + - id: check-added-large-files + - id: check-toml + - id: check-yaml + args: + - --unsafe + - id: end-of-file-fixer + - id: trailing-whitespace + diff --git a/docs/de/docs/features.md b/docs/de/docs/features.md index 767a17073..d99ade402 100644 --- a/docs/de/docs/features.md +++ b/docs/de/docs/features.md @@ -27,7 +27,7 @@ Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzers Alles basiert auf **Python 3.6 Typ**-Deklarationen (dank Pydantic). Es muss keine neue Syntax gelernt werden, nur standardisiertes modernes Python. - + Wenn Sie eine kurze, zweiminütige, Auffrischung in der Benutzung von Python Typ-Deklarationen benötigen (auch wenn Sie FastAPI nicht nutzen), schauen Sie sich diese kurze Einführung an (Englisch): Python Types{.internal-link target=_blank}. diff --git a/docs/de/docs/index.md b/docs/de/docs/index.md index cdce66223..ce13bcc4a 100644 --- a/docs/de/docs/index.md +++ b/docs/de/docs/index.md @@ -321,7 +321,7 @@ And now, go to Falcon @@ -333,7 +333,7 @@ Now APIStar is a set of tools to validate OpenAPI specifications, not a web fram Exist. The idea of declaring multiple things (data validation, serialization and documentation) with the same Python types, that at the same time provided great editor support, was something I considered a brilliant idea. - + And after searching for a long time for a similar framework and testing many different alternatives, APIStar was the best option available. Then APIStar stopped to exist as a server and Starlette was created, and was a new better foundation for such a system. That was the final inspiration to build **FastAPI**. @@ -391,7 +391,7 @@ That's one of the main things that **FastAPI** adds on top, all based on Python Handle all the core web parts. Adding features on top. The class `FastAPI` itself inherits directly from the class `Starlette`. - + So, anything that you can do with Starlette, you can do it directly with **FastAPI**, as it is basically Starlette on steroids. ### Uvicorn diff --git a/docs/en/docs/deployment/docker.md b/docs/en/docs/deployment/docker.md index 3f86efcce..651b0e840 100644 --- a/docs/en/docs/deployment/docker.md +++ b/docs/en/docs/deployment/docker.md @@ -350,7 +350,7 @@ If your FastAPI is a single file, for example, `main.py` without an `./app` dire Then you would just have to change the corresponding paths to copy the file inside the `Dockerfile`: ```{ .dockerfile .annotate hl_lines="10 13" } -FROM python:3.9 +FROM python:3.9 WORKDIR /code diff --git a/docs/en/docs/deployment/manually.md b/docs/en/docs/deployment/manually.md index 16286533a..d6892b2c1 100644 --- a/docs/en/docs/deployment/manually.md +++ b/docs/en/docs/deployment/manually.md @@ -38,7 +38,7 @@ You can install an ASGI compatible server with: !!! tip By adding the `standard`, Uvicorn will install and use some recommended extra dependencies. - + That including `uvloop`, the high-performance drop-in replacement for `asyncio`, that provides the big concurrency performance boost. === "Hypercorn" @@ -89,7 +89,7 @@ You can then run your application the same way you have done in the tutorials, b Remember to remove the `--reload` option if you were using it. The `--reload` option consumes much more resources, is more unstable, etc. - + It helps a lot during **development**, but you **shouldn't** use it in **production**. ## Hypercorn with Trio diff --git a/docs/en/docs/img/deployment/concepts/process-ram.drawio b/docs/en/docs/img/deployment/concepts/process-ram.drawio index 51fc30ed3..b29c8a342 100644 --- a/docs/en/docs/img/deployment/concepts/process-ram.drawio +++ b/docs/en/docs/img/deployment/concepts/process-ram.drawio @@ -103,4 +103,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/concepts/process-ram.svg b/docs/en/docs/img/deployment/concepts/process-ram.svg index cd086c36b..c1bf0d589 100644 --- a/docs/en/docs/img/deployment/concepts/process-ram.svg +++ b/docs/en/docs/img/deployment/concepts/process-ram.svg @@ -56,4 +56,4 @@ }
Server
Server
RAM
RAM
CPU
CPU -
Process Manager
Process Manager
Worker Process
Worker Process
Worker Process
Worker Process
Another Process
Another Process
1 GB
1 GB
1 GB
1 GB
Viewer does not support full SVG 1.1 \ No newline at end of file +
Process Manager
Process Manager
Worker Process
Worker Process
Worker Process
Worker Process
Another Process
Another Process
1 GB
1 GB
1 GB
1 GB
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/deployment/https/https.drawio b/docs/en/docs/img/deployment/https/https.drawio index 31cfab96b..c4c8a3628 100644 --- a/docs/en/docs/img/deployment/https/https.drawio +++ b/docs/en/docs/img/deployment/https/https.drawio @@ -274,4 +274,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/https/https.svg b/docs/en/docs/img/deployment/https/https.svg index e63345eba..69497518a 100644 --- a/docs/en/docs/img/deployment/https/https.svg +++ b/docs/en/docs/img/deployment/https/https.svg @@ -59,4 +59,4 @@
someapp.example.com
someapp.example.com
another.example.net
another.example.net
onemore.example.org
onemore.example.org -
IP:
123.124.125.126
IP:...
Decrypted request for: someapp.example.com
Decrypted request for: someapp.example.com
Viewer does not support full SVG 1.1 \ No newline at end of file +
IP:
123.124.125.126
IP:...
Decrypted request for: someapp.example.com
Decrypted request for: someapp.example.com
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/deployment/https/https01.drawio b/docs/en/docs/img/deployment/https/https01.drawio index 9bc5340ce..181582f9b 100644 --- a/docs/en/docs/img/deployment/https/https01.drawio +++ b/docs/en/docs/img/deployment/https/https01.drawio @@ -75,4 +75,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/https/https01.svg b/docs/en/docs/img/deployment/https/https01.svg index 4fee0adfc..2edbd0623 100644 --- a/docs/en/docs/img/deployment/https/https01.svg +++ b/docs/en/docs/img/deployment/https/https01.svg @@ -54,4 +54,4 @@ src: url("https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu4mxK.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } -
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 \ No newline at end of file +
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/deployment/https/https02.drawio b/docs/en/docs/img/deployment/https/https02.drawio index 0f7578d3e..650c06d1e 100644 --- a/docs/en/docs/img/deployment/https/https02.drawio +++ b/docs/en/docs/img/deployment/https/https02.drawio @@ -107,4 +107,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/https/https02.svg b/docs/en/docs/img/deployment/https/https02.svg index 1f37a7098..e16b7e94a 100644 --- a/docs/en/docs/img/deployment/https/https02.svg +++ b/docs/en/docs/img/deployment/https/https02.svg @@ -54,4 +54,4 @@ src: url("https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu4mxK.woff2") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } -
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
Port 443 (HTTPS)
Port 443 (HTTPS)
IP:
123.124.125.126
IP:...
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
TLS Handshake
TLS Handshake
Viewer does not support full SVG 1.1 \ No newline at end of file +
Server(s)
Server(s)
https://someapp.example.com
https://someapp.example.com
DNS Servers
DNS Servers
Port 443 (HTTPS)
Port 443 (HTTPS)
IP:
123.124.125.126
IP:...
Who is: someapp.example.com
Who is: someapp.example.com
IP:
123.124.125.126
IP:...
TLS Handshake
TLS Handshake
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/deployment/https/https03.drawio b/docs/en/docs/img/deployment/https/https03.drawio index c5766086c..c178fd363 100644 --- a/docs/en/docs/img/deployment/https/https03.drawio +++ b/docs/en/docs/img/deployment/https/https03.drawio @@ -128,4 +128,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/https/https03.svg b/docs/en/docs/img/deployment/https/https03.svg index e68e1c459..2badd1c7d 100644 --- a/docs/en/docs/img/deployment/https/https03.svg +++ b/docs/en/docs/img/deployment/https/https03.svg @@ -59,4 +59,4 @@
someapp.example.com
someapp.example.com
another.example.net
another.example.net
onemore.example.org
onemore.example.org -
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 \ No newline at end of file +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/deployment/https/https04.drawio b/docs/en/docs/img/deployment/https/https04.drawio index ea357a6c1..78a6e919a 100644 --- a/docs/en/docs/img/deployment/https/https04.drawio +++ b/docs/en/docs/img/deployment/https/https04.drawio @@ -149,4 +149,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/https/https04.svg b/docs/en/docs/img/deployment/https/https04.svg index 4c9b7999b..4513ac76b 100644 --- a/docs/en/docs/img/deployment/https/https04.svg +++ b/docs/en/docs/img/deployment/https/https04.svg @@ -59,4 +59,4 @@
someapp.example.com
someapp.example.com
another.example.net
another.example.net
onemore.example.org
onemore.example.org -
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 \ No newline at end of file +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/deployment/https/https05.drawio b/docs/en/docs/img/deployment/https/https05.drawio index 9b8b7c6f7..236ecd841 100644 --- a/docs/en/docs/img/deployment/https/https05.drawio +++ b/docs/en/docs/img/deployment/https/https05.drawio @@ -163,4 +163,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/https/https05.svg b/docs/en/docs/img/deployment/https/https05.svg index d11647b9b..ddcd2760a 100644 --- a/docs/en/docs/img/deployment/https/https05.svg +++ b/docs/en/docs/img/deployment/https/https05.svg @@ -59,4 +59,4 @@
someapp.example.com
someapp.example.com
another.example.net
another.example.net
onemore.example.org
onemore.example.org -
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 \ No newline at end of file +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/deployment/https/https06.drawio b/docs/en/docs/img/deployment/https/https06.drawio index 5bb85813f..9dec13184 100644 --- a/docs/en/docs/img/deployment/https/https06.drawio +++ b/docs/en/docs/img/deployment/https/https06.drawio @@ -180,4 +180,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/https/https06.svg b/docs/en/docs/img/deployment/https/https06.svg index 10e03b7c5..3695de40c 100644 --- a/docs/en/docs/img/deployment/https/https06.svg +++ b/docs/en/docs/img/deployment/https/https06.svg @@ -59,4 +59,4 @@
someapp.example.com
someapp.example.com
another.example.net
another.example.net
onemore.example.org
onemore.example.org -
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 \ No newline at end of file +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/deployment/https/https07.drawio b/docs/en/docs/img/deployment/https/https07.drawio index 1ca994b22..aa8f4d6be 100644 --- a/docs/en/docs/img/deployment/https/https07.drawio +++ b/docs/en/docs/img/deployment/https/https07.drawio @@ -200,4 +200,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/https/https07.svg b/docs/en/docs/img/deployment/https/https07.svg index e409d8871..551354cef 100644 --- a/docs/en/docs/img/deployment/https/https07.svg +++ b/docs/en/docs/img/deployment/https/https07.svg @@ -59,4 +59,4 @@
someapp.example.com
someapp.example.com
another.example.net
another.example.net
onemore.example.org
onemore.example.org -
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 \ No newline at end of file +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/deployment/https/https08.drawio b/docs/en/docs/img/deployment/https/https08.drawio index 8a4f41056..794b192df 100644 --- a/docs/en/docs/img/deployment/https/https08.drawio +++ b/docs/en/docs/img/deployment/https/https08.drawio @@ -214,4 +214,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/deployment/https/https08.svg b/docs/en/docs/img/deployment/https/https08.svg index 3047dd821..2d4680dcc 100644 --- a/docs/en/docs/img/deployment/https/https08.svg +++ b/docs/en/docs/img/deployment/https/https08.svg @@ -59,4 +59,4 @@
someapp.example.com
someapp.example.com
another.example.net
another.example.net
onemore.example.org
onemore.example.org -
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 \ No newline at end of file +
IP:
123.124.125.126
IP:...
Viewer does not support full SVG 1.1 diff --git a/docs/en/docs/img/tutorial/bigger-applications/package.drawio b/docs/en/docs/img/tutorial/bigger-applications/package.drawio index 48f6e76fe..cab3de2ca 100644 --- a/docs/en/docs/img/tutorial/bigger-applications/package.drawio +++ b/docs/en/docs/img/tutorial/bigger-applications/package.drawio @@ -40,4 +40,4 @@ - \ No newline at end of file + diff --git a/docs/en/docs/img/tutorial/bigger-applications/package.svg b/docs/en/docs/img/tutorial/bigger-applications/package.svg index a9cec926a..44da1dc30 100644 --- a/docs/en/docs/img/tutorial/bigger-applications/package.svg +++ b/docs/en/docs/img/tutorial/bigger-applications/package.svg @@ -1 +1 @@ -
Package app
app/__init__.py
Package app...
Module app.main
app/main.py
Module app.main...
Module app.dependencies
app/dependencies.py
Module app.dependencies...
Subpackage app.internal
app/internal/__init__.py
Subpackage app.internal...
Module app.internal.admin
app/internal/admin.py
Module app.internal.admin...
Subpackage app.routers
app/routers/__init__.py
Subpackage app.routers...
Module app.routers.items
app/routers/items.py
Module app.routers.items...
Module app.routers.users
app/routers/users.py
Module app.routers.users...
Viewer does not support full SVG 1.1
\ No newline at end of file +
Package app
app/__init__.py
Package app...
Module app.main
app/main.py
Module app.main...
Module app.dependencies
app/dependencies.py
Module app.dependencies...
Subpackage app.internal
app/internal/__init__.py
Subpackage app.internal...
Module app.internal.admin
app/internal/admin.py
Module app.internal.admin...
Subpackage app.routers
app/routers/__init__.py
Subpackage app.routers...
Module app.routers.items
app/routers/items.py
Module app.routers.items...
Module app.routers.users
app/routers/users.py
Module app.routers.users...
Viewer does not support full SVG 1.1
diff --git a/docs/en/docs/js/termynal.js b/docs/en/docs/js/termynal.js index 8b0e9339e..4ac32708a 100644 --- a/docs/en/docs/js/termynal.js +++ b/docs/en/docs/js/termynal.js @@ -72,14 +72,14 @@ class Termynal { * Initialise the widget, get lines, clear container and start animation. */ init() { - /** + /** * Calculates width and height of Termynal container. * If container is empty and lines are dynamically loaded, defaults to browser `auto` or CSS. - */ + */ const containerStyle = getComputedStyle(this.container); - this.container.style.width = containerStyle.width !== '0px' ? + this.container.style.width = containerStyle.width !== '0px' ? containerStyle.width : undefined; - this.container.style.minHeight = containerStyle.height !== '0px' ? + this.container.style.minHeight = containerStyle.height !== '0px' ? containerStyle.height : undefined; this.container.setAttribute('data-termynal', ''); @@ -138,7 +138,7 @@ class Termynal { restart.innerHTML = "restart ↻" return restart } - + generateFinish() { const finish = document.createElement('a') finish.onclick = (e) => { @@ -215,7 +215,7 @@ class Termynal { /** * Converts line data objects into line elements. - * + * * @param {Object[]} lineData - Dynamically loaded lines. * @param {Object} line - Line data object. * @returns {Element[]} - Array of line elements. @@ -231,7 +231,7 @@ class Termynal { /** * Helper function for generating attributes string. - * + * * @param {Object} line - Line data object. * @returns {string} - String of attributes. */ diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index fe56dadec..8486ed849 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -29,7 +29,7 @@ Calling this program outputs: John Doe ``` -The function does the following: +The function does the following: * Takes a `first_name` and `last_name`. * Converts the first letter of each one to upper case with `title()`. @@ -334,14 +334,14 @@ These types that take type parameters in square brackets are called **Generic ty === "Python 3.9 and above" You can use the same builtin types as generics (with square brakets and types inside): - + * `list` * `tuple` * `set` * `dict` And the same as with Python 3.6, from the `typing` module: - + * `Union` * `Optional` * ...and others. @@ -354,7 +354,7 @@ These types that take type parameters in square brackets are called **Generic ty * `tuple` * `set` * `dict` - + And the same as with Python 3.6, from the `typing` module: * `Union` diff --git a/docs/en/docs/tutorial/bigger-applications.md b/docs/en/docs/tutorial/bigger-applications.md index 2a2e764b5..d201953df 100644 --- a/docs/en/docs/tutorial/bigger-applications.md +++ b/docs/en/docs/tutorial/bigger-applications.md @@ -334,7 +334,7 @@ from app.routers import items, users ```Python from .routers import items, users ``` - + The second version is an "absolute import": ```Python diff --git a/docs/en/docs/tutorial/body-nested-models.md b/docs/en/docs/tutorial/body-nested-models.md index fa38cfc48..bfc948f4f 100644 --- a/docs/en/docs/tutorial/body-nested-models.md +++ b/docs/en/docs/tutorial/body-nested-models.md @@ -366,7 +366,7 @@ In this case, you would accept any `dict` as long as it has `int` keys with `flo But Pydantic has automatic data conversion. This means that, even though your API clients can only send strings as keys, as long as those strings contain pure integers, Pydantic will convert them and validate them. - + And the `dict` you receive as `weights` will actually have `int` keys and `float` values. ## Recap diff --git a/docs/en/docs/tutorial/body.md b/docs/en/docs/tutorial/body.md index 81441b41e..eb21f29a8 100644 --- a/docs/en/docs/tutorial/body.md +++ b/docs/en/docs/tutorial/body.md @@ -138,7 +138,7 @@ But you would get the same editor support with PyCharm as your editor, you can use the Pydantic PyCharm Plugin. It improves editor support for Pydantic models, with: - + * auto-completion * type checks * refactoring diff --git a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md index ac2e9cb8c..a7300f0b7 100644 --- a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md @@ -10,7 +10,7 @@ To do this, use `yield` instead of `return`, and write the extra steps after. !!! note "Technical Details" Any function that is valid to use with: - * `@contextlib.contextmanager` or + * `@contextlib.contextmanager` or * `@contextlib.asynccontextmanager` would be valid to use as a **FastAPI** dependency. @@ -207,7 +207,7 @@ You can also use them inside of **FastAPI** dependencies with `yield` by using !!! tip Another way to create a context manager is with: - * `@contextlib.contextmanager` or + * `@contextlib.contextmanager` or * `@contextlib.asynccontextmanager` using them to decorate a function with a single `yield`. diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md index 3ca471a91..664a1102f 100644 --- a/docs/en/docs/tutorial/request-files.md +++ b/docs/en/docs/tutorial/request-files.md @@ -106,7 +106,7 @@ The way HTML forms (`
`) sends the data to the server normally uses Data from forms is normally encoded using the "media type" `application/x-www-form-urlencoded` when it doesn't include files. But when the form includes files, it is encoded as `multipart/form-data`. If you use `File`, **FastAPI** will know it has to get the files from the correct part of the body. - + If you want to read more about these encodings and form fields, head to the MDN web docs for POST. !!! warning diff --git a/docs/en/docs/tutorial/request-forms.md b/docs/en/docs/tutorial/request-forms.md index b5495a400..2021a098f 100644 --- a/docs/en/docs/tutorial/request-forms.md +++ b/docs/en/docs/tutorial/request-forms.md @@ -45,7 +45,7 @@ The way HTML forms (`
`) sends the data to the server normally uses Data from forms is normally encoded using the "media type" `application/x-www-form-urlencoded`. But when the form includes files, it is encoded as `multipart/form-data`. You'll read about handling files in the next chapter. - + If you want to read more about these encodings and form fields, head to the MDN web docs for POST. !!! warning diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index cac02ca7c..eb1cb5c82 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -69,9 +69,9 @@ }); }); -Marshmallow -L'une des principales fonctionnalités nécessaires aux systèmes API est la "sérialisation" des données, qui consiste à prendre les données du code (Python) et à les convertir en quelque chose qui peut être envoyé sur le réseau. Par exemple, convertir un objet contenant des données provenant d'une base de données en un objet JSON. Convertir des objets `datetime` en strings, etc. @@ -147,7 +147,7 @@ Sans un système de validation des données, vous devriez effectuer toutes les v Ces fonctionnalités sont ce pourquoi Marshmallow a été construit. C'est une excellente bibliothèque, et je l'ai déjà beaucoup utilisée. -Mais elle a été créée avant que les type hints n'existent en Python. Ainsi, pour définir chaque schéma, vous devez utiliser des utilitaires et des classes spécifiques fournies par Marshmallow. !!! check "A inspiré **FastAPI** à" @@ -155,7 +155,7 @@ Utilisez du code pour définir des "schémas" qui fournissent automatiquement le ### Webargs -Une autre grande fonctionnalité requise par les API est le parsing des données provenant des requêtes entrantes. Webargs est un outil qui a été créé pour fournir cela par-dessus plusieurs frameworks, dont Flask. diff --git a/docs/fr/docs/async.md b/docs/fr/docs/async.md index 20f4ee101..71c28b703 100644 --- a/docs/fr/docs/async.md +++ b/docs/fr/docs/async.md @@ -220,7 +220,7 @@ Et comme on peut avoir du parallélisme et de l'asynchronicité en même temps, Nope ! C'est ça la morale de l'histoire. La concurrence est différente du parallélisme. C'est mieux sur des scénarios **spécifiques** qui impliquent beaucoup d'attente. À cause de ça, c'est généralement bien meilleur que le parallélisme pour le développement d'applications web. Mais pas pour tout. - + Donc pour équilibrer tout ça, imaginez l'histoire suivante : > Vous devez nettoyer une grande et sale maison. @@ -293,7 +293,7 @@ def get_sequential_burgers(number: int): Avec `async def`, Python sait que dans cette fonction il doit prendre en compte les expressions `await`, et qu'il peut mettre en pause ⏸ l'exécution de la fonction pour aller faire autre chose 🔀 avant de revenir. -Pour appeler une fonction définie avec `async def`, vous devez utiliser `await`. Donc ceci ne marche pas : +Pour appeler une fonction définie avec `async def`, vous devez utiliser `await`. Donc ceci ne marche pas : ```Python # Ceci ne fonctionne pas, car get_burgers a été défini avec async def @@ -375,7 +375,7 @@ Au final, dans les deux situations, il est fort probable que **FastAPI** soit to La même chose s'applique aux dépendances. Si une dépendance est définie avec `def` plutôt que `async def`, elle est exécutée dans la threadpool externe. -### Sous-dépendances +### Sous-dépendances Vous pouvez avoir de multiples dépendances et sous-dépendances dépendant les unes des autres (en tant que paramètres de la définition de la *fonction de chemin*), certaines créées avec `async def` et d'autres avec `def`. Cela fonctionnerait aussi, et celles définies avec un simple `def` seraient exécutées sur un thread externe (venant de la threadpool) plutôt que d'être "attendues". diff --git a/docs/fr/docs/deployment/docker.md b/docs/fr/docs/deployment/docker.md index e4b59afbf..d2dcae722 100644 --- a/docs/fr/docs/deployment/docker.md +++ b/docs/fr/docs/deployment/docker.md @@ -118,7 +118,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage -Vous disposez maintenant d'un serveur FastAPI optimisé dans un conteneur Docker. Configuré automatiquement pour votre +Vous disposez maintenant d'un serveur FastAPI optimisé dans un conteneur Docker. Configuré automatiquement pour votre serveur actuel (et le nombre de cœurs du CPU). ## Vérifier @@ -139,7 +139,7 @@ Vous verrez la documentation interactive automatique de l'API (fournie par http://192.168.99.100/redoc ou http://127.0.0.1/redoc (ou équivalent, en utilisant votre hôte Docker). @@ -149,7 +149,7 @@ Vous verrez la documentation automatique alternative (fournie par Traefik est un reverse proxy/load balancer +Traefik est un reverse proxy/load balancer haute performance. Il peut faire office de "Proxy de terminaison TLS" (entre autres fonctionnalités). Il est intégré à Let's Encrypt. Ainsi, il peut gérer toutes les parties HTTPS, y compris l'acquisition et le renouvellement des certificats. @@ -164,7 +164,7 @@ Avec ces informations et ces outils, passez à la section suivante pour tout com Vous pouvez avoir un cluster en mode Docker Swarm configuré en quelques minutes (environ 20 min) avec un processus Traefik principal gérant HTTPS (y compris l'acquisition et le renouvellement des certificats). -En utilisant le mode Docker Swarm, vous pouvez commencer par un "cluster" d'une seule machine (il peut même s'agir +En utilisant le mode Docker Swarm, vous pouvez commencer par un "cluster" d'une seule machine (il peut même s'agir d'un serveur à 5 USD/mois) et ensuite vous pouvez vous développer autant que vous le souhaitez en ajoutant d'autres serveurs. Pour configurer un cluster en mode Docker Swarm avec Traefik et la gestion de HTTPS, suivez ce guide : diff --git a/docs/fr/docs/features.md b/docs/fr/docs/features.md index 4b00ecb6f..dcc0e39ed 100644 --- a/docs/fr/docs/features.md +++ b/docs/fr/docs/features.md @@ -27,7 +27,7 @@ Documentation d'API interactive et interface web d'exploration. Comme le framewo Tout est basé sur la déclaration de type standard de **Python 3.6** (grâce à Pydantic). Pas de nouvelles syntaxes à apprendre. Juste du Python standard et moderne. -Si vous souhaitez un rappel de 2 minutes sur l'utilisation des types en Python (même si vous ne comptez pas utiliser FastAPI), jetez un oeil au tutoriel suivant: [Python Types](python-types.md){.internal-link target=_blank}. +Si vous souhaitez un rappel de 2 minutes sur l'utilisation des types en Python (même si vous ne comptez pas utiliser FastAPI), jetez un oeil au tutoriel suivant: [Python Types](python-types.md){.internal-link target=_blank}. Vous écrivez du python standard avec des annotations de types: diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md index 3922d9c77..0b537054e 100644 --- a/docs/fr/docs/index.md +++ b/docs/fr/docs/index.md @@ -321,7 +321,7 @@ And now, go to http://127.0.0.1:8000/items/foo, vous verrez comme réponse : @@ -44,7 +44,7 @@ Si vous exécutez cet exemple et allez sur "parsing" automatique. ## Validation de données @@ -91,7 +91,7 @@ documentation générée automatiquement et interactive : On voit bien dans la documentation que `item_id` est déclaré comme entier. -## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative. +## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative. Le schéma généré suivant la norme OpenAPI, il existe de nombreux outils compatibles. @@ -102,7 +102,7 @@ sur De la même façon, il existe bien d'autres outils compatibles, y compris des outils de génération de code -pour de nombreux langages. +pour de nombreux langages. ## Pydantic diff --git a/docs/fr/docs/tutorial/query-params.md b/docs/fr/docs/tutorial/query-params.md index f1f2a605d..7bf3b9e79 100644 --- a/docs/fr/docs/tutorial/query-params.md +++ b/docs/fr/docs/tutorial/query-params.md @@ -6,7 +6,7 @@ Quand vous déclarez des paramètres dans votre fonction de chemin qui ne font p {!../../../docs_src/query_params/tutorial001.py!} ``` -La partie appelée requête (ou **query**) dans une URL est l'ensemble des paires clés-valeurs placées après le `?` , séparées par des `&`. +La partie appelée requête (ou **query**) dans une URL est l'ensemble des paires clés-valeurs placées après le `?` , séparées par des `&`. Par exemple, dans l'URL : @@ -120,7 +120,7 @@ ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la ## Multiples paramètres de chemin et de requête -Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête dans la même fonction, **FastAPI** saura comment les gérer. +Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête dans la même fonction, **FastAPI** saura comment les gérer. Et vous n'avez pas besoin de les déclarer dans un ordre spécifique. diff --git a/docs/id/docs/index.md b/docs/id/docs/index.md index a7af14781..0bb7b55e3 100644 --- a/docs/id/docs/index.md +++ b/docs/id/docs/index.md @@ -321,7 +321,7 @@ And now, go to https://github.com/tiangolo/full-stack * https://github.com/tiangolo/full-stack-flask-couchbase -* https://github.com/tiangolo/full-stack-flask-couchdb +* https://github.com/tiangolo/full-stack-flask-couchdb そして、これらのフルスタックジェネレーターは、[**FastAPI** Project Generators](project-generation.md){.internal-link target=_blank}の元となっていました。 @@ -295,7 +295,7 @@ OpenAPIやJSON Schemaのような標準に基づいたものではありませ HugはAPIStarに部分的なインスピレーションを与えており、私が発見した中ではAPIStarと同様に最も期待の持てるツールの一つでした。 Hugは、**FastAPI**がPythonの型ヒントを用いてパラメータを宣言し自動的にAPIを定義するスキーマを生成することを触発しました。 - + Hugは、**FastAPI**がヘッダーやクッキーを設定するために関数に `response`引数を宣言することにインスピレーションを与えました。 ### APIStar (<= 0.5) diff --git a/docs/ja/docs/async.md b/docs/ja/docs/async.md index eff4f2f43..8fac2cb38 100644 --- a/docs/ja/docs/async.md +++ b/docs/ja/docs/async.md @@ -361,7 +361,7 @@ async def read_burgers(): この部分は**FastAPI**の仕組みに関する非常に技術的な詳細です。 かなりの技術知識 (コルーチン、スレッド、ブロッキングなど) があり、FastAPIが `async def` と通常の `def` をどのように処理するか知りたい場合は、先に進んでください。 - + ### Path operation 関数 *path operation 関数*を `async def` の代わりに通常の `def` で宣言すると、(サーバーをブロックするので) 直接呼び出す代わりに外部スレッドプール (awaitされる) で実行されます。 diff --git a/docs/ja/docs/deployment/index.md b/docs/ja/docs/deployment/index.md index 2ce81b551..40710a93a 100644 --- a/docs/ja/docs/deployment/index.md +++ b/docs/ja/docs/deployment/index.md @@ -4,4 +4,4 @@ ユースケースや使用しているツールによっていくつかの方法に分かれます。 -次のセクションでより詳しくそれらの方法について説明します。 \ No newline at end of file +次のセクションでより詳しくそれらの方法について説明します。 diff --git a/docs/ja/docs/deployment/manually.md b/docs/ja/docs/deployment/manually.md index 3296ba76f..dd4b568bd 100644 --- a/docs/ja/docs/deployment/manually.md +++ b/docs/ja/docs/deployment/manually.md @@ -20,7 +20,7 @@ !!! tip "豆知識" `standard` を加えることで、Uvicornがインストールされ、いくつかの推奨される依存関係を利用するようになります。 - + これには、`asyncio` の高性能な完全互換品である `uvloop` が含まれ、並行処理のパフォーマンスが大幅に向上します。 === "Hypercorn" diff --git a/docs/ja/docs/history-design-future.md b/docs/ja/docs/history-design-future.md index 778252d4e..d0d1230c4 100644 --- a/docs/ja/docs/history-design-future.md +++ b/docs/ja/docs/history-design-future.md @@ -77,4 +77,4 @@ **FastAPI**には大きな未来が待っています。 -そして、[あなたの助け](help-fastapi.md){.internal-link target=_blank}を大いに歓迎します。 \ No newline at end of file +そして、[あなたの助け](help-fastapi.md){.internal-link target=_blank}を大いに歓迎します。 diff --git a/docs/ja/docs/tutorial/body.md b/docs/ja/docs/tutorial/body.md index 59388d904..d2559205b 100644 --- a/docs/ja/docs/tutorial/body.md +++ b/docs/ja/docs/tutorial/body.md @@ -114,7 +114,7 @@ APIはほとんどの場合 **レスポンス** ボディを送らなければ PyCharmエディタを使用している場合は、Pydantic PyCharm Pluginが使用可能です。 以下のエディターサポートが強化されます: - + * 自動補完 * 型チェック * リファクタリング @@ -157,7 +157,7 @@ APIはほとんどの場合 **レスポンス** ボディを送らなければ !!! note "備考" FastAPIは、`= None`があるおかげで、`q`がオプショナルだとわかります。 - + `Optional[str]` の`Optional` はFastAPIでは使用されていません(FastAPIは`str`の部分のみ使用します)。しかし、`Optional[str]` はエディタがコードのエラーを見つけるのを助けてくれます。 ## Pydanticを使わない方法 diff --git a/docs/ja/docs/tutorial/middleware.md b/docs/ja/docs/tutorial/middleware.md index f2a22119b..973eb2b1a 100644 --- a/docs/ja/docs/tutorial/middleware.md +++ b/docs/ja/docs/tutorial/middleware.md @@ -35,7 +35,7 @@ !!! tip "豆知識" 'X-'プレフィックスを使用してカスタムの独自ヘッダーを追加できます。 - ただし、ブラウザのクライアントに表示させたいカスタムヘッダーがある場合は、StarletteのCORSドキュメントに記載されているパラメータ `expose_headers` を使用して、それらをCORS設定に追加する必要があります ([CORS (オリジン間リソース共有)](cors.md){.internal-link target=_blank}) + ただし、ブラウザのクライアントに表示させたいカスタムヘッダーがある場合は、StarletteのCORSドキュメントに記載されているパラメータ `expose_headers` を使用して、それらをCORS設定に追加する必要があります ([CORS (オリジン間リソース共有)](cors.md){.internal-link target=_blank}) !!! note "技術詳細" `from starlette.requests import Request` を使用することもできます。 diff --git a/docs/ja/docs/tutorial/path-params.md b/docs/ja/docs/tutorial/path-params.md index 452ca0c98..66de05afb 100644 --- a/docs/ja/docs/tutorial/path-params.md +++ b/docs/ja/docs/tutorial/path-params.md @@ -139,7 +139,7 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー ### *パスパラメータ*の宣言 -次に、作成したenumクラスである`ModelName`を使用した型アノテーションをもつ*パスパラメータ*を作成します: +次に、作成したenumクラスである`ModelName`を使用した型アノテーションをもつ*パスパラメータ*を作成します: ```Python hl_lines="16" {!../../../docs_src/path_params/tutorial005.py!} diff --git a/docs/ja/docs/tutorial/query-params.md b/docs/ja/docs/tutorial/query-params.md index 91783a53a..9f8c6ab9f 100644 --- a/docs/ja/docs/tutorial/query-params.md +++ b/docs/ja/docs/tutorial/query-params.md @@ -18,7 +18,7 @@ http://127.0.0.1:8000/items/?skip=0&limit=10 ...クエリパラメータは: * `skip`: 値は `0` -* `limit`: 値は `10` +* `limit`: 値は `10` これらはURLの一部なので、「自然に」文字列になります。 @@ -75,7 +75,7 @@ http://127.0.0.1:8000/items/?skip=20 !!! note "備考" FastAPIは、`= None`があるおかげで、`q`がオプショナルだとわかります。 - + `Optional[str]` の`Optional` はFastAPIでは使用されていません(FastAPIは`str`の部分のみ使用します)。しかし、`Optional[str]` はエディタがコードのエラーを見つけるのを助けてくれます。 ## クエリパラメータの型変換 @@ -116,7 +116,7 @@ http://127.0.0.1:8000/items/foo?short=on http://127.0.0.1:8000/items/foo?short=yes ``` -もしくは、他の大文字小文字のバリエーション (アッパーケース、最初の文字だけアッパーケース、など)で、関数は `short` パラメータを `True` な `bool` 値として扱います。それ以外は `False` になります。 +もしくは、他の大文字小文字のバリエーション (アッパーケース、最初の文字だけアッパーケース、など)で、関数は `short` パラメータを `True` な `bool` 値として扱います。それ以外は `False` になります。 ## 複数のパスパラメータとクエリパラメータ diff --git a/docs/ja/docs/tutorial/request-forms.md b/docs/ja/docs/tutorial/request-forms.md index 06105c9ef..bce6e8d9a 100644 --- a/docs/ja/docs/tutorial/request-forms.md +++ b/docs/ja/docs/tutorial/request-forms.md @@ -45,7 +45,7 @@ HTMLフォーム(`
`)がサーバにデータを送信する方 フォームからのデータは通常、`application/x-www-form-urlencoded`の「media type」を使用してエンコードされます。 しかし、フォームがファイルを含む場合は、`multipart/form-data`としてエンコードされます。ファイルの扱いについては次の章で説明します。 - + これらのエンコーディングやフォームフィールドの詳細については、MDNPOSTのウェブドキュメントを参照してください。 !!! warning "注意" diff --git a/docs/ja/docs/tutorial/testing.md b/docs/ja/docs/tutorial/testing.md index 3db493294..03b0e1dee 100644 --- a/docs/ja/docs/tutorial/testing.md +++ b/docs/ja/docs/tutorial/testing.md @@ -36,7 +36,7 @@ !!! tip "豆知識" FastAPIアプリケーションへのリクエストの送信とは別に、テストで `async` 関数 (非同期データベース関数など) を呼び出したい場合は、高度なチュートリアルの[Async Tests](../advanced/async-tests.md){.internal-link target=_blank} を参照してください。 - + ## テストの分離 実際のアプリケーションでは、おそらくテストを別のファイルに保存します。 @@ -112,7 +112,7 @@ `TestClient` は、Pydanticモデルではなく、JSONに変換できるデータを受け取ることに注意してください。 テストにPydanticモデルがあり、テスト中にそのデータをアプリケーションに送信したい場合は、[JSON互換エンコーダ](encoder.md){.internal-link target=_blank} で説明されている `jsonable_encoder` が利用できます。 - + ## 実行 後は、`pytest` をインストールするだけです: diff --git a/docs/ko/docs/deployment/versions.md b/docs/ko/docs/deployment/versions.md index 4c1bcdc2e..074c15158 100644 --- a/docs/ko/docs/deployment/versions.md +++ b/docs/ko/docs/deployment/versions.md @@ -6,7 +6,7 @@ 이것이 아직도 최신 버전이 `0.x.x`인 이유입니다. 이것은 각각의 버전들이 잠재적으로 변할 수 있다는 것을 보여줍니다. 이는 유의적 버전 관습을 따릅니다. -지금 바로 **FastAPI**로 응용 프로그램을 만들 수 있습니다. 이때 (아마 지금까지 그래 왔던 것처럼), 사용하는 버전이 코드와 잘 맞는지 확인해야합니다. +지금 바로 **FastAPI**로 응용 프로그램을 만들 수 있습니다. 이때 (아마 지금까지 그래 왔던 것처럼), 사용하는 버전이 코드와 잘 맞는지 확인해야합니다. ## `fastapi` 버전을 표시 @@ -46,7 +46,7 @@ FastAPI는 오류를 수정하고, 일반적인 변경사항을 위해 "패치" !!! tip "팁" 여기서 말하는 "패치"란 버전의 마지막 숫자로, 예를 들어 `0.2.3` 버전에서 "패치"는 `3`을 의미합니다. -따라서 다음과 같이 버전을 표시할 수 있습니다: +따라서 다음과 같이 버전을 표시할 수 있습니다: ```txt fastapi>=0.45.0,<0.46.0 @@ -71,7 +71,7 @@ fastapi>=0.45.0,<0.46.0 `starlette`의 버전은 표시할 수 없습니다. -서로다른 버전의 **FastAPI**가 구체적이고 새로운 버전의 Starlette을 사용할 것입니다. +서로다른 버전의 **FastAPI**가 구체적이고 새로운 버전의 Starlette을 사용할 것입니다. 그러므로 **FastAPI**가 알맞은 Starlette 버전을 사용하도록 하십시오. diff --git a/docs/ko/docs/tutorial/header-params.md b/docs/ko/docs/tutorial/header-params.md index 1c46b32ba..484554e97 100644 --- a/docs/ko/docs/tutorial/header-params.md +++ b/docs/ko/docs/tutorial/header-params.md @@ -57,7 +57,7 @@ 타입 정의에서 리스트를 사용하여 이러한 케이스를 정의할 수 있습니다. -중복 헤더의 모든 값을 파이썬 `list`로 수신합니다. +중복 헤더의 모든 값을 파이썬 `list`로 수신합니다. 예를 들어, 두 번 이상 나타날 수 있는 `X-Token`헤더를 선언하려면, 다음과 같이 작성합니다: diff --git a/docs/ko/docs/tutorial/path-params.md b/docs/ko/docs/tutorial/path-params.md index ede63f69d..5cf397e7a 100644 --- a/docs/ko/docs/tutorial/path-params.md +++ b/docs/ko/docs/tutorial/path-params.md @@ -241,4 +241,4 @@ Starlette에서 직접 옵션을 사용하면 다음과 같은 URL을 사용하 위 사항들을 그저 한번에 선언하면 됩니다. -이는 (원래 성능과는 별개로) 대체 프레임워크와 비교했을 때 **FastAPI**의 주요 가시적 장점일 것입니다. \ No newline at end of file +이는 (원래 성능과는 별개로) 대체 프레임워크와 비교했을 때 **FastAPI**의 주요 가시적 장점일 것입니다. diff --git a/docs/ko/docs/tutorial/request-files.md b/docs/ko/docs/tutorial/request-files.md index 769a676cd..decefe981 100644 --- a/docs/ko/docs/tutorial/request-files.md +++ b/docs/ko/docs/tutorial/request-files.md @@ -13,7 +13,7 @@ `fastapi` 에서 `File` 과 `UploadFile` 을 임포트 합니다: -```Python hl_lines="1" +```Python hl_lines="1" {!../../../docs_src/request_files/tutorial001.py!} ``` @@ -21,7 +21,7 @@ `Body` 및 `Form` 과 동일한 방식으로 파일의 매개변수를 생성합니다: -```Python hl_lines="7" +```Python hl_lines="7" {!../../../docs_src/request_files/tutorial001.py!} ``` @@ -45,7 +45,7 @@ `File` 매개변수를 `UploadFile` 타입으로 정의합니다: -```Python hl_lines="12" +```Python hl_lines="12" {!../../../docs_src/request_files/tutorial001.py!} ``` @@ -97,7 +97,7 @@ contents = myfile.file.read() ## "폼 데이터"란 -HTML의 폼들(`
`)이 서버에 데이터를 전송하는 방식은 대개 데이터에 JSON과는 다른 "특별한" 인코딩을 사용합니다. +HTML의 폼들(`
`)이 서버에 데이터를 전송하는 방식은 대개 데이터에 JSON과는 다른 "특별한" 인코딩을 사용합니다. **FastAPI**는 JSON 대신 올바른 위치에서 데이터를 읽을 수 있도록 합니다. @@ -121,7 +121,7 @@ HTML의 폼들(`
`)이 서버에 데이터를 전송하는 방식은 이 기능을 사용하기 위해 , `bytes` 의 `List` 또는 `UploadFile` 를 선언하기 바랍니다: -```Python hl_lines="10 15" +```Python hl_lines="10 15" {!../../../docs_src/request_files/tutorial002.py!} ``` diff --git a/docs/ko/docs/tutorial/request-forms-and-files.md b/docs/ko/docs/tutorial/request-forms-and-files.md index 6750c7b23..ddf232e7f 100644 --- a/docs/ko/docs/tutorial/request-forms-and-files.md +++ b/docs/ko/docs/tutorial/request-forms-and-files.md @@ -9,7 +9,7 @@ ## `File` 및 `Form` 업로드 -```Python hl_lines="1" +```Python hl_lines="1" {!../../../docs_src/request_forms_and_files/tutorial001.py!} ``` @@ -17,7 +17,7 @@ `Body` 및 `Query`와 동일한 방식으로 파일과 폼의 매개변수를 생성합니다: -```Python hl_lines="8" +```Python hl_lines="8" {!../../../docs_src/request_forms_and_files/tutorial001.py!} ``` diff --git a/docs/ko/docs/tutorial/response-status-code.md b/docs/ko/docs/tutorial/response-status-code.md index d201867a1..f92c057be 100644 --- a/docs/ko/docs/tutorial/response-status-code.md +++ b/docs/ko/docs/tutorial/response-status-code.md @@ -8,11 +8,11 @@ * `@app.delete()` * 기타 -```Python hl_lines="6" +```Python hl_lines="6" {!../../../docs_src/response_status_code/tutorial001.py!} ``` -!!! note "참고" +!!! note "참고" `status_code` 는 "데코레이터" 메소드(`get`, `post` 등)의 매개변수입니다. 모든 매개변수들과 본문처럼 *경로 작동 함수*가 아닙니다. `status_code` 매개변수는 HTTP 상태 코드를 숫자로 입력받습니다. @@ -27,7 +27,7 @@ -!!! note "참고" +!!! note "참고" 어떤 응답 코드들은 해당 응답에 본문이 없다는 것을 의미하기도 합니다 (다음 항목 참고). 이에 따라 FastAPI는 응답 본문이 없음을 명시하는 OpenAPI를 생성합니다. @@ -61,7 +61,7 @@ HTTP는 세자리의 숫자 상태 코드를 응답의 일부로 전송합니다 상기 예시 참고: -```Python hl_lines="6" +```Python hl_lines="6" {!../../../docs_src/response_status_code/tutorial001.py!} ``` @@ -71,7 +71,7 @@ HTTP는 세자리의 숫자 상태 코드를 응답의 일부로 전송합니다 `fastapi.status` 의 편의 변수를 사용할 수 있습니다. -```Python hl_lines="1 6" +```Python hl_lines="1 6" {!../../../docs_src/response_status_code/tutorial002.py!} ``` diff --git a/docs/pl/docs/tutorial/index.md b/docs/pl/docs/tutorial/index.md index 1a97214af..ed8752a95 100644 --- a/docs/pl/docs/tutorial/index.md +++ b/docs/pl/docs/tutorial/index.md @@ -78,4 +78,3 @@ Jest też **Zaawansowany poradnik**, który możesz przeczytać po lekturze tego Najpierw jednak powinieneś przeczytać **Samouczek** (czytasz go teraz). Ten rozdział jest zaprojektowany tak, że możesz stworzyć kompletną aplikację używając tylko informacji tutaj zawartych, a następnie rozszerzać ją na różne sposoby, w zależności od potrzeb, używając kilku dodatkowych pomysłów z **Zaawansowanego poradnika**. - diff --git a/docs/pt/docs/alternatives.md b/docs/pt/docs/alternatives.md index 6559b7398..61ee4f900 100644 --- a/docs/pt/docs/alternatives.md +++ b/docs/pt/docs/alternatives.md @@ -331,7 +331,7 @@ Agora APIStar é um conjunto de ferramentas para validar especificações OpenAP Existir. A idéia de declarar múltiplas coisas (validação de dados, serialização e documentação) com os mesmos tipos Python, que ao mesmo tempo fornecesse grande suporte ao editor, era algo que eu considerava uma brilhante idéia. - + E após procurar por um logo tempo por um framework similar e testar muitas alternativas diferentes, APIStar foi a melhor opção disponível. Então APIStar parou de existir como um servidor e Starlette foi criado, e foi uma nova melhor fundação para tal sistema. Essa foi a inspiração final para construir **FastAPI**. @@ -390,7 +390,7 @@ Essa é uma das principais coisas que **FastAPI** adiciona no topo, tudo baseado Controlar todas as partes web centrais. Adiciona recursos no topo. A classe `FastAPI` em si herda `Starlette`. - + Então, qualquer coisa que você faz com Starlette, você pode fazer diretamente com **FastAPI**, pois ele é basicamente um Starlette com esteróides. ### Uvicorn diff --git a/docs/pt/docs/async.md b/docs/pt/docs/async.md index 44f4b5148..be1278a1b 100644 --- a/docs/pt/docs/async.md +++ b/docs/pt/docs/async.md @@ -94,7 +94,7 @@ Para "síncrono" (contrário de "assíncrono") também é utilizado o termo "seq Essa idéia de código **assíncrono** descrito acima é algo às vezes chamado de **"concorrência"**. E é diferente de **"paralelismo"**. -**Concorrência** e **paralelismo** ambos são relacionados a "diferentes coisas acontecendo mais ou menos ao mesmo tempo". +**Concorrência** e **paralelismo** ambos são relacionados a "diferentes coisas acontecendo mais ou menos ao mesmo tempo". Mas os detalhes entre *concorrência* e *paralelismo* são bem diferentes. @@ -134,7 +134,7 @@ Mas então, embora você ainda não tenha os hambúrgueres, seu trabalho no caix Mas enquanto você se afasta do balcão e senta na mesa com o número da sua chamada, você pode trocar sua atenção para seu _crush_ :heart_eyes:, e "trabalhar" nisso. Então você está novamente fazendo algo muito "produtivo", como flertar com seu _crush_ :heart_eyes:. -Então o caixa diz que "seus hambúrgueres estão prontos" colocando seu número no balcão, mas você não corre que nem um maluco imediatamente quando o número exibido é o seu. Você sabe que ninguém irá roubar seus hambúrgueres porquê você tem o número de chamada, e os outros tem os números deles. +Então o caixa diz que "seus hambúrgueres estão prontos" colocando seu número no balcão, mas você não corre que nem um maluco imediatamente quando o número exibido é o seu. Você sabe que ninguém irá roubar seus hambúrgueres porquê você tem o número de chamada, e os outros tem os números deles. Então você espera que seu _crush_ :heart_eyes: termine a história que estava contando (terminar o trabalho atual / tarefa sendo processada), sorri gentilmente e diz que você está indo buscar os hambúrgueres. @@ -358,9 +358,9 @@ Tudo isso é o que deixa o FastAPI poderoso (através do Starlette) e que o faz !!! warning Você pode provavelmente pular isso. - + Esses são detalhes muito técnicos de como **FastAPI** funciona por baixo do capô. - + Se você tem algum conhecimento técnico (corrotinas, threads, blocking etc) e está curioso sobre como o FastAPI controla o `async def` vs normal `def`, vá em frente. ### Funções de operação de rota diff --git a/docs/pt/docs/benchmarks.md b/docs/pt/docs/benchmarks.md index 7f7c95ba1..07461ce46 100644 --- a/docs/pt/docs/benchmarks.md +++ b/docs/pt/docs/benchmarks.md @@ -2,7 +2,7 @@ As comparações independentes da TechEmpower mostram as aplicações **FastAPI** rodando com Uvicorn como um dos _frameworks_ Python mais rápidos disponíveis, somente atrás dos próprios Starlette e Uvicorn (utilizados internamente pelo FastAPI). (*) -Mas quando se checa _benchmarks_ e comparações você deveria ter o seguinte em mente. +Mas quando se checa _benchmarks_ e comparações você deveria ter o seguinte em mente. ## Comparações e velocidade diff --git a/docs/pt/docs/help-fastapi.md b/docs/pt/docs/help-fastapi.md index 086273a1d..d82ce3414 100644 --- a/docs/pt/docs/help-fastapi.md +++ b/docs/pt/docs/help-fastapi.md @@ -36,7 +36,7 @@ Você pode "acompanhar" (watch) o FastAPI no GitHub (clicando no botão com um " Podendo selecionar apenas "Novos Updates". -Fazendo isto, serão enviadas notificações (em seu email) sempre que tiver novos updates (uma nova versão) com correções de bugs e novos recursos no **FastAPI** +Fazendo isto, serão enviadas notificações (em seu email) sempre que tiver novos updates (uma nova versão) com correções de bugs e novos recursos no **FastAPI** ## Conect-se com o autor diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md index 97044dd90..c1a0dbf0d 100644 --- a/docs/pt/docs/index.md +++ b/docs/pt/docs/index.md @@ -365,7 +365,7 @@ Voltando ao código do exemplo anterior, **FastAPI** irá: * Como o parâmetro `q` é declarado com `= None`, ele é opcional. * Sem o `None` ele poderia ser obrigatório (como o corpo no caso de `PUT`). * Para requisições `PUT` para `/items/{item_id}`, lerá o corpo como JSON e: - * Verifica que tem um atributo obrigatório `name` que deve ser `str`. + * Verifica que tem um atributo obrigatório `name` que deve ser `str`. * Verifica que tem um atributo obrigatório `price` que deve ser `float`. * Verifica que tem an atributo opcional `is_offer`, que deve ser `bool`, se presente. * Tudo isso também funciona para objetos JSON profundamente aninhados. diff --git a/docs/pt/docs/python-types.md b/docs/pt/docs/python-types.md index df70afd40..9f12211c7 100644 --- a/docs/pt/docs/python-types.md +++ b/docs/pt/docs/python-types.md @@ -313,4 +313,3 @@ O importante é que, usando tipos padrão de Python, em um único local (em vez !!! info "Informação" Se você já passou por todo o tutorial e voltou para ver mais sobre os tipos, um bom recurso é a "cheat sheet" do `mypy` . - diff --git a/docs/pt/docs/tutorial/body.md b/docs/pt/docs/tutorial/body.md index 5891185f3..5abc91177 100644 --- a/docs/pt/docs/tutorial/body.md +++ b/docs/pt/docs/tutorial/body.md @@ -114,7 +114,7 @@ Mas você terá o mesmo suporte do editor no PyCharm como editor, você pode utilizar o Plugin do Pydantic para o PyCharm . Melhora o suporte do editor para seus modelos Pydantic com:: - + * completação automática * verificação de tipos * refatoração diff --git a/docs/ru/docs/async.md b/docs/ru/docs/async.md index fc5e44471..4c44fc22d 100644 --- a/docs/ru/docs/async.md +++ b/docs/ru/docs/async.md @@ -228,7 +228,7 @@ def results(): И то же самое с большинством веб-приложений. -Пользователей очень много, но ваш сервер всё равно вынужден ждать 🕙 запросы по их слабому интернет-соединению. +Пользователей очень много, но ваш сервер всё равно вынужден ждать 🕙 запросы по их слабому интернет-соединению. Потом снова ждать 🕙, пока вернётся ответ. @@ -379,7 +379,7 @@ async def read_burgers(): burgers = await get_burgers(2) return burgers ``` - + ### Технические подробности Как вы могли заметить, `await` может применяться только в функциях, объявленных с использованием `async def`. diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index c0a958c3d..a1d302276 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -321,7 +321,7 @@ And now, go to тип переменной. diff --git a/docs/sq/docs/index.md b/docs/sq/docs/index.md index a7af14781..0bb7b55e3 100644 --- a/docs/sq/docs/index.md +++ b/docs/sq/docs/index.md @@ -321,7 +321,7 @@ And now, go to OpenAPI buna path operasyonları parametreleri, body talebi, güvenlik gibi şeyler dahil olmak üzere deklare bunların deklare edilmesi. +* API oluşturma işlemlerinde OpenAPI buna path operasyonları parametreleri, body talebi, güvenlik gibi şeyler dahil olmak üzere deklare bunların deklare edilmesi. * Otomatik olarak data modelinin JSON Schema ile beraber dokümante edilmesi (OpenAPI'n kendisi zaten JSON Schema'ya dayanıyor). * Titiz bir çalışmanın sonucunda yukarıdaki standartlara uygun bir framework oluşturduk. Standartları pastanın üzerine sonradan eklenmiş bir çilek olarak görmedik. * Ayrıca bu bir çok dilde kullanılabilecek **client code generator** kullanımına da izin veriyor. @@ -74,7 +74,7 @@ my_second_user: User = User(**second_user_data) ### Editor desteği -Bütün framework kullanılması kolay ve sezgileri güçlü olması için tasarlandı, verilen bütün kararlar geliştiricilere en iyi geliştirme deneyimini yaşatmak üzere, bir çok editör üzerinde test edildi. +Bütün framework kullanılması kolay ve sezgileri güçlü olması için tasarlandı, verilen bütün kararlar geliştiricilere en iyi geliştirme deneyimini yaşatmak üzere, bir çok editör üzerinde test edildi. Son yapılan Python geliştiricileri anketinde, açık ara en çok kullanılan özellik "oto-tamamlama" idi.. @@ -135,7 +135,7 @@ Bütün güvenlik şemaları OpenAPI'da tanımlanmış durumda, kapsadıkları: Bütün güvenlik özellikleri Starlette'den geliyor (**session cookies'de** dahil olmak üzere). -Bütün hepsi tekrardan kullanılabilir aletler ve bileşenler olarak, kolayca sistemlerinize, data depolarınıza, ilişkisel ve NoSQL databaselerinize entegre edebileceğiniz şekilde yapıldı. +Bütün hepsi tekrardan kullanılabilir aletler ve bileşenler olarak, kolayca sistemlerinize, data depolarınıza, ilişkisel ve NoSQL databaselerinize entegre edebileceğiniz şekilde yapıldı. ### Dependency injection @@ -206,4 +206,3 @@ Aynı şekilde, databaseden gelen objeyi de **direkt olarak isteğe** de tamamiy * **Genişletilebilir**: * Pydantic özelleştirilmiş data tiplerinin tanımlanmasının yapılmasına izin veriyor ayrıca validator decoratorü ile senin doğrulamaları genişletip, kendi doğrulayıcılarını yazmana izin veriyor. * 100% test kapsayıcılığı. - diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md index 19f46fb4c..3195cd440 100644 --- a/docs/tr/docs/index.md +++ b/docs/tr/docs/index.md @@ -28,7 +28,7 @@ --- -FastAPI, Python 3.6+'nın standart type hintlerine dayanan modern ve hızlı (yüksek performanslı) API'lar oluşturmak için kullanılabilecek web framework'ü. +FastAPI, Python 3.6+'nın standart type hintlerine dayanan modern ve hızlı (yüksek performanslı) API'lar oluşturmak için kullanılabilecek web framework'ü. Ana özellikleri: @@ -315,7 +315,7 @@ Server otomatik olarak yeniden başlamalı (çünkü yukarıda `uvicorn`'u çal ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) -* Şimdi "Execute" butonuna tıkla, kullanıcı arayüzü otomatik olarak API'ın ile bağlantı kurarak ona bu parametreleri gönderecek ve sonucu karşına getirecek. +* Şimdi "Execute" butonuna tıkla, kullanıcı arayüzü otomatik olarak API'ın ile bağlantı kurarak ona bu parametreleri gönderecek ve sonucu karşına getirecek. ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) @@ -329,7 +329,7 @@ Server otomatik olarak yeniden başlamalı (çünkü yukarıda `uvicorn`'u çal ### Özet -Özetleyecek olursak, URL, sorgu veya request body'deki parametrelerini fonksiyon parametresi olarak kullanıyorsun. Bu parametrelerin veri tiplerini bir kere belirtmen yeterli. +Özetleyecek olursak, URL, sorgu veya request body'deki parametrelerini fonksiyon parametresi olarak kullanıyorsun. Bu parametrelerin veri tiplerini bir kere belirtmen yeterli. Type-hinting işlemini Python dilindeki standart veri tipleri ile yapabilirsin @@ -381,14 +381,14 @@ Az önceki kod örneğine geri dönelim, **FastAPI**'ın yapacaklarına bir bak * `item_id`'nin `GET` ve `PUT` talepleri içinde olup olmadığının doğruluğunu kontol edecek. * `item_id`'nin tipinin `int` olduğunu `GET` ve `PUT` talepleri içinde olup olmadığının doğruluğunu kontol edecek. - * Eğer `GET` ve `PUT` içinde yok ise ve `int` değil ise, sebebini belirten bir hata mesajı gösterecek + * Eğer `GET` ve `PUT` içinde yok ise ve `int` değil ise, sebebini belirten bir hata mesajı gösterecek * Opsiyonel bir `q` parametresinin `GET` talebi için (`http://127.0.0.1:8000/items/foo?q=somequery` içinde) olup olmadığını kontrol edecek * `q` parametresini `= None` ile oluşturduğumuz için, opsiyonel bir parametre olacak. * Eğer `None` olmasa zorunlu bir parametre olacak idi (bu yüzden body'de `PUT` parametresi var). * `PUT` talebi için `/items/{item_id}`'nin body'sini, JSON olarak okuyor: - * `name` adında bir parametetre olup olmadığını ve var ise onun `str` olup olmadığını kontol ediyor. - * `price` adında bir parametetre olup olmadığını ve var ise onun `float` olup olmadığını kontol ediyor. - * `is_offer` adında bir parametetre olup olmadığını ve var ise onun `bool` olup olmadığını kontol ediyor. + * `name` adında bir parametetre olup olmadığını ve var ise onun `str` olup olmadığını kontol ediyor. + * `price` adında bir parametetre olup olmadığını ve var ise onun `float` olup olmadığını kontol ediyor. + * `is_offer` adında bir parametetre olup olmadığını ve var ise onun `bool` olup olmadığını kontol ediyor. * Bunların hepsini en derin JSON modellerinde bile yapacaktır. * Bütün veri tiplerini otomatik olarak JSON'a çeviriyor veya tam tersi. * Her şeyi dokümanlayıp, çeşitli yerlerde: diff --git a/docs/tr/docs/python-types.md b/docs/tr/docs/python-types.md index 7e46bd031..3b9ab9050 100644 --- a/docs/tr/docs/python-types.md +++ b/docs/tr/docs/python-types.md @@ -29,7 +29,7 @@ Programın çıktısı: John Doe ``` -Fonksiyon sırayla şunları yapar: +Fonksiyon sırayla şunları yapar: * `first_name` ve `last_name` değerlerini alır. * `title()` ile değişkenlerin ilk karakterlerini büyütür. diff --git a/docs/uk/docs/index.md b/docs/uk/docs/index.md index a7af14781..0bb7b55e3 100644 --- a/docs/uk/docs/index.md +++ b/docs/uk/docs/index.md @@ -321,7 +321,7 @@ And now, go to -该命令生成了一个 `./htmlcov/` 目录,如果你在浏览器中打开 `./htmlcov/index.html` 文件,你可以交互式地浏览被测试所覆盖的代码区块,并注意是否缺少了任何区块。 +该命令生成了一个 `./htmlcov/` 目录,如果你在浏览器中打开 `./htmlcov/index.html` 文件,你可以交互式地浏览被测试所覆盖的代码区块,并注意是否缺少了任何区块。 diff --git a/docs/zh/docs/features.md b/docs/zh/docs/features.md index 2d5ba2982..fefe4b197 100644 --- a/docs/zh/docs/features.md +++ b/docs/zh/docs/features.md @@ -193,7 +193,7 @@ FastAPI 有一个使用非常简单,但是非常强大的`Enum`. diff --git a/docs_src/path_params/tutorial003b.py b/docs_src/path_params/tutorial003b.py new file mode 100644 index 000000000..822d37369 --- /dev/null +++ b/docs_src/path_params/tutorial003b.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/users") +async def read_users(): + return ["Rick", "Morty"] + + +@app.get("/users") +async def read_users2(): + return ["Bean", "Elfo"] From 16f1d073db0a8672f85769227f47b47c22d156e0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 12 May 2022 16:16:56 +0000 Subject: [PATCH 546/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b438112e2..2e596e03b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add documentation for redefined path operations. PR [#4864](https://github.com/tiangolo/fastapi/pull/4864) by [@madkinsz](https://github.com/madkinsz). * 🔥 Remove un-used old pending tests, already covered in other places. PR [#4891](https://github.com/tiangolo/fastapi/pull/4891) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add Python formatting hooks to pre-commit. PR [#4890](https://github.com/tiangolo/fastapi/pull/4890) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add pre-commit with first config and first formatting pass. PR [#4888](https://github.com/tiangolo/fastapi/pull/4888) by [@tiangolo](https://github.com/tiangolo). From 29df6b3e830ba3f8f1e57f85e26860445534db68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 May 2022 11:42:47 -0500 Subject: [PATCH 547/814] =?UTF-8?q?=F0=9F=91=B7=20Add=20pre-commit=20GitHu?= =?UTF-8?q?b=20Action=20workflow=20(#4895)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit --- .github/workflows/autoformat.yml | 43 ++++++++++++++++++++++++ docs/en/docs/img/sponsors/testdriven.svg | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/autoformat.yml diff --git a/.github/workflows/autoformat.yml b/.github/workflows/autoformat.yml new file mode 100644 index 000000000..2bd58008d --- /dev/null +++ b/.github/workflows/autoformat.yml @@ -0,0 +1,43 @@ +name: Auto Format + +on: + pull_request: + types: [opened, synchronize] + +jobs: + autoformat: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.10' + - uses: actions/cache@v2 + id: cache + with: + path: ${{ env.pythonLocation }} + key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-v01 + - name: Install Flit + if: steps.cache.outputs.cache-hit != 'true' + run: pip install flit + - name: Install Dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: flit install --symlink + - uses: actions/cache@v2 + id: pre-commit-hooks-cache + with: + path: ~/.cache/pre-commit + key: ${{ runner.os }}-pre-commit-hooks-${{ hashFiles('.pre-commit-config.yaml') }}-v01 + - name: Run pre-commit + run: pre-commit run --all-files + - name: Commit pre-commit changes + if: failure() + run: | + git config --global user.name "pre-commit" + git config --global user.email github-actions@github.com + git add --update + git commit -m "🎨 Format code with pre-commit" + git push diff --git a/docs/en/docs/img/sponsors/testdriven.svg b/docs/en/docs/img/sponsors/testdriven.svg index 97741b9e0..6ba2daa3b 100644 --- a/docs/en/docs/img/sponsors/testdriven.svg +++ b/docs/en/docs/img/sponsors/testdriven.svg @@ -1 +1 @@ - \ No newline at end of file + From bcabbf8b37db3fbc020560e94ad2f90e64d1510a Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 12 May 2022 16:43:22 +0000 Subject: [PATCH 548/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2e596e03b..681d7f183 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Add pre-commit GitHub Action workflow. PR [#4895](https://github.com/tiangolo/fastapi/pull/4895) by [@tiangolo](https://github.com/tiangolo). * 📝 Add documentation for redefined path operations. PR [#4864](https://github.com/tiangolo/fastapi/pull/4864) by [@madkinsz](https://github.com/madkinsz). * 🔥 Remove un-used old pending tests, already covered in other places. PR [#4891](https://github.com/tiangolo/fastapi/pull/4891) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add Python formatting hooks to pre-commit. PR [#4890](https://github.com/tiangolo/fastapi/pull/4890) by [@tiangolo](https://github.com/tiangolo). From f204e8010a190ac28149c969f496acfc548895ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 May 2022 12:15:13 -0500 Subject: [PATCH 549/814] =?UTF-8?q?=F0=9F=91=B7=20Add=20pre-commit=20CI=20?= =?UTF-8?q?instead=20of=20custom=20GitHub=20Action=20(#4896)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/autoformat.yml | 43 -------------------------------- .pre-commit-config.yaml | 3 +++ 2 files changed, 3 insertions(+), 43 deletions(-) delete mode 100644 .github/workflows/autoformat.yml diff --git a/.github/workflows/autoformat.yml b/.github/workflows/autoformat.yml deleted file mode 100644 index 2bd58008d..000000000 --- a/.github/workflows/autoformat.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Auto Format - -on: - pull_request: - types: [opened, synchronize] - -jobs: - autoformat: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.10' - - uses: actions/cache@v2 - id: cache - with: - path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-v01 - - name: Install Flit - if: steps.cache.outputs.cache-hit != 'true' - run: pip install flit - - name: Install Dependencies - if: steps.cache.outputs.cache-hit != 'true' - run: flit install --symlink - - uses: actions/cache@v2 - id: pre-commit-hooks-cache - with: - path: ~/.cache/pre-commit - key: ${{ runner.os }}-pre-commit-hooks-${{ hashFiles('.pre-commit-config.yaml') }}-v01 - - name: Run pre-commit - run: pre-commit run --all-files - - name: Commit pre-commit changes - if: failure() - run: | - git config --global user.name "pre-commit" - git config --global user.email github-actions@github.com - git add --update - git commit -m "🎨 Format code with pre-commit" - git push diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f6a0b251c..5c278571e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -46,3 +46,6 @@ repos: rev: 22.3.0 hooks: - id: black +ci: + autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks + autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate From d75c69e01f010642b45b723177dd7c5ebf973f46 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 12 May 2022 17:15:56 +0000 Subject: [PATCH 550/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 681d7f183..5efa5b818 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Add pre-commit CI instead of custom GitHub Action. PR [#4896](https://github.com/tiangolo/fastapi/pull/4896) by [@tiangolo](https://github.com/tiangolo). * 👷 Add pre-commit GitHub Action workflow. PR [#4895](https://github.com/tiangolo/fastapi/pull/4895) by [@tiangolo](https://github.com/tiangolo). * 📝 Add documentation for redefined path operations. PR [#4864](https://github.com/tiangolo/fastapi/pull/4864) by [@madkinsz](https://github.com/madkinsz). * 🔥 Remove un-used old pending tests, already covered in other places. PR [#4891](https://github.com/tiangolo/fastapi/pull/4891) by [@tiangolo](https://github.com/tiangolo). From f31ad41dda3e01c9f65b5454c17fc30918d2079b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 May 2022 13:10:57 -0500 Subject: [PATCH 551/814] =?UTF-8?q?=F0=9F=91=B7=20Fix=20installing=20Mater?= =?UTF-8?q?ial=20for=20MkDocs=20Insiders=20in=20CI=20(#4897)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-docs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index bdef6ea8a..505d66f9f 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -22,7 +22,7 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-docs-v2 + key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-v03 - name: Install Flit if: steps.cache.outputs.cache-hit != 'true' run: python3.7 -m pip install flit @@ -30,7 +30,7 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' run: python3.7 -m flit install --deps production --extras doc - name: Install Material for MkDocs Insiders - if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false && steps.cache.outputs.cache-hit != 'true' + if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true' run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git - name: Build Docs run: python3.7 ./scripts/docs.py build-all From 497e5a2422f672daec7e8f4b4ee42b6e8bfd2df0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 12 May 2022 18:11:39 +0000 Subject: [PATCH 552/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5efa5b818..71c0be532 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Fix installing Material for MkDocs Insiders in CI. PR [#4897](https://github.com/tiangolo/fastapi/pull/4897) by [@tiangolo](https://github.com/tiangolo). * 👷 Add pre-commit CI instead of custom GitHub Action. PR [#4896](https://github.com/tiangolo/fastapi/pull/4896) by [@tiangolo](https://github.com/tiangolo). * 👷 Add pre-commit GitHub Action workflow. PR [#4895](https://github.com/tiangolo/fastapi/pull/4895) by [@tiangolo](https://github.com/tiangolo). * 📝 Add documentation for redefined path operations. PR [#4864](https://github.com/tiangolo/fastapi/pull/4864) by [@madkinsz](https://github.com/madkinsz). From 82775f7cd01f93ca10ed7dcf0081d5c746e62068 Mon Sep 17 00:00:00 2001 From: Shahriyar Rzayev Date: Fri, 13 May 2022 00:38:30 +0400 Subject: [PATCH 553/814] =?UTF-8?q?=E2=99=BB=20Refactor=20dict=20value=20e?= =?UTF-8?q?xtraction=20to=20minimize=20key=20lookups=20`fastapi/utils.py`?= =?UTF-8?q?=20(#3139)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fastapi/utils.py b/fastapi/utils.py index b9301499a..9d720feb3 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -147,15 +147,15 @@ def generate_unique_id(route: "APIRoute") -> str: def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) -> None: - for key in update_dict: + for key, value in update_dict.items(): if ( key in main_dict and isinstance(main_dict[key], dict) - and isinstance(update_dict[key], dict) + and isinstance(value, dict) ): - deep_dict_update(main_dict[key], update_dict[key]) + deep_dict_update(main_dict[key], value) else: - main_dict[key] = update_dict[key] + main_dict[key] = value def get_value_or_default( From 975d859ac49e72b7346c52e3660f08de55c20e60 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 12 May 2022 20:39:14 +0000 Subject: [PATCH 554/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 71c0be532..4ad301c6a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻ Refactor dict value extraction to minimize key lookups `fastapi/utils.py`. PR [#3139](https://github.com/tiangolo/fastapi/pull/3139) by [@ShahriyarR](https://github.com/ShahriyarR). * 👷 Fix installing Material for MkDocs Insiders in CI. PR [#4897](https://github.com/tiangolo/fastapi/pull/4897) by [@tiangolo](https://github.com/tiangolo). * 👷 Add pre-commit CI instead of custom GitHub Action. PR [#4896](https://github.com/tiangolo/fastapi/pull/4896) by [@tiangolo](https://github.com/tiangolo). * 👷 Add pre-commit GitHub Action workflow. PR [#4895](https://github.com/tiangolo/fastapi/pull/4895) by [@tiangolo](https://github.com/tiangolo). From 8b66b9ca3ef8b1cdb0ca2089781a04fe0e021c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 May 2022 15:47:31 -0500 Subject: [PATCH 555/814] =?UTF-8?q?=F0=9F=8E=A8=20Fix=20default=20value=20?= =?UTF-8?q?as=20set=20in=20tutorial=20for=20Path=20Operations=20Advanced?= =?UTF-8?q?=20Configurations=20(#4899)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs_src/path_operation_advanced_configuration/tutorial004.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs_src/path_operation_advanced_configuration/tutorial004.py b/docs_src/path_operation_advanced_configuration/tutorial004.py index fa867e794..da678aed3 100644 --- a/docs_src/path_operation_advanced_configuration/tutorial004.py +++ b/docs_src/path_operation_advanced_configuration/tutorial004.py @@ -11,7 +11,7 @@ class Item(BaseModel): description: Optional[str] = None price: float tax: Optional[float] = None - tags: Set[str] = [] + tags: Set[str] = set() @app.post("/items/", response_model=Item, summary="Create an item") From 31690dda2c1e8557fe96bc30b7d8a170ff4a90a5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 12 May 2022 20:48:12 +0000 Subject: [PATCH 556/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4ad301c6a..5c73818fe 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🎨 Fix default value as set in tutorial for Path Operations Advanced Configurations. PR [#4899](https://github.com/tiangolo/fastapi/pull/4899) by [@tiangolo](https://github.com/tiangolo). * ♻ Refactor dict value extraction to minimize key lookups `fastapi/utils.py`. PR [#3139](https://github.com/tiangolo/fastapi/pull/3139) by [@ShahriyarR](https://github.com/ShahriyarR). * 👷 Fix installing Material for MkDocs Insiders in CI. PR [#4897](https://github.com/tiangolo/fastapi/pull/4897) by [@tiangolo](https://github.com/tiangolo). * 👷 Add pre-commit CI instead of custom GitHub Action. PR [#4896](https://github.com/tiangolo/fastapi/pull/4896) by [@tiangolo](https://github.com/tiangolo). From 9262fa836283a3fcd05ba7f7fb6f3aa14b377f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 13 May 2022 18:38:22 -0500 Subject: [PATCH 557/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20not?= =?UTF-8?q?=20needing=20`...`=20as=20default=20value=20in=20required=20Que?= =?UTF-8?q?ry(),=20Path(),=20Header(),=20etc.=20(#4906)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Do not require default value in Query(), Path(), Header(), etc * 📝 Update source examples for docs with default and required values * ✅ Update tests with new default values and not required Ellipsis * 📝 Update docs for Query params and update info about default value, required, Ellipsis --- .../tutorial/query-params-str-validations.md | 78 ++++++++++++++----- .../additional_status_codes/tutorial001.py | 6 +- docs_src/app_testing/app_b/main.py | 8 +- docs_src/app_testing/app_b_py310/main.py | 4 +- .../bigger_applications/app/dependencies.py | 2 +- docs_src/body_fields/tutorial001.py | 12 +-- docs_src/body_fields/tutorial001_py310.py | 6 +- docs_src/body_multiple_params/tutorial001.py | 12 +-- .../body_multiple_params/tutorial001_py310.py | 2 +- docs_src/body_multiple_params/tutorial003.py | 12 ++- .../body_multiple_params/tutorial003_py310.py | 4 +- docs_src/body_multiple_params/tutorial004.py | 12 +-- .../body_multiple_params/tutorial004_py310.py | 2 +- docs_src/body_multiple_params/tutorial005.py | 8 +- .../body_multiple_params/tutorial005_py310.py | 2 +- docs_src/cookie_params/tutorial001.py | 4 +- docs_src/cookie_params/tutorial001_py310.py | 2 +- .../custom_request_and_route/tutorial001.py | 2 +- .../custom_request_and_route/tutorial002.py | 2 +- docs_src/dependencies/tutorial005.py | 2 +- docs_src/dependencies/tutorial005_py310.py | 2 +- docs_src/dependencies/tutorial006.py | 4 +- docs_src/dependencies/tutorial012.py | 4 +- docs_src/extra_data_types/tutorial001.py | 8 +- .../extra_data_types/tutorial001_py310.py | 8 +- docs_src/header_params/tutorial001.py | 2 +- docs_src/header_params/tutorial001_py310.py | 2 +- docs_src/header_params/tutorial002.py | 2 +- docs_src/header_params/tutorial002_py310.py | 2 +- docs_src/header_params/tutorial003.py | 2 +- docs_src/header_params/tutorial003_py310.py | 2 +- docs_src/header_params/tutorial003_py39.py | 2 +- .../tutorial001.py | 6 +- .../tutorial001_py310.py | 4 +- .../tutorial002.py | 4 +- .../tutorial003.py | 4 +- .../tutorial004.py | 2 +- .../tutorial005.py | 2 +- .../tutorial006.py | 4 +- .../tutorial002.py | 4 +- .../tutorial002_py310.py | 2 +- .../tutorial003.py | 6 +- .../tutorial003_py310.py | 2 +- .../tutorial004.py | 6 +- .../tutorial004_py310.py | 3 +- .../tutorial005.py | 2 +- .../tutorial006.py | 2 +- .../tutorial006b.py | 11 +++ .../tutorial006c.py | 13 ++++ .../tutorial006c_py310.py | 11 +++ .../tutorial006d.py | 12 +++ .../tutorial007.py | 4 +- .../tutorial007_py310.py | 4 +- .../tutorial008.py | 6 +- .../tutorial008_py310.py | 2 +- .../tutorial009.py | 4 +- .../tutorial009_py310.py | 2 +- .../tutorial010.py | 6 +- .../tutorial010_py310.py | 2 +- .../tutorial011.py | 4 +- .../tutorial011_py310.py | 2 +- .../tutorial011_py39.py | 4 +- .../tutorial012.py | 2 +- .../tutorial012_py39.py | 2 +- .../tutorial013.py | 2 +- .../tutorial014.py | 4 +- .../tutorial014_py310.py | 4 +- docs_src/request_files/tutorial001.py | 2 +- docs_src/request_files/tutorial001_02.py | 2 +- .../request_files/tutorial001_02_py310.py | 2 +- docs_src/request_files/tutorial001_03.py | 4 +- docs_src/request_files/tutorial002.py | 2 +- docs_src/request_files/tutorial002_py39.py | 2 +- docs_src/request_files/tutorial003.py | 4 +- docs_src/request_files/tutorial003_py39.py | 4 +- docs_src/request_forms/tutorial001.py | 2 +- .../request_forms_and_files/tutorial001.py | 2 +- docs_src/schema_extra_example/tutorial002.py | 8 +- .../schema_extra_example/tutorial002_py310.py | 8 +- docs_src/schema_extra_example/tutorial003.py | 1 - .../schema_extra_example/tutorial003_py310.py | 1 - docs_src/schema_extra_example/tutorial004.py | 1 - .../schema_extra_example/tutorial004_py310.py | 1 - docs_src/websockets/tutorial002.py | 4 +- fastapi/dependencies/utils.py | 17 ++-- fastapi/openapi/models.py | 30 +++---- fastapi/param_functions.py | 26 +++---- fastapi/params.py | 28 +++---- fastapi/security/oauth2.py | 24 +++--- fastapi/utils.py | 2 +- tests/main.py | 44 +++++------ tests/test_dependency_normal_exceptions.py | 4 +- tests/test_forms_from_non_typing_sequences.py | 6 +- tests/test_invalid_sequence_param.py | 8 +- tests/test_jsonable_encoder.py | 2 +- tests/test_modules_same_name_body/app/a.py | 2 +- tests/test_modules_same_name_body/app/b.py | 2 +- tests/test_multi_query_errors.py | 2 +- tests/test_multipart_installation.py | 20 ++--- tests/test_param_class.py | 2 +- tests/test_param_include_in_schema.py | 8 +- tests/test_repeated_dependency_schema.py | 2 +- ...test_request_body_parameters_media_type.py | 6 +- tests/test_schema_extra_examples.py | 47 ++++++----- tests/test_serialize_response_model.py | 2 +- tests/test_starlette_urlconvertors.py | 6 +- tests/test_tuples.py | 2 +- 107 files changed, 404 insertions(+), 314 deletions(-) create mode 100644 docs_src/query_params_str_validations/tutorial006b.py create mode 100644 docs_src/query_params_str_validations/tutorial006c.py create mode 100644 docs_src/query_params_str_validations/tutorial006c_py310.py create mode 100644 docs_src/query_params_str_validations/tutorial006d.py diff --git a/docs/en/docs/tutorial/query-params-str-validations.md b/docs/en/docs/tutorial/query-params-str-validations.md index ee62b9718..c5fc35b88 100644 --- a/docs/en/docs/tutorial/query-params-str-validations.md +++ b/docs/en/docs/tutorial/query-params-str-validations.md @@ -16,12 +16,12 @@ Let's take this application as example: {!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!} ``` -The query parameter `q` is of type `Optional[str]` (or `str | None` in Python 3.10), that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required. +The query parameter `q` is of type `Union[str, None]` (or `str | None` in Python 3.10), that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required. !!! note FastAPI will know that the value of `q` is not required because of the default value `= None`. - The `Optional` in `Optional[str]` is not used by FastAPI, but will allow your editor to give you better support and detect errors. + The `Union` in `Union[str, None]` will allow your editor to give you better support and detect errors. ## Additional validation @@ -59,24 +59,24 @@ And now use it as the default value of your parameter, setting the parameter `ma {!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!} ``` -As we have to replace the default value `None` with `Query(None)`, the first parameter to `Query` serves the same purpose of defining that default value. +As we have to replace the default value `None` in the function with `Query()`, we can now set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value. So: ```Python -q: Optional[str] = Query(None) +q: Union[str, None] = Query(default=None) ``` ...makes the parameter optional, the same as: ```Python -q: Optional[str] = None +q: Union[str, None] = None ``` And in Python 3.10 and above: ```Python -q: str | None = Query(None) +q: str | None = Query(default=None) ``` ...makes the parameter optional, the same as: @@ -97,17 +97,17 @@ But it declares it explicitly as being a query parameter. or the: ```Python - = Query(None) + = Query(default=None) ``` as it will use that `None` as the default value, and that way make the parameter **not required**. - The `Optional` part allows your editor to provide better support, but it is not what tells FastAPI that this parameter is not required. + The `Union[str, None]` part allows your editor to provide better support, but it is not what tells FastAPI that this parameter is not required. Then, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings: ```Python -q: str = Query(None, max_length=50) +q: Union[str, None] = Query(default=None, max_length=50) ``` This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema *path operation*. @@ -118,7 +118,7 @@ You can also add a parameter `min_length`: === "Python 3.6 and above" - ```Python hl_lines="9" + ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial003.py!} ``` @@ -134,13 +134,13 @@ You can define a ../../../docs_src/query_params_str_validations/tutorial004.py!} ``` === "Python 3.10 and above" - ```Python hl_lines="8" + ```Python hl_lines="9" {!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!} ``` @@ -156,7 +156,7 @@ But whenever you need them and go and learn them, know that you can already use ## Default values -The same way that you can pass `None` as the first argument to be used as the default value, you can pass other values. +The same way that you can pass `None` as the value for the `default` parameter, you can pass other values. Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`: @@ -178,26 +178,68 @@ q: str instead of: ```Python -q: Optional[str] = None +q: Union[str, None] = None ``` But we are now declaring it with `Query`, for example like: ```Python -q: Optional[str] = Query(None, min_length=3) +q: Union[str, None] = Query(default=None, min_length=3) ``` -So, when you need to declare a value as required while using `Query`, you can use `...` as the first argument: +So, when you need to declare a value as required while using `Query`, you can simply not declare a default value: ```Python hl_lines="7" {!../../../docs_src/query_params_str_validations/tutorial006.py!} ``` +### Required with Ellipsis (`...`) + +There's an alternative way to explicitly declare that a value is required. You can set the `default` parameter to the literal value `...`: + +```Python hl_lines="7" +{!../../../docs_src/query_params_str_validations/tutorial006b.py!} +``` + !!! info If you hadn't seen that `...` before: it is a special single value, it is part of Python and is called "Ellipsis". + It is used by Pydantic and FastAPI to explicitly declare that a value is required. + This will let **FastAPI** know that this parameter is required. +### Required with `None` + +You can declare that a parameter can accept `None`, but that it's still required. This would force clients to send a value, even if the value is `None`. + +To do that, you can declare that `None` is a valid type but still use `default=...`: + +=== "Python 3.6 and above" + + ```Python hl_lines="8" + {!> ../../../docs_src/query_params_str_validations/tutorial006c.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!} + ``` + +!!! tip + Pydantic, which is what powers all the data validation and serialization in FastAPI, has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about Required Optional fields. + +### Use Pydantic's `Required` instead of Ellipsis (`...`) + +If you feel uncomfortable using `...`, you can also import and use `Required` from Pydantic: + +```Python hl_lines="2 8" +{!../../../docs_src/query_params_str_validations/tutorial006d.py!} +``` + +!!! tip + Remember that in most of the cases, when something is required, you can simply omit the `default` parameter, so you normally don't have to use `...` nor `Required`. + ## Query parameter list / multiple values When you define a query parameter explicitly with `Query` you can also declare it to receive a list of values, or said in other way, to receive multiple values. @@ -315,7 +357,7 @@ You can add a `title`: === "Python 3.10 and above" - ```Python hl_lines="7" + ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!} ``` @@ -399,7 +441,7 @@ To exclude a query parameter from the generated OpenAPI schema (and thus, from t === "Python 3.10 and above" - ```Python hl_lines="7" + ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!} ``` diff --git a/docs_src/additional_status_codes/tutorial001.py b/docs_src/additional_status_codes/tutorial001.py index ae101e0a0..74a986a6a 100644 --- a/docs_src/additional_status_codes/tutorial001.py +++ b/docs_src/additional_status_codes/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Body, FastAPI, status from fastapi.responses import JSONResponse @@ -10,7 +10,9 @@ items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "siz @app.put("/items/{item_id}") async def upsert_item( - item_id: str, name: Optional[str] = Body(None), size: Optional[int] = Body(None) + item_id: str, + name: Union[str, None] = Body(default=None), + size: Union[int, None] = Body(default=None), ): if item_id in items: item = items[item_id] diff --git a/docs_src/app_testing/app_b/main.py b/docs_src/app_testing/app_b/main.py index df43db806..11558b8e8 100644 --- a/docs_src/app_testing/app_b/main.py +++ b/docs_src/app_testing/app_b/main.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Header, HTTPException from pydantic import BaseModel @@ -16,11 +16,11 @@ app = FastAPI() class Item(BaseModel): id: str title: str - description: Optional[str] = None + description: Union[str, None] = None @app.get("/items/{item_id}", response_model=Item) -async def read_main(item_id: str, x_token: str = Header(...)): +async def read_main(item_id: str, x_token: str = Header()): if x_token != fake_secret_token: raise HTTPException(status_code=400, detail="Invalid X-Token header") if item_id not in fake_db: @@ -29,7 +29,7 @@ async def read_main(item_id: str, x_token: str = Header(...)): @app.post("/items/", response_model=Item) -async def create_item(item: Item, x_token: str = Header(...)): +async def create_item(item: Item, x_token: str = Header()): if x_token != fake_secret_token: raise HTTPException(status_code=400, detail="Invalid X-Token header") if item.id in fake_db: diff --git a/docs_src/app_testing/app_b_py310/main.py b/docs_src/app_testing/app_b_py310/main.py index d44ab9e7c..b4c72de5c 100644 --- a/docs_src/app_testing/app_b_py310/main.py +++ b/docs_src/app_testing/app_b_py310/main.py @@ -18,7 +18,7 @@ class Item(BaseModel): @app.get("/items/{item_id}", response_model=Item) -async def read_main(item_id: str, x_token: str = Header(...)): +async def read_main(item_id: str, x_token: str = Header()): if x_token != fake_secret_token: raise HTTPException(status_code=400, detail="Invalid X-Token header") if item_id not in fake_db: @@ -27,7 +27,7 @@ async def read_main(item_id: str, x_token: str = Header(...)): @app.post("/items/", response_model=Item) -async def create_item(item: Item, x_token: str = Header(...)): +async def create_item(item: Item, x_token: str = Header()): if x_token != fake_secret_token: raise HTTPException(status_code=400, detail="Invalid X-Token header") if item.id in fake_db: diff --git a/docs_src/bigger_applications/app/dependencies.py b/docs_src/bigger_applications/app/dependencies.py index 267b0d3a8..8e45f004b 100644 --- a/docs_src/bigger_applications/app/dependencies.py +++ b/docs_src/bigger_applications/app/dependencies.py @@ -1,7 +1,7 @@ from fastapi import Header, HTTPException -async def get_token_header(x_token: str = Header(...)): +async def get_token_header(x_token: str = Header()): if x_token != "fake-super-secret-token": raise HTTPException(status_code=400, detail="X-Token header invalid") diff --git a/docs_src/body_fields/tutorial001.py b/docs_src/body_fields/tutorial001.py index dabc48a0f..cbeebd614 100644 --- a/docs_src/body_fields/tutorial001.py +++ b/docs_src/body_fields/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Body, FastAPI from pydantic import BaseModel, Field @@ -8,14 +8,14 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = Field( - None, title="The description of the item", max_length=300 + description: Union[str, None] = Field( + default=None, title="The description of the item", max_length=300 ) - price: float = Field(..., gt=0, description="The price must be greater than zero") - tax: Optional[float] = None + price: float = Field(gt=0, description="The price must be greater than zero") + tax: Union[float, None] = None @app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item = Body(..., embed=True)): +async def update_item(item_id: int, item: Item = Body(embed=True)): results = {"item_id": item_id, "item": item} return results diff --git a/docs_src/body_fields/tutorial001_py310.py b/docs_src/body_fields/tutorial001_py310.py index 01e02a050..4437327f3 100644 --- a/docs_src/body_fields/tutorial001_py310.py +++ b/docs_src/body_fields/tutorial001_py310.py @@ -7,13 +7,13 @@ app = FastAPI() class Item(BaseModel): name: str description: str | None = Field( - None, title="The description of the item", max_length=300 + default=None, title="The description of the item", max_length=300 ) - price: float = Field(..., gt=0, description="The price must be greater than zero") + price: float = Field(gt=0, description="The price must be greater than zero") tax: float | None = None @app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item = Body(..., embed=True)): +async def update_item(item_id: int, item: Item = Body(embed=True)): results = {"item_id": item_id, "item": item} return results diff --git a/docs_src/body_multiple_params/tutorial001.py b/docs_src/body_multiple_params/tutorial001.py index 7ce0ae6f2..a73975b3a 100644 --- a/docs_src/body_multiple_params/tutorial001.py +++ b/docs_src/body_multiple_params/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Path from pydantic import BaseModel @@ -8,17 +8,17 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None @app.put("/items/{item_id}") async def update_item( *, - item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000), - q: Optional[str] = None, - item: Optional[Item] = None, + item_id: int = Path(title="The ID of the item to get", ge=0, le=1000), + q: Union[str, None] = None, + item: Union[Item, None] = None, ): results = {"item_id": item_id} if q: diff --git a/docs_src/body_multiple_params/tutorial001_py310.py b/docs_src/body_multiple_params/tutorial001_py310.py index b08d397b3..be0eba2ae 100644 --- a/docs_src/body_multiple_params/tutorial001_py310.py +++ b/docs_src/body_multiple_params/tutorial001_py310.py @@ -14,7 +14,7 @@ class Item(BaseModel): @app.put("/items/{item_id}") async def update_item( *, - item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000), + item_id: int = Path(title="The ID of the item to get", ge=0, le=1000), q: str | None = None, item: Item | None = None, ): diff --git a/docs_src/body_multiple_params/tutorial003.py b/docs_src/body_multiple_params/tutorial003.py index 7e9e24374..cf344e6c5 100644 --- a/docs_src/body_multiple_params/tutorial003.py +++ b/docs_src/body_multiple_params/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Body, FastAPI from pydantic import BaseModel @@ -8,19 +8,17 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None class User(BaseModel): username: str - full_name: Optional[str] = None + full_name: Union[str, None] = None @app.put("/items/{item_id}") -async def update_item( - item_id: int, item: Item, user: User, importance: int = Body(...) -): +async def update_item(item_id: int, item: Item, user: User, importance: int = Body()): results = {"item_id": item_id, "item": item, "user": user, "importance": importance} return results diff --git a/docs_src/body_multiple_params/tutorial003_py310.py b/docs_src/body_multiple_params/tutorial003_py310.py index 9ddbda3f7..a1a75fe8e 100644 --- a/docs_src/body_multiple_params/tutorial003_py310.py +++ b/docs_src/body_multiple_params/tutorial003_py310.py @@ -17,8 +17,6 @@ class User(BaseModel): @app.put("/items/{item_id}") -async def update_item( - item_id: int, item: Item, user: User, importance: int = Body(...) -): +async def update_item(item_id: int, item: Item, user: User, importance: int = Body()): results = {"item_id": item_id, "item": item, "user": user, "importance": importance} return results diff --git a/docs_src/body_multiple_params/tutorial004.py b/docs_src/body_multiple_params/tutorial004.py index 8dc0d374d..beea7d1e3 100644 --- a/docs_src/body_multiple_params/tutorial004.py +++ b/docs_src/body_multiple_params/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Body, FastAPI from pydantic import BaseModel @@ -8,14 +8,14 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None class User(BaseModel): username: str - full_name: Optional[str] = None + full_name: Union[str, None] = None @app.put("/items/{item_id}") @@ -24,8 +24,8 @@ async def update_item( item_id: int, item: Item, user: User, - importance: int = Body(..., gt=0), - q: Optional[str] = None + importance: int = Body(gt=0), + q: Union[str, None] = None ): results = {"item_id": item_id, "item": item, "user": user, "importance": importance} if q: diff --git a/docs_src/body_multiple_params/tutorial004_py310.py b/docs_src/body_multiple_params/tutorial004_py310.py index 77321300e..6d495d408 100644 --- a/docs_src/body_multiple_params/tutorial004_py310.py +++ b/docs_src/body_multiple_params/tutorial004_py310.py @@ -22,7 +22,7 @@ async def update_item( item_id: int, item: Item, user: User, - importance: int = Body(..., gt=0), + importance: int = Body(gt=0), q: str | None = None ): results = {"item_id": item_id, "item": item, "user": user, "importance": importance} diff --git a/docs_src/body_multiple_params/tutorial005.py b/docs_src/body_multiple_params/tutorial005.py index 4657b4144..29e6e14b7 100644 --- a/docs_src/body_multiple_params/tutorial005.py +++ b/docs_src/body_multiple_params/tutorial005.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Body, FastAPI from pydantic import BaseModel @@ -8,12 +8,12 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None @app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item = Body(..., embed=True)): +async def update_item(item_id: int, item: Item = Body(embed=True)): results = {"item_id": item_id, "item": item} return results diff --git a/docs_src/body_multiple_params/tutorial005_py310.py b/docs_src/body_multiple_params/tutorial005_py310.py index 97b213b16..06744507b 100644 --- a/docs_src/body_multiple_params/tutorial005_py310.py +++ b/docs_src/body_multiple_params/tutorial005_py310.py @@ -12,6 +12,6 @@ class Item(BaseModel): @app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item = Body(..., embed=True)): +async def update_item(item_id: int, item: Item = Body(embed=True)): results = {"item_id": item_id, "item": item} return results diff --git a/docs_src/cookie_params/tutorial001.py b/docs_src/cookie_params/tutorial001.py index 67d03b133..c4a497fda 100644 --- a/docs_src/cookie_params/tutorial001.py +++ b/docs_src/cookie_params/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Cookie, FastAPI @@ -6,5 +6,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(ads_id: Optional[str] = Cookie(None)): +async def read_items(ads_id: Union[str, None] = Cookie(default=None)): return {"ads_id": ads_id} diff --git a/docs_src/cookie_params/tutorial001_py310.py b/docs_src/cookie_params/tutorial001_py310.py index d0b004631..6c9d5f9a1 100644 --- a/docs_src/cookie_params/tutorial001_py310.py +++ b/docs_src/cookie_params/tutorial001_py310.py @@ -4,5 +4,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(ads_id: str | None = Cookie(None)): +async def read_items(ads_id: str | None = Cookie(default=None)): return {"ads_id": ads_id} diff --git a/docs_src/custom_request_and_route/tutorial001.py b/docs_src/custom_request_and_route/tutorial001.py index 2e64ad45d..268ce9019 100644 --- a/docs_src/custom_request_and_route/tutorial001.py +++ b/docs_src/custom_request_and_route/tutorial001.py @@ -31,5 +31,5 @@ app.router.route_class = GzipRoute @app.post("/sum") -async def sum_numbers(numbers: List[int] = Body(...)): +async def sum_numbers(numbers: List[int] = Body()): return {"sum": sum(numbers)} diff --git a/docs_src/custom_request_and_route/tutorial002.py b/docs_src/custom_request_and_route/tutorial002.py index f4c093ac9..cee4a95f0 100644 --- a/docs_src/custom_request_and_route/tutorial002.py +++ b/docs_src/custom_request_and_route/tutorial002.py @@ -25,5 +25,5 @@ app.router.route_class = ValidationErrorLoggingRoute @app.post("/") -async def sum_numbers(numbers: List[int] = Body(...)): +async def sum_numbers(numbers: List[int] = Body()): return sum(numbers) diff --git a/docs_src/dependencies/tutorial005.py b/docs_src/dependencies/tutorial005.py index c8923d143..24f73c617 100644 --- a/docs_src/dependencies/tutorial005.py +++ b/docs_src/dependencies/tutorial005.py @@ -10,7 +10,7 @@ def query_extractor(q: Optional[str] = None): def query_or_cookie_extractor( - q: str = Depends(query_extractor), last_query: Optional[str] = Cookie(None) + q: str = Depends(query_extractor), last_query: Optional[str] = Cookie(default=None) ): if not q: return last_query diff --git a/docs_src/dependencies/tutorial005_py310.py b/docs_src/dependencies/tutorial005_py310.py index 5e1d7e0ef..247cdabe2 100644 --- a/docs_src/dependencies/tutorial005_py310.py +++ b/docs_src/dependencies/tutorial005_py310.py @@ -8,7 +8,7 @@ def query_extractor(q: str | None = None): def query_or_cookie_extractor( - q: str = Depends(query_extractor), last_query: str | None = Cookie(None) + q: str = Depends(query_extractor), last_query: str | None = Cookie(default=None) ): if not q: return last_query diff --git a/docs_src/dependencies/tutorial006.py b/docs_src/dependencies/tutorial006.py index a71d7cce6..9aff4154f 100644 --- a/docs_src/dependencies/tutorial006.py +++ b/docs_src/dependencies/tutorial006.py @@ -3,12 +3,12 @@ from fastapi import Depends, FastAPI, Header, HTTPException app = FastAPI() -async def verify_token(x_token: str = Header(...)): +async def verify_token(x_token: str = Header()): if x_token != "fake-super-secret-token": raise HTTPException(status_code=400, detail="X-Token header invalid") -async def verify_key(x_key: str = Header(...)): +async def verify_key(x_key: str = Header()): if x_key != "fake-super-secret-key": raise HTTPException(status_code=400, detail="X-Key header invalid") return x_key diff --git a/docs_src/dependencies/tutorial012.py b/docs_src/dependencies/tutorial012.py index 8f8868a55..36ce6c711 100644 --- a/docs_src/dependencies/tutorial012.py +++ b/docs_src/dependencies/tutorial012.py @@ -1,12 +1,12 @@ from fastapi import Depends, FastAPI, Header, HTTPException -async def verify_token(x_token: str = Header(...)): +async def verify_token(x_token: str = Header()): if x_token != "fake-super-secret-token": raise HTTPException(status_code=400, detail="X-Token header invalid") -async def verify_key(x_key: str = Header(...)): +async def verify_key(x_key: str = Header()): if x_key != "fake-super-secret-key": raise HTTPException(status_code=400, detail="X-Key header invalid") return x_key diff --git a/docs_src/extra_data_types/tutorial001.py b/docs_src/extra_data_types/tutorial001.py index e8d7e1ea3..9f5e911bf 100644 --- a/docs_src/extra_data_types/tutorial001.py +++ b/docs_src/extra_data_types/tutorial001.py @@ -10,10 +10,10 @@ app = FastAPI() @app.put("/items/{item_id}") async def read_items( item_id: UUID, - start_datetime: Optional[datetime] = Body(None), - end_datetime: Optional[datetime] = Body(None), - repeat_at: Optional[time] = Body(None), - process_after: Optional[timedelta] = Body(None), + start_datetime: Optional[datetime] = Body(default=None), + end_datetime: Optional[datetime] = Body(default=None), + repeat_at: Optional[time] = Body(default=None), + process_after: Optional[timedelta] = Body(default=None), ): start_process = start_datetime + process_after duration = end_datetime - start_process diff --git a/docs_src/extra_data_types/tutorial001_py310.py b/docs_src/extra_data_types/tutorial001_py310.py index 4a33481b7..d22f81888 100644 --- a/docs_src/extra_data_types/tutorial001_py310.py +++ b/docs_src/extra_data_types/tutorial001_py310.py @@ -9,10 +9,10 @@ app = FastAPI() @app.put("/items/{item_id}") async def read_items( item_id: UUID, - start_datetime: datetime | None = Body(None), - end_datetime: datetime | None = Body(None), - repeat_at: time | None = Body(None), - process_after: timedelta | None = Body(None), + start_datetime: datetime | None = Body(default=None), + end_datetime: datetime | None = Body(default=None), + repeat_at: time | None = Body(default=None), + process_after: timedelta | None = Body(default=None), ): start_process = start_datetime + process_after duration = end_datetime - start_process diff --git a/docs_src/header_params/tutorial001.py b/docs_src/header_params/tutorial001.py index 7d69b027e..1df561a12 100644 --- a/docs_src/header_params/tutorial001.py +++ b/docs_src/header_params/tutorial001.py @@ -6,5 +6,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(user_agent: Optional[str] = Header(None)): +async def read_items(user_agent: Optional[str] = Header(default=None)): return {"User-Agent": user_agent} diff --git a/docs_src/header_params/tutorial001_py310.py b/docs_src/header_params/tutorial001_py310.py index b28463346..2203ed1b8 100644 --- a/docs_src/header_params/tutorial001_py310.py +++ b/docs_src/header_params/tutorial001_py310.py @@ -4,5 +4,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(user_agent: str | None = Header(None)): +async def read_items(user_agent: str | None = Header(default=None)): return {"User-Agent": user_agent} diff --git a/docs_src/header_params/tutorial002.py b/docs_src/header_params/tutorial002.py index 2de3dddd7..2250727f6 100644 --- a/docs_src/header_params/tutorial002.py +++ b/docs_src/header_params/tutorial002.py @@ -7,6 +7,6 @@ app = FastAPI() @app.get("/items/") async def read_items( - strange_header: Optional[str] = Header(None, convert_underscores=False) + strange_header: Optional[str] = Header(default=None, convert_underscores=False) ): return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial002_py310.py b/docs_src/header_params/tutorial002_py310.py index 98ab5a807..b7979b542 100644 --- a/docs_src/header_params/tutorial002_py310.py +++ b/docs_src/header_params/tutorial002_py310.py @@ -5,6 +5,6 @@ app = FastAPI() @app.get("/items/") async def read_items( - strange_header: str | None = Header(None, convert_underscores=False) + strange_header: str | None = Header(default=None, convert_underscores=False) ): return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial003.py b/docs_src/header_params/tutorial003.py index 6d0eefdd2..1ef131cee 100644 --- a/docs_src/header_params/tutorial003.py +++ b/docs_src/header_params/tutorial003.py @@ -6,5 +6,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(x_token: Optional[List[str]] = Header(None)): +async def read_items(x_token: Optional[List[str]] = Header(default=None)): return {"X-Token values": x_token} diff --git a/docs_src/header_params/tutorial003_py310.py b/docs_src/header_params/tutorial003_py310.py index 2dac2c13c..435c67574 100644 --- a/docs_src/header_params/tutorial003_py310.py +++ b/docs_src/header_params/tutorial003_py310.py @@ -4,5 +4,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(x_token: list[str] | None = Header(None)): +async def read_items(x_token: list[str] | None = Header(default=None)): return {"X-Token values": x_token} diff --git a/docs_src/header_params/tutorial003_py39.py b/docs_src/header_params/tutorial003_py39.py index 359766527..78dda58da 100644 --- a/docs_src/header_params/tutorial003_py39.py +++ b/docs_src/header_params/tutorial003_py39.py @@ -6,5 +6,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(x_token: Optional[list[str]] = Header(None)): +async def read_items(x_token: Optional[list[str]] = Header(default=None)): return {"X-Token values": x_token} diff --git a/docs_src/path_params_numeric_validations/tutorial001.py b/docs_src/path_params_numeric_validations/tutorial001.py index 11777bba7..530147028 100644 --- a/docs_src/path_params_numeric_validations/tutorial001.py +++ b/docs_src/path_params_numeric_validations/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Path, Query @@ -7,8 +7,8 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_items( - item_id: int = Path(..., title="The ID of the item to get"), - q: Optional[str] = Query(None, alias="item-query"), + item_id: int = Path(title="The ID of the item to get"), + q: Union[str, None] = Query(default=None, alias="item-query"), ): results = {"item_id": item_id} if q: diff --git a/docs_src/path_params_numeric_validations/tutorial001_py310.py b/docs_src/path_params_numeric_validations/tutorial001_py310.py index b940a0949..b1a77cc9d 100644 --- a/docs_src/path_params_numeric_validations/tutorial001_py310.py +++ b/docs_src/path_params_numeric_validations/tutorial001_py310.py @@ -5,8 +5,8 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_items( - item_id: int = Path(..., title="The ID of the item to get"), - q: str | None = Query(None, alias="item-query"), + item_id: int = Path(title="The ID of the item to get"), + q: str | None = Query(default=None, alias="item-query"), ): results = {"item_id": item_id} if q: diff --git a/docs_src/path_params_numeric_validations/tutorial002.py b/docs_src/path_params_numeric_validations/tutorial002.py index 57ca50ece..63ac691a8 100644 --- a/docs_src/path_params_numeric_validations/tutorial002.py +++ b/docs_src/path_params_numeric_validations/tutorial002.py @@ -4,9 +4,7 @@ app = FastAPI() @app.get("/items/{item_id}") -async def read_items( - q: str, item_id: int = Path(..., title="The ID of the item to get") -): +async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")): results = {"item_id": item_id} if q: results.update({"q": q}) diff --git a/docs_src/path_params_numeric_validations/tutorial003.py b/docs_src/path_params_numeric_validations/tutorial003.py index b6b5a1986..8df0ffc62 100644 --- a/docs_src/path_params_numeric_validations/tutorial003.py +++ b/docs_src/path_params_numeric_validations/tutorial003.py @@ -4,9 +4,7 @@ app = FastAPI() @app.get("/items/{item_id}") -async def read_items( - *, item_id: int = Path(..., title="The ID of the item to get"), q: str -): +async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str): results = {"item_id": item_id} if q: results.update({"q": q}) diff --git a/docs_src/path_params_numeric_validations/tutorial004.py b/docs_src/path_params_numeric_validations/tutorial004.py index 2ec708280..86651d47c 100644 --- a/docs_src/path_params_numeric_validations/tutorial004.py +++ b/docs_src/path_params_numeric_validations/tutorial004.py @@ -5,7 +5,7 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_items( - *, item_id: int = Path(..., title="The ID of the item to get", ge=1), q: str + *, item_id: int = Path(title="The ID of the item to get", ge=1), q: str ): results = {"item_id": item_id} if q: diff --git a/docs_src/path_params_numeric_validations/tutorial005.py b/docs_src/path_params_numeric_validations/tutorial005.py index 2809f37b2..8f12f2da0 100644 --- a/docs_src/path_params_numeric_validations/tutorial005.py +++ b/docs_src/path_params_numeric_validations/tutorial005.py @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_items( *, - item_id: int = Path(..., title="The ID of the item to get", gt=0, le=1000), + item_id: int = Path(title="The ID of the item to get", gt=0, le=1000), q: str, ): results = {"item_id": item_id} diff --git a/docs_src/path_params_numeric_validations/tutorial006.py b/docs_src/path_params_numeric_validations/tutorial006.py index 0c19579f5..85bd6e8b4 100644 --- a/docs_src/path_params_numeric_validations/tutorial006.py +++ b/docs_src/path_params_numeric_validations/tutorial006.py @@ -6,9 +6,9 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_items( *, - item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000), + item_id: int = Path(title="The ID of the item to get", ge=0, le=1000), q: str, - size: float = Query(..., gt=0, lt=10.5) + size: float = Query(gt=0, lt=10.5) ): results = {"item_id": item_id} if q: diff --git a/docs_src/query_params_str_validations/tutorial002.py b/docs_src/query_params_str_validations/tutorial002.py index 68ea58206..17e017b7e 100644 --- a/docs_src/query_params_str_validations/tutorial002.py +++ b/docs_src/query_params_str_validations/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Query @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Optional[str] = Query(None, max_length=50)): +async def read_items(q: Union[str, None] = Query(default=None, max_length=50)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial002_py310.py b/docs_src/query_params_str_validations/tutorial002_py310.py index fa3139d5a..f15351d29 100644 --- a/docs_src/query_params_str_validations/tutorial002_py310.py +++ b/docs_src/query_params_str_validations/tutorial002_py310.py @@ -4,7 +4,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: str | None = Query(None, max_length=50)): +async def read_items(q: str | None = Query(default=None, max_length=50)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial003.py b/docs_src/query_params_str_validations/tutorial003.py index e52acc72f..73d2e08c8 100644 --- a/docs_src/query_params_str_validations/tutorial003.py +++ b/docs_src/query_params_str_validations/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Query @@ -6,7 +6,9 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Optional[str] = Query(None, min_length=3, max_length=50)): +async def read_items( + q: Union[str, None] = Query(default=None, min_length=3, max_length=50) +): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial003_py310.py b/docs_src/query_params_str_validations/tutorial003_py310.py index 335858a40..dc60ecb39 100644 --- a/docs_src/query_params_str_validations/tutorial003_py310.py +++ b/docs_src/query_params_str_validations/tutorial003_py310.py @@ -4,7 +4,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: str | None = Query(None, min_length=3, max_length=50)): +async def read_items(q: str | None = Query(default=None, min_length=3, max_length=50)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial004.py b/docs_src/query_params_str_validations/tutorial004.py index d2c30331f..5a7129816 100644 --- a/docs_src/query_params_str_validations/tutorial004.py +++ b/docs_src/query_params_str_validations/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Query @@ -7,7 +7,9 @@ app = FastAPI() @app.get("/items/") async def read_items( - q: Optional[str] = Query(None, min_length=3, max_length=50, regex="^fixedquery$") + q: Union[str, None] = Query( + default=None, min_length=3, max_length=50, regex="^fixedquery$" + ) ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial004_py310.py b/docs_src/query_params_str_validations/tutorial004_py310.py index 518b779f7..180a2e511 100644 --- a/docs_src/query_params_str_validations/tutorial004_py310.py +++ b/docs_src/query_params_str_validations/tutorial004_py310.py @@ -5,7 +5,8 @@ app = FastAPI() @app.get("/items/") async def read_items( - q: str | None = Query(None, min_length=3, max_length=50, regex="^fixedquery$") + q: str + | None = Query(default=None, min_length=3, max_length=50, regex="^fixedquery$") ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial005.py b/docs_src/query_params_str_validations/tutorial005.py index 22eb3acba..8ab42869e 100644 --- a/docs_src/query_params_str_validations/tutorial005.py +++ b/docs_src/query_params_str_validations/tutorial005.py @@ -4,7 +4,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: str = Query("fixedquery", min_length=3)): +async def read_items(q: str = Query(default="fixedquery", min_length=3)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial006.py b/docs_src/query_params_str_validations/tutorial006.py index 720bf07f1..9a90eb64e 100644 --- a/docs_src/query_params_str_validations/tutorial006.py +++ b/docs_src/query_params_str_validations/tutorial006.py @@ -4,7 +4,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: str = Query(..., min_length=3)): +async def read_items(q: str = Query(min_length=3)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial006b.py b/docs_src/query_params_str_validations/tutorial006b.py new file mode 100644 index 000000000..a8d69c889 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial006b.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str = Query(default=..., min_length=3)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial006c.py b/docs_src/query_params_str_validations/tutorial006c.py new file mode 100644 index 000000000..2ac148c94 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial006c.py @@ -0,0 +1,13 @@ +from typing import Union + +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: Union[str, None] = Query(default=..., min_length=3)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial006c_py310.py b/docs_src/query_params_str_validations/tutorial006c_py310.py new file mode 100644 index 000000000..82dd9e5d7 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial006c_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str | None = Query(default=..., min_length=3)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial006d.py b/docs_src/query_params_str_validations/tutorial006d.py new file mode 100644 index 000000000..42c5bf4eb --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial006d.py @@ -0,0 +1,12 @@ +from fastapi import FastAPI, Query +from pydantic import Required + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: str = Query(default=Required, min_length=3)): + results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/query_params_str_validations/tutorial007.py b/docs_src/query_params_str_validations/tutorial007.py index e360feda9..cb836569e 100644 --- a/docs_src/query_params_str_validations/tutorial007.py +++ b/docs_src/query_params_str_validations/tutorial007.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Query @@ -7,7 +7,7 @@ app = FastAPI() @app.get("/items/") async def read_items( - q: Optional[str] = Query(None, title="Query string", min_length=3) + q: Union[str, None] = Query(default=None, title="Query string", min_length=3) ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial007_py310.py b/docs_src/query_params_str_validations/tutorial007_py310.py index 14ef4cb69..e3e1ef2e0 100644 --- a/docs_src/query_params_str_validations/tutorial007_py310.py +++ b/docs_src/query_params_str_validations/tutorial007_py310.py @@ -4,7 +4,9 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: str | None = Query(None, title="Query string", min_length=3)): +async def read_items( + q: str | None = Query(default=None, title="Query string", min_length=3) +): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial008.py b/docs_src/query_params_str_validations/tutorial008.py index 238add471..d112a9ab8 100644 --- a/docs_src/query_params_str_validations/tutorial008.py +++ b/docs_src/query_params_str_validations/tutorial008.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Query @@ -7,8 +7,8 @@ app = FastAPI() @app.get("/items/") async def read_items( - q: Optional[str] = Query( - None, + q: Union[str, None] = Query( + default=None, title="Query string", description="Query string for the items to search in the database that have a good match", min_length=3, diff --git a/docs_src/query_params_str_validations/tutorial008_py310.py b/docs_src/query_params_str_validations/tutorial008_py310.py index 06bb02442..489f631d5 100644 --- a/docs_src/query_params_str_validations/tutorial008_py310.py +++ b/docs_src/query_params_str_validations/tutorial008_py310.py @@ -7,7 +7,7 @@ app = FastAPI() async def read_items( q: str | None = Query( - None, + default=None, title="Query string", description="Query string for the items to search in the database that have a good match", min_length=3, diff --git a/docs_src/query_params_str_validations/tutorial009.py b/docs_src/query_params_str_validations/tutorial009.py index 7e5c0b81a..8a6bfe2d9 100644 --- a/docs_src/query_params_str_validations/tutorial009.py +++ b/docs_src/query_params_str_validations/tutorial009.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Query @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Optional[str] = Query(None, alias="item-query")): +async def read_items(q: Union[str, None] = Query(default=None, alias="item-query")): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial009_py310.py b/docs_src/query_params_str_validations/tutorial009_py310.py index e84c116f1..a38d32cbb 100644 --- a/docs_src/query_params_str_validations/tutorial009_py310.py +++ b/docs_src/query_params_str_validations/tutorial009_py310.py @@ -4,7 +4,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: str | None = Query(None, alias="item-query")): +async def read_items(q: str | None = Query(default=None, alias="item-query")): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial010.py b/docs_src/query_params_str_validations/tutorial010.py index 7921506b6..35443d194 100644 --- a/docs_src/query_params_str_validations/tutorial010.py +++ b/docs_src/query_params_str_validations/tutorial010.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Query @@ -7,8 +7,8 @@ app = FastAPI() @app.get("/items/") async def read_items( - q: Optional[str] = Query( - None, + q: Union[str, None] = Query( + default=None, alias="item-query", title="Query string", description="Query string for the items to search in the database that have a good match", diff --git a/docs_src/query_params_str_validations/tutorial010_py310.py b/docs_src/query_params_str_validations/tutorial010_py310.py index c35800858..f2839516e 100644 --- a/docs_src/query_params_str_validations/tutorial010_py310.py +++ b/docs_src/query_params_str_validations/tutorial010_py310.py @@ -7,7 +7,7 @@ app = FastAPI() async def read_items( q: str | None = Query( - None, + default=None, alias="item-query", title="Query string", description="Query string for the items to search in the database that have a good match", diff --git a/docs_src/query_params_str_validations/tutorial011.py b/docs_src/query_params_str_validations/tutorial011.py index 7fda267ed..65bbce781 100644 --- a/docs_src/query_params_str_validations/tutorial011.py +++ b/docs_src/query_params_str_validations/tutorial011.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Union from fastapi import FastAPI, Query @@ -6,6 +6,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Optional[List[str]] = Query(None)): +async def read_items(q: Union[List[str], None] = Query(default=None)): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial011_py310.py b/docs_src/query_params_str_validations/tutorial011_py310.py index c3d992e62..70155de7c 100644 --- a/docs_src/query_params_str_validations/tutorial011_py310.py +++ b/docs_src/query_params_str_validations/tutorial011_py310.py @@ -4,6 +4,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: list[str] | None = Query(None)): +async def read_items(q: list[str] | None = Query(default=None)): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial011_py39.py b/docs_src/query_params_str_validations/tutorial011_py39.py index 38ba764d6..878f95c79 100644 --- a/docs_src/query_params_str_validations/tutorial011_py39.py +++ b/docs_src/query_params_str_validations/tutorial011_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Query @@ -6,6 +6,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Optional[list[str]] = Query(None)): +async def read_items(q: Union[list[str], None] = Query(default=None)): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial012.py b/docs_src/query_params_str_validations/tutorial012.py index 7ea9f017d..e77d56974 100644 --- a/docs_src/query_params_str_validations/tutorial012.py +++ b/docs_src/query_params_str_validations/tutorial012.py @@ -6,6 +6,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: List[str] = Query(["foo", "bar"])): +async def read_items(q: List[str] = Query(default=["foo", "bar"])): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial012_py39.py b/docs_src/query_params_str_validations/tutorial012_py39.py index 1900133d9..070d0b04b 100644 --- a/docs_src/query_params_str_validations/tutorial012_py39.py +++ b/docs_src/query_params_str_validations/tutorial012_py39.py @@ -4,6 +4,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: list[str] = Query(["foo", "bar"])): +async def read_items(q: list[str] = Query(default=["foo", "bar"])): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial013.py b/docs_src/query_params_str_validations/tutorial013.py index 95dd6999d..0b0f44869 100644 --- a/docs_src/query_params_str_validations/tutorial013.py +++ b/docs_src/query_params_str_validations/tutorial013.py @@ -4,6 +4,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: list = Query([])): +async def read_items(q: list = Query(default=[])): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial014.py b/docs_src/query_params_str_validations/tutorial014.py index fb50bc27b..50e0a6c2b 100644 --- a/docs_src/query_params_str_validations/tutorial014.py +++ b/docs_src/query_params_str_validations/tutorial014.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Query @@ -7,7 +7,7 @@ app = FastAPI() @app.get("/items/") async def read_items( - hidden_query: Optional[str] = Query(None, include_in_schema=False) + hidden_query: Union[str, None] = Query(default=None, include_in_schema=False) ): if hidden_query: return {"hidden_query": hidden_query} diff --git a/docs_src/query_params_str_validations/tutorial014_py310.py b/docs_src/query_params_str_validations/tutorial014_py310.py index 7ae39c7f9..1b617efdd 100644 --- a/docs_src/query_params_str_validations/tutorial014_py310.py +++ b/docs_src/query_params_str_validations/tutorial014_py310.py @@ -4,7 +4,9 @@ app = FastAPI() @app.get("/items/") -async def read_items(hidden_query: str | None = Query(None, include_in_schema=False)): +async def read_items( + hidden_query: str | None = Query(default=None, include_in_schema=False) +): if hidden_query: return {"hidden_query": hidden_query} else: diff --git a/docs_src/request_files/tutorial001.py b/docs_src/request_files/tutorial001.py index 0fb1dd571..2e0ea6391 100644 --- a/docs_src/request_files/tutorial001.py +++ b/docs_src/request_files/tutorial001.py @@ -4,7 +4,7 @@ app = FastAPI() @app.post("/files/") -async def create_file(file: bytes = File(...)): +async def create_file(file: bytes = File()): return {"file_size": len(file)} diff --git a/docs_src/request_files/tutorial001_02.py b/docs_src/request_files/tutorial001_02.py index 26a4c9cbf..3f311c4b8 100644 --- a/docs_src/request_files/tutorial001_02.py +++ b/docs_src/request_files/tutorial001_02.py @@ -6,7 +6,7 @@ app = FastAPI() @app.post("/files/") -async def create_file(file: Optional[bytes] = File(None)): +async def create_file(file: Optional[bytes] = File(default=None)): if not file: return {"message": "No file sent"} else: diff --git a/docs_src/request_files/tutorial001_02_py310.py b/docs_src/request_files/tutorial001_02_py310.py index 0e576251b..298c9974f 100644 --- a/docs_src/request_files/tutorial001_02_py310.py +++ b/docs_src/request_files/tutorial001_02_py310.py @@ -4,7 +4,7 @@ app = FastAPI() @app.post("/files/") -async def create_file(file: bytes | None = File(None)): +async def create_file(file: bytes | None = File(default=None)): if not file: return {"message": "No file sent"} else: diff --git a/docs_src/request_files/tutorial001_03.py b/docs_src/request_files/tutorial001_03.py index abcac9e4c..d8005cc7d 100644 --- a/docs_src/request_files/tutorial001_03.py +++ b/docs_src/request_files/tutorial001_03.py @@ -4,12 +4,12 @@ app = FastAPI() @app.post("/files/") -async def create_file(file: bytes = File(..., description="A file read as bytes")): +async def create_file(file: bytes = File(description="A file read as bytes")): return {"file_size": len(file)} @app.post("/uploadfile/") async def create_upload_file( - file: UploadFile = File(..., description="A file read as UploadFile") + file: UploadFile = File(description="A file read as UploadFile"), ): return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial002.py b/docs_src/request_files/tutorial002.py index 94abb7c6c..b4d0acc68 100644 --- a/docs_src/request_files/tutorial002.py +++ b/docs_src/request_files/tutorial002.py @@ -7,7 +7,7 @@ app = FastAPI() @app.post("/files/") -async def create_files(files: List[bytes] = File(...)): +async def create_files(files: List[bytes] = File()): return {"file_sizes": [len(file) for file in files]} diff --git a/docs_src/request_files/tutorial002_py39.py b/docs_src/request_files/tutorial002_py39.py index 2779618bd..b64cf5598 100644 --- a/docs_src/request_files/tutorial002_py39.py +++ b/docs_src/request_files/tutorial002_py39.py @@ -5,7 +5,7 @@ app = FastAPI() @app.post("/files/") -async def create_files(files: list[bytes] = File(...)): +async def create_files(files: list[bytes] = File()): return {"file_sizes": [len(file) for file in files]} diff --git a/docs_src/request_files/tutorial003.py b/docs_src/request_files/tutorial003.py index 4a91b7a8b..e3f805f60 100644 --- a/docs_src/request_files/tutorial003.py +++ b/docs_src/request_files/tutorial003.py @@ -8,14 +8,14 @@ app = FastAPI() @app.post("/files/") async def create_files( - files: List[bytes] = File(..., description="Multiple files as bytes") + files: List[bytes] = File(description="Multiple files as bytes"), ): return {"file_sizes": [len(file) for file in files]} @app.post("/uploadfiles/") async def create_upload_files( - files: List[UploadFile] = File(..., description="Multiple files as UploadFile") + files: List[UploadFile] = File(description="Multiple files as UploadFile"), ): return {"filenames": [file.filename for file in files]} diff --git a/docs_src/request_files/tutorial003_py39.py b/docs_src/request_files/tutorial003_py39.py index d853f48d1..96f5e8742 100644 --- a/docs_src/request_files/tutorial003_py39.py +++ b/docs_src/request_files/tutorial003_py39.py @@ -6,14 +6,14 @@ app = FastAPI() @app.post("/files/") async def create_files( - files: list[bytes] = File(..., description="Multiple files as bytes") + files: list[bytes] = File(description="Multiple files as bytes"), ): return {"file_sizes": [len(file) for file in files]} @app.post("/uploadfiles/") async def create_upload_files( - files: list[UploadFile] = File(..., description="Multiple files as UploadFile") + files: list[UploadFile] = File(description="Multiple files as UploadFile"), ): return {"filenames": [file.filename for file in files]} diff --git a/docs_src/request_forms/tutorial001.py b/docs_src/request_forms/tutorial001.py index c07e22945..a53770001 100644 --- a/docs_src/request_forms/tutorial001.py +++ b/docs_src/request_forms/tutorial001.py @@ -4,5 +4,5 @@ app = FastAPI() @app.post("/login/") -async def login(username: str = Form(...), password: str = Form(...)): +async def login(username: str = Form(), password: str = Form()): return {"username": username} diff --git a/docs_src/request_forms_and_files/tutorial001.py b/docs_src/request_forms_and_files/tutorial001.py index 5bf3a5bc0..7b5224ce5 100644 --- a/docs_src/request_forms_and_files/tutorial001.py +++ b/docs_src/request_forms_and_files/tutorial001.py @@ -5,7 +5,7 @@ app = FastAPI() @app.post("/files/") async def create_file( - file: bytes = File(...), fileb: UploadFile = File(...), token: str = Form(...) + file: bytes = File(), fileb: UploadFile = File(), token: str = Form() ): return { "file_size": len(file), diff --git a/docs_src/schema_extra_example/tutorial002.py b/docs_src/schema_extra_example/tutorial002.py index df3df8854..a2aec46f5 100644 --- a/docs_src/schema_extra_example/tutorial002.py +++ b/docs_src/schema_extra_example/tutorial002.py @@ -7,10 +7,10 @@ app = FastAPI() class Item(BaseModel): - name: str = Field(..., example="Foo") - description: Optional[str] = Field(None, example="A very nice Item") - price: float = Field(..., example=35.4) - tax: Optional[float] = Field(None, example=3.2) + name: str = Field(example="Foo") + description: Optional[str] = Field(default=None, example="A very nice Item") + price: float = Field(example=35.4) + tax: Optional[float] = Field(default=None, example=3.2) @app.put("/items/{item_id}") diff --git a/docs_src/schema_extra_example/tutorial002_py310.py b/docs_src/schema_extra_example/tutorial002_py310.py index 4f8f8304e..e84928bb1 100644 --- a/docs_src/schema_extra_example/tutorial002_py310.py +++ b/docs_src/schema_extra_example/tutorial002_py310.py @@ -5,10 +5,10 @@ app = FastAPI() class Item(BaseModel): - name: str = Field(..., example="Foo") - description: str | None = Field(None, example="A very nice Item") - price: float = Field(..., example=35.4) - tax: float | None = Field(None, example=3.2) + name: str = Field(example="Foo") + description: str | None = Field(default=None, example="A very nice Item") + price: float = Field(example=35.4) + tax: float | None = Field(default=None, example=3.2) @app.put("/items/{item_id}") diff --git a/docs_src/schema_extra_example/tutorial003.py b/docs_src/schema_extra_example/tutorial003.py index 58c79f554..43d46b81b 100644 --- a/docs_src/schema_extra_example/tutorial003.py +++ b/docs_src/schema_extra_example/tutorial003.py @@ -17,7 +17,6 @@ class Item(BaseModel): async def update_item( item_id: int, item: Item = Body( - ..., example={ "name": "Foo", "description": "A very nice Item", diff --git a/docs_src/schema_extra_example/tutorial003_py310.py b/docs_src/schema_extra_example/tutorial003_py310.py index cf4c99dc0..1e137101d 100644 --- a/docs_src/schema_extra_example/tutorial003_py310.py +++ b/docs_src/schema_extra_example/tutorial003_py310.py @@ -15,7 +15,6 @@ class Item(BaseModel): async def update_item( item_id: int, item: Item = Body( - ..., example={ "name": "Foo", "description": "A very nice Item", diff --git a/docs_src/schema_extra_example/tutorial004.py b/docs_src/schema_extra_example/tutorial004.py index 9f0e8b437..42d7a04a3 100644 --- a/docs_src/schema_extra_example/tutorial004.py +++ b/docs_src/schema_extra_example/tutorial004.py @@ -18,7 +18,6 @@ async def update_item( *, item_id: int, item: Item = Body( - ..., examples={ "normal": { "summary": "A normal example", diff --git a/docs_src/schema_extra_example/tutorial004_py310.py b/docs_src/schema_extra_example/tutorial004_py310.py index 6f29c1a5c..100a30860 100644 --- a/docs_src/schema_extra_example/tutorial004_py310.py +++ b/docs_src/schema_extra_example/tutorial004_py310.py @@ -16,7 +16,6 @@ async def update_item( *, item_id: int, item: Item = Body( - ..., examples={ "normal": { "summary": "A normal example", diff --git a/docs_src/websockets/tutorial002.py b/docs_src/websockets/tutorial002.py index 53cdb41ff..b01008530 100644 --- a/docs_src/websockets/tutorial002.py +++ b/docs_src/websockets/tutorial002.py @@ -57,8 +57,8 @@ async def get(): async def get_cookie_or_token( websocket: WebSocket, - session: Optional[str] = Cookie(None), - token: Optional[str] = Query(None), + session: Optional[str] = Cookie(default=None), + token: Optional[str] = Query(default=None), ): if session is None and token is None: await websocket.close(code=status.WS_1008_POLICY_VIOLATION) diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 9dccd354e..f397e333c 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -43,6 +43,7 @@ from pydantic.fields import ( FieldInfo, ModelField, Required, + Undefined, ) from pydantic.schema import get_annotation_from_field_info from pydantic.typing import ForwardRef, evaluate_forwardref @@ -316,7 +317,7 @@ def get_dependant( field_info = param_field.field_info assert isinstance( field_info, params.Body - ), f"Param: {param_field.name} can only be a request body, using Body(...)" + ), f"Param: {param_field.name} can only be a request body, using Body()" dependant.body_params.append(param_field) return dependant @@ -353,7 +354,7 @@ def get_param_field( force_type: Optional[params.ParamTypes] = None, ignore_default: bool = False, ) -> ModelField: - default_value = Required + default_value: Any = Undefined had_schema = False if not param.default == param.empty and ignore_default is False: default_value = param.default @@ -369,8 +370,13 @@ def get_param_field( if force_type: field_info.in_ = force_type # type: ignore else: - field_info = default_field_info(default_value) - required = default_value == Required + field_info = default_field_info(default=default_value) + required = True + if default_value is Required or ignore_default: + required = True + default_value = None + elif default_value is not Undefined: + required = False annotation: Any = Any if not param.annotation == param.empty: annotation = param.annotation @@ -382,12 +388,11 @@ def get_param_field( field = create_response_field( name=param.name, type_=annotation, - default=None if required else default_value, + default=default_value, alias=alias, required=required, field_info=field_info, ) - field.required = required if not had_schema and not is_scalar_field(field=field): field.field_info = params.Body(field_info.default) if not had_schema and lenient_issubclass(field.type_, UploadFile): diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 9c6598d2d..35aa1672b 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -73,7 +73,7 @@ class Server(BaseModel): class Reference(BaseModel): - ref: str = Field(..., alias="$ref") + ref: str = Field(alias="$ref") class Discriminator(BaseModel): @@ -101,28 +101,28 @@ class ExternalDocumentation(BaseModel): class Schema(BaseModel): - ref: Optional[str] = Field(None, alias="$ref") + ref: Optional[str] = Field(default=None, alias="$ref") title: Optional[str] = None multipleOf: Optional[float] = None maximum: Optional[float] = None exclusiveMaximum: Optional[float] = None minimum: Optional[float] = None exclusiveMinimum: Optional[float] = None - maxLength: Optional[int] = Field(None, gte=0) - minLength: Optional[int] = Field(None, gte=0) + maxLength: Optional[int] = Field(default=None, gte=0) + minLength: Optional[int] = Field(default=None, gte=0) pattern: Optional[str] = None - maxItems: Optional[int] = Field(None, gte=0) - minItems: Optional[int] = Field(None, gte=0) + maxItems: Optional[int] = Field(default=None, gte=0) + minItems: Optional[int] = Field(default=None, gte=0) uniqueItems: Optional[bool] = None - maxProperties: Optional[int] = Field(None, gte=0) - minProperties: Optional[int] = Field(None, gte=0) + maxProperties: Optional[int] = Field(default=None, gte=0) + minProperties: Optional[int] = Field(default=None, gte=0) required: Optional[List[str]] = None enum: Optional[List[Any]] = None type: Optional[str] = None allOf: Optional[List["Schema"]] = None oneOf: Optional[List["Schema"]] = None anyOf: Optional[List["Schema"]] = None - not_: Optional["Schema"] = Field(None, alias="not") + not_: Optional["Schema"] = Field(default=None, alias="not") items: Optional[Union["Schema", List["Schema"]]] = None properties: Optional[Dict[str, "Schema"]] = None additionalProperties: Optional[Union["Schema", Reference, bool]] = None @@ -171,7 +171,7 @@ class Encoding(BaseModel): class MediaType(BaseModel): - schema_: Optional[Union[Schema, Reference]] = Field(None, alias="schema") + schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") example: Optional[Any] = None examples: Optional[Dict[str, Union[Example, Reference]]] = None encoding: Optional[Dict[str, Encoding]] = None @@ -188,7 +188,7 @@ class ParameterBase(BaseModel): style: Optional[str] = None explode: Optional[bool] = None allowReserved: Optional[bool] = None - schema_: Optional[Union[Schema, Reference]] = Field(None, alias="schema") + schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") example: Optional[Any] = None examples: Optional[Dict[str, Union[Example, Reference]]] = None # Serialization rules for more complex scenarios @@ -200,7 +200,7 @@ class ParameterBase(BaseModel): class Parameter(ParameterBase): name: str - in_: ParameterInType = Field(..., alias="in") + in_: ParameterInType = Field(alias="in") class Header(ParameterBase): @@ -258,7 +258,7 @@ class Operation(BaseModel): class PathItem(BaseModel): - ref: Optional[str] = Field(None, alias="$ref") + ref: Optional[str] = Field(default=None, alias="$ref") summary: Optional[str] = None description: Optional[str] = None get: Optional[Operation] = None @@ -284,7 +284,7 @@ class SecuritySchemeType(Enum): class SecurityBase(BaseModel): - type_: SecuritySchemeType = Field(..., alias="type") + type_: SecuritySchemeType = Field(alias="type") description: Optional[str] = None class Config: @@ -299,7 +299,7 @@ class APIKeyIn(Enum): class APIKey(SecurityBase): type_ = Field(SecuritySchemeType.apiKey, alias="type") - in_: APIKeyIn = Field(..., alias="in") + in_: APIKeyIn = Field(alias="in") name: str diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py index a553a1461..1932ef065 100644 --- a/fastapi/param_functions.py +++ b/fastapi/param_functions.py @@ -5,7 +5,7 @@ from pydantic.fields import Undefined def Path( # noqa: N802 - default: Any, + default: Any = Undefined, *, alias: Optional[str] = None, title: Optional[str] = None, @@ -44,7 +44,7 @@ def Path( # noqa: N802 def Query( # noqa: N802 - default: Any, + default: Any = Undefined, *, alias: Optional[str] = None, title: Optional[str] = None, @@ -63,7 +63,7 @@ def Query( # noqa: N802 **extra: Any, ) -> Any: return params.Query( - default, + default=default, alias=alias, title=title, description=description, @@ -83,7 +83,7 @@ def Query( # noqa: N802 def Header( # noqa: N802 - default: Any, + default: Any = Undefined, *, alias: Optional[str] = None, convert_underscores: bool = True, @@ -103,7 +103,7 @@ def Header( # noqa: N802 **extra: Any, ) -> Any: return params.Header( - default, + default=default, alias=alias, convert_underscores=convert_underscores, title=title, @@ -124,7 +124,7 @@ def Header( # noqa: N802 def Cookie( # noqa: N802 - default: Any, + default: Any = Undefined, *, alias: Optional[str] = None, title: Optional[str] = None, @@ -143,7 +143,7 @@ def Cookie( # noqa: N802 **extra: Any, ) -> Any: return params.Cookie( - default, + default=default, alias=alias, title=title, description=description, @@ -163,7 +163,7 @@ def Cookie( # noqa: N802 def Body( # noqa: N802 - default: Any, + default: Any = Undefined, *, embed: bool = False, media_type: str = "application/json", @@ -182,7 +182,7 @@ def Body( # noqa: N802 **extra: Any, ) -> Any: return params.Body( - default, + default=default, embed=embed, media_type=media_type, alias=alias, @@ -202,7 +202,7 @@ def Body( # noqa: N802 def Form( # noqa: N802 - default: Any, + default: Any = Undefined, *, media_type: str = "application/x-www-form-urlencoded", alias: Optional[str] = None, @@ -220,7 +220,7 @@ def Form( # noqa: N802 **extra: Any, ) -> Any: return params.Form( - default, + default=default, media_type=media_type, alias=alias, title=title, @@ -239,7 +239,7 @@ def Form( # noqa: N802 def File( # noqa: N802 - default: Any, + default: Any = Undefined, *, media_type: str = "multipart/form-data", alias: Optional[str] = None, @@ -257,7 +257,7 @@ def File( # noqa: N802 **extra: Any, ) -> Any: return params.File( - default, + default=default, media_type=media_type, alias=alias, title=title, diff --git a/fastapi/params.py b/fastapi/params.py index 042bbd42f..5395b98a3 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -16,7 +16,7 @@ class Param(FieldInfo): def __init__( self, - default: Any, + default: Any = Undefined, *, alias: Optional[str] = None, title: Optional[str] = None, @@ -39,7 +39,7 @@ class Param(FieldInfo): self.examples = examples self.include_in_schema = include_in_schema super().__init__( - default, + default=default, alias=alias, title=title, description=description, @@ -62,7 +62,7 @@ class Path(Param): def __init__( self, - default: Any, + default: Any = Undefined, *, alias: Optional[str] = None, title: Optional[str] = None, @@ -82,7 +82,7 @@ class Path(Param): ): self.in_ = self.in_ super().__init__( - ..., + default=..., alias=alias, title=title, description=description, @@ -106,7 +106,7 @@ class Query(Param): def __init__( self, - default: Any, + default: Any = Undefined, *, alias: Optional[str] = None, title: Optional[str] = None, @@ -125,7 +125,7 @@ class Query(Param): **extra: Any, ): super().__init__( - default, + default=default, alias=alias, title=title, description=description, @@ -149,7 +149,7 @@ class Header(Param): def __init__( self, - default: Any, + default: Any = Undefined, *, alias: Optional[str] = None, convert_underscores: bool = True, @@ -170,7 +170,7 @@ class Header(Param): ): self.convert_underscores = convert_underscores super().__init__( - default, + default=default, alias=alias, title=title, description=description, @@ -194,7 +194,7 @@ class Cookie(Param): def __init__( self, - default: Any, + default: Any = Undefined, *, alias: Optional[str] = None, title: Optional[str] = None, @@ -213,7 +213,7 @@ class Cookie(Param): **extra: Any, ): super().__init__( - default, + default=default, alias=alias, title=title, description=description, @@ -235,7 +235,7 @@ class Cookie(Param): class Body(FieldInfo): def __init__( self, - default: Any, + default: Any = Undefined, *, embed: bool = False, media_type: str = "application/json", @@ -258,7 +258,7 @@ class Body(FieldInfo): self.example = example self.examples = examples super().__init__( - default, + default=default, alias=alias, title=title, description=description, @@ -297,7 +297,7 @@ class Form(Body): **extra: Any, ): super().__init__( - default, + default=default, embed=True, media_type=media_type, alias=alias, @@ -337,7 +337,7 @@ class File(Form): **extra: Any, ): super().__init__( - default, + default=default, media_type=media_type, alias=alias, title=title, diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py index bdc6e2ea9..888208c15 100644 --- a/fastapi/security/oauth2.py +++ b/fastapi/security/oauth2.py @@ -45,12 +45,12 @@ class OAuth2PasswordRequestForm: def __init__( self, - grant_type: str = Form(None, regex="password"), - username: str = Form(...), - password: str = Form(...), - scope: str = Form(""), - client_id: Optional[str] = Form(None), - client_secret: Optional[str] = Form(None), + grant_type: str = Form(default=None, regex="password"), + username: str = Form(), + password: str = Form(), + scope: str = Form(default=""), + client_id: Optional[str] = Form(default=None), + client_secret: Optional[str] = Form(default=None), ): self.grant_type = grant_type self.username = username @@ -95,12 +95,12 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): def __init__( self, - grant_type: str = Form(..., regex="password"), - username: str = Form(...), - password: str = Form(...), - scope: str = Form(""), - client_id: Optional[str] = Form(None), - client_secret: Optional[str] = Form(None), + grant_type: str = Form(regex="password"), + username: str = Form(), + password: str = Form(), + scope: str = Form(default=""), + client_id: Optional[str] = Form(default=None), + client_secret: Optional[str] = Form(default=None), ): super().__init__( grant_type=grant_type, diff --git a/fastapi/utils.py b/fastapi/utils.py index 9d720feb3..a7e135bca 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -52,7 +52,7 @@ def create_response_field( Create a new response field. Raises if type_ is invalid. """ class_validators = class_validators or {} - field_info = field_info or FieldInfo(None) + field_info = field_info or FieldInfo() response_field = functools.partial( ModelField, diff --git a/tests/main.py b/tests/main.py index d5603d0e6..f70496db8 100644 --- a/tests/main.py +++ b/tests/main.py @@ -49,97 +49,97 @@ def get_bool_id(item_id: bool): @app.get("/path/param/{item_id}") -def get_path_param_id(item_id: Optional[str] = Path(None)): +def get_path_param_id(item_id: str = Path()): return item_id @app.get("/path/param-required/{item_id}") -def get_path_param_required_id(item_id: str = Path(...)): +def get_path_param_required_id(item_id: str = Path()): return item_id @app.get("/path/param-minlength/{item_id}") -def get_path_param_min_length(item_id: str = Path(..., min_length=3)): +def get_path_param_min_length(item_id: str = Path(min_length=3)): return item_id @app.get("/path/param-maxlength/{item_id}") -def get_path_param_max_length(item_id: str = Path(..., max_length=3)): +def get_path_param_max_length(item_id: str = Path(max_length=3)): return item_id @app.get("/path/param-min_maxlength/{item_id}") -def get_path_param_min_max_length(item_id: str = Path(..., max_length=3, min_length=2)): +def get_path_param_min_max_length(item_id: str = Path(max_length=3, min_length=2)): return item_id @app.get("/path/param-gt/{item_id}") -def get_path_param_gt(item_id: float = Path(..., gt=3)): +def get_path_param_gt(item_id: float = Path(gt=3)): return item_id @app.get("/path/param-gt0/{item_id}") -def get_path_param_gt0(item_id: float = Path(..., gt=0)): +def get_path_param_gt0(item_id: float = Path(gt=0)): return item_id @app.get("/path/param-ge/{item_id}") -def get_path_param_ge(item_id: float = Path(..., ge=3)): +def get_path_param_ge(item_id: float = Path(ge=3)): return item_id @app.get("/path/param-lt/{item_id}") -def get_path_param_lt(item_id: float = Path(..., lt=3)): +def get_path_param_lt(item_id: float = Path(lt=3)): return item_id @app.get("/path/param-lt0/{item_id}") -def get_path_param_lt0(item_id: float = Path(..., lt=0)): +def get_path_param_lt0(item_id: float = Path(lt=0)): return item_id @app.get("/path/param-le/{item_id}") -def get_path_param_le(item_id: float = Path(..., le=3)): +def get_path_param_le(item_id: float = Path(le=3)): return item_id @app.get("/path/param-lt-gt/{item_id}") -def get_path_param_lt_gt(item_id: float = Path(..., lt=3, gt=1)): +def get_path_param_lt_gt(item_id: float = Path(lt=3, gt=1)): return item_id @app.get("/path/param-le-ge/{item_id}") -def get_path_param_le_ge(item_id: float = Path(..., le=3, ge=1)): +def get_path_param_le_ge(item_id: float = Path(le=3, ge=1)): return item_id @app.get("/path/param-lt-int/{item_id}") -def get_path_param_lt_int(item_id: int = Path(..., lt=3)): +def get_path_param_lt_int(item_id: int = Path(lt=3)): return item_id @app.get("/path/param-gt-int/{item_id}") -def get_path_param_gt_int(item_id: int = Path(..., gt=3)): +def get_path_param_gt_int(item_id: int = Path(gt=3)): return item_id @app.get("/path/param-le-int/{item_id}") -def get_path_param_le_int(item_id: int = Path(..., le=3)): +def get_path_param_le_int(item_id: int = Path(le=3)): return item_id @app.get("/path/param-ge-int/{item_id}") -def get_path_param_ge_int(item_id: int = Path(..., ge=3)): +def get_path_param_ge_int(item_id: int = Path(ge=3)): return item_id @app.get("/path/param-lt-gt-int/{item_id}") -def get_path_param_lt_gt_int(item_id: int = Path(..., lt=3, gt=1)): +def get_path_param_lt_gt_int(item_id: int = Path(lt=3, gt=1)): return item_id @app.get("/path/param-le-ge-int/{item_id}") -def get_path_param_le_ge_int(item_id: int = Path(..., le=3, ge=1)): +def get_path_param_le_ge_int(item_id: int = Path(le=3, ge=1)): return item_id @@ -173,19 +173,19 @@ def get_query_type_int_default(query: int = 10): @app.get("/query/param") -def get_query_param(query=Query(None)): +def get_query_param(query=Query(default=None)): if query is None: return "foo bar" return f"foo bar {query}" @app.get("/query/param-required") -def get_query_param_required(query=Query(...)): +def get_query_param_required(query=Query()): return f"foo bar {query}" @app.get("/query/param-required/int") -def get_query_param_required_type(query: int = Query(...)): +def get_query_param_required_type(query: int = Query()): return f"foo bar {query}" diff --git a/tests/test_dependency_normal_exceptions.py b/tests/test_dependency_normal_exceptions.py index 49a19f460..23c366d5d 100644 --- a/tests/test_dependency_normal_exceptions.py +++ b/tests/test_dependency_normal_exceptions.py @@ -26,14 +26,14 @@ async def get_database(): @app.put("/invalid-user/{user_id}") def put_invalid_user( - user_id: str, name: str = Body(...), db: dict = Depends(get_database) + user_id: str, name: str = Body(), db: dict = Depends(get_database) ): db[user_id] = name raise HTTPException(status_code=400, detail="Invalid user") @app.put("/user/{user_id}") -def put_user(user_id: str, name: str = Body(...), db: dict = Depends(get_database)): +def put_user(user_id: str, name: str = Body(), db: dict = Depends(get_database)): db[user_id] = name return {"message": "OK"} diff --git a/tests/test_forms_from_non_typing_sequences.py b/tests/test_forms_from_non_typing_sequences.py index be917eab7..52ce24753 100644 --- a/tests/test_forms_from_non_typing_sequences.py +++ b/tests/test_forms_from_non_typing_sequences.py @@ -5,17 +5,17 @@ app = FastAPI() @app.post("/form/python-list") -def post_form_param_list(items: list = Form(...)): +def post_form_param_list(items: list = Form()): return items @app.post("/form/python-set") -def post_form_param_set(items: set = Form(...)): +def post_form_param_set(items: set = Form()): return items @app.post("/form/python-tuple") -def post_form_param_tuple(items: tuple = Form(...)): +def post_form_param_tuple(items: tuple = Form()): return items diff --git a/tests/test_invalid_sequence_param.py b/tests/test_invalid_sequence_param.py index f00dd7b93..475786adb 100644 --- a/tests/test_invalid_sequence_param.py +++ b/tests/test_invalid_sequence_param.py @@ -13,7 +13,7 @@ def test_invalid_sequence(): title: str @app.get("/items/") - def read_items(q: List[Item] = Query(None)): + def read_items(q: List[Item] = Query(default=None)): pass # pragma: no cover @@ -25,7 +25,7 @@ def test_invalid_tuple(): title: str @app.get("/items/") - def read_items(q: Tuple[Item, Item] = Query(None)): + def read_items(q: Tuple[Item, Item] = Query(default=None)): pass # pragma: no cover @@ -37,7 +37,7 @@ def test_invalid_dict(): title: str @app.get("/items/") - def read_items(q: Dict[str, Item] = Query(None)): + def read_items(q: Dict[str, Item] = Query(default=None)): pass # pragma: no cover @@ -49,5 +49,5 @@ def test_invalid_simple_dict(): title: str @app.get("/items/") - def read_items(q: Optional[dict] = Query(None)): + def read_items(q: Optional[dict] = Query(default=None)): pass # pragma: no cover diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py index fa82b5ea8..ed35fd32e 100644 --- a/tests/test_jsonable_encoder.py +++ b/tests/test_jsonable_encoder.py @@ -67,7 +67,7 @@ class ModelWithConfig(BaseModel): class ModelWithAlias(BaseModel): - foo: str = Field(..., alias="Foo") + foo: str = Field(alias="Foo") class ModelWithDefault(BaseModel): diff --git a/tests/test_modules_same_name_body/app/a.py b/tests/test_modules_same_name_body/app/a.py index 3c86c1865..377236890 100644 --- a/tests/test_modules_same_name_body/app/a.py +++ b/tests/test_modules_same_name_body/app/a.py @@ -4,5 +4,5 @@ router = APIRouter() @router.post("/compute") -def compute(a: int = Body(...), b: str = Body(...)): +def compute(a: int = Body(), b: str = Body()): return {"a": a, "b": b} diff --git a/tests/test_modules_same_name_body/app/b.py b/tests/test_modules_same_name_body/app/b.py index f7c7fdfc6..b62118f84 100644 --- a/tests/test_modules_same_name_body/app/b.py +++ b/tests/test_modules_same_name_body/app/b.py @@ -4,5 +4,5 @@ router = APIRouter() @router.post("/compute/") -def compute(a: int = Body(...), b: str = Body(...)): +def compute(a: int = Body(), b: str = Body()): return {"a": a, "b": b} diff --git a/tests/test_multi_query_errors.py b/tests/test_multi_query_errors.py index 0a15833fa..3da461af5 100644 --- a/tests/test_multi_query_errors.py +++ b/tests/test_multi_query_errors.py @@ -7,7 +7,7 @@ app = FastAPI() @app.get("/items/") -def read_items(q: List[int] = Query(None)): +def read_items(q: List[int] = Query(default=None)): return {"q": q} diff --git a/tests/test_multipart_installation.py b/tests/test_multipart_installation.py index c8a6fd942..788d9ef5a 100644 --- a/tests/test_multipart_installation.py +++ b/tests/test_multipart_installation.py @@ -12,7 +12,7 @@ def test_incorrect_multipart_installed_form(monkeypatch): app = FastAPI() @app.post("/") - async def root(username: str = Form(...)): + async def root(username: str = Form()): return username # pragma: nocover @@ -22,7 +22,7 @@ def test_incorrect_multipart_installed_file_upload(monkeypatch): app = FastAPI() @app.post("/") - async def root(f: UploadFile = File(...)): + async def root(f: UploadFile = File()): return f # pragma: nocover @@ -32,7 +32,7 @@ def test_incorrect_multipart_installed_file_bytes(monkeypatch): app = FastAPI() @app.post("/") - async def root(f: bytes = File(...)): + async def root(f: bytes = File()): return f # pragma: nocover @@ -42,7 +42,7 @@ def test_incorrect_multipart_installed_multi_form(monkeypatch): app = FastAPI() @app.post("/") - async def root(username: str = Form(...), password: str = Form(...)): + async def root(username: str = Form(), password: str = Form()): return username # pragma: nocover @@ -52,7 +52,7 @@ def test_incorrect_multipart_installed_form_file(monkeypatch): app = FastAPI() @app.post("/") - async def root(username: str = Form(...), f: UploadFile = File(...)): + async def root(username: str = Form(), f: UploadFile = File()): return username # pragma: nocover @@ -62,7 +62,7 @@ def test_no_multipart_installed(monkeypatch): app = FastAPI() @app.post("/") - async def root(username: str = Form(...)): + async def root(username: str = Form()): return username # pragma: nocover @@ -72,7 +72,7 @@ def test_no_multipart_installed_file(monkeypatch): app = FastAPI() @app.post("/") - async def root(f: UploadFile = File(...)): + async def root(f: UploadFile = File()): return f # pragma: nocover @@ -82,7 +82,7 @@ def test_no_multipart_installed_file_bytes(monkeypatch): app = FastAPI() @app.post("/") - async def root(f: bytes = File(...)): + async def root(f: bytes = File()): return f # pragma: nocover @@ -92,7 +92,7 @@ def test_no_multipart_installed_multi_form(monkeypatch): app = FastAPI() @app.post("/") - async def root(username: str = Form(...), password: str = Form(...)): + async def root(username: str = Form(), password: str = Form()): return username # pragma: nocover @@ -102,5 +102,5 @@ def test_no_multipart_installed_form_file(monkeypatch): app = FastAPI() @app.post("/") - async def root(username: str = Form(...), f: UploadFile = File(...)): + async def root(username: str = Form(), f: UploadFile = File()): return username # pragma: nocover diff --git a/tests/test_param_class.py b/tests/test_param_class.py index f5767ec96..1fd40dcd2 100644 --- a/tests/test_param_class.py +++ b/tests/test_param_class.py @@ -8,7 +8,7 @@ app = FastAPI() @app.get("/items/") -def read_items(q: Optional[str] = Param(None)): # type: ignore +def read_items(q: Optional[str] = Param(default=None)): # type: ignore return {"q": q} diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py index 26aa63897..214f039b6 100644 --- a/tests/test_param_include_in_schema.py +++ b/tests/test_param_include_in_schema.py @@ -9,26 +9,26 @@ app = FastAPI() @app.get("/hidden_cookie") async def hidden_cookie( - hidden_cookie: Optional[str] = Cookie(None, include_in_schema=False) + hidden_cookie: Optional[str] = Cookie(default=None, include_in_schema=False) ): return {"hidden_cookie": hidden_cookie} @app.get("/hidden_header") async def hidden_header( - hidden_header: Optional[str] = Header(None, include_in_schema=False) + hidden_header: Optional[str] = Header(default=None, include_in_schema=False) ): return {"hidden_header": hidden_header} @app.get("/hidden_path/{hidden_path}") -async def hidden_path(hidden_path: str = Path(..., include_in_schema=False)): +async def hidden_path(hidden_path: str = Path(include_in_schema=False)): return {"hidden_path": hidden_path} @app.get("/hidden_query") async def hidden_query( - hidden_query: Optional[str] = Query(None, include_in_schema=False) + hidden_query: Optional[str] = Query(default=None, include_in_schema=False) ): return {"hidden_query": hidden_query} diff --git a/tests/test_repeated_dependency_schema.py b/tests/test_repeated_dependency_schema.py index 00441694e..ca0305184 100644 --- a/tests/test_repeated_dependency_schema.py +++ b/tests/test_repeated_dependency_schema.py @@ -4,7 +4,7 @@ from fastapi.testclient import TestClient app = FastAPI() -def get_header(*, someheader: str = Header(...)): +def get_header(*, someheader: str = Header()): return someheader diff --git a/tests/test_request_body_parameters_media_type.py b/tests/test_request_body_parameters_media_type.py index ace6bdef7..e9cf4006d 100644 --- a/tests/test_request_body_parameters_media_type.py +++ b/tests/test_request_body_parameters_media_type.py @@ -21,14 +21,14 @@ class Shop(BaseModel): @app.post("/products") -async def create_product(data: Product = Body(..., media_type=media_type, embed=True)): +async def create_product(data: Product = Body(media_type=media_type, embed=True)): pass # pragma: no cover @app.post("/shops") async def create_shop( - data: Shop = Body(..., media_type=media_type), - included: typing.List[Product] = Body([], media_type=media_type), + data: Shop = Body(media_type=media_type), + included: typing.List[Product] = Body(default=[], media_type=media_type), ): pass # pragma: no cover diff --git a/tests/test_schema_extra_examples.py b/tests/test_schema_extra_examples.py index 444e350a8..5047aeaa4 100644 --- a/tests/test_schema_extra_examples.py +++ b/tests/test_schema_extra_examples.py @@ -1,3 +1,5 @@ +from typing import Union + from fastapi import Body, Cookie, FastAPI, Header, Path, Query from fastapi.testclient import TestClient from pydantic import BaseModel @@ -18,14 +20,13 @@ def schema_extra(item: Item): @app.post("/example/") -def example(item: Item = Body(..., example={"data": "Data in Body example"})): +def example(item: Item = Body(example={"data": "Data in Body example"})): return item @app.post("/examples/") def examples( item: Item = Body( - ..., examples={ "example1": { "summary": "example1 summary", @@ -41,7 +42,6 @@ def examples( @app.post("/example_examples/") def example_examples( item: Item = Body( - ..., example={"data": "Overriden example"}, examples={ "example1": {"value": {"data": "examples example_examples 1"}}, @@ -55,7 +55,7 @@ def example_examples( # TODO: enable these tests once/if Form(embed=False) is supported # TODO: In that case, define if File() should support example/examples too # @app.post("/form_example") -# def form_example(firstname: str = Form(..., example="John")): +# def form_example(firstname: str = Form(example="John")): # return firstname @@ -89,7 +89,6 @@ def example_examples( @app.get("/path_example/{item_id}") def path_example( item_id: str = Path( - ..., example="item_1", ), ): @@ -99,7 +98,6 @@ def path_example( @app.get("/path_examples/{item_id}") def path_examples( item_id: str = Path( - ..., examples={ "example1": {"summary": "item ID summary", "value": "item_1"}, "example2": {"value": "item_2"}, @@ -112,7 +110,6 @@ def path_examples( @app.get("/path_example_examples/{item_id}") def path_example_examples( item_id: str = Path( - ..., example="item_overriden", examples={ "example1": {"summary": "item ID summary", "value": "item_1"}, @@ -125,8 +122,8 @@ def path_example_examples( @app.get("/query_example/") def query_example( - data: str = Query( - None, + data: Union[str, None] = Query( + default=None, example="query1", ), ): @@ -135,8 +132,8 @@ def query_example( @app.get("/query_examples/") def query_examples( - data: str = Query( - None, + data: Union[str, None] = Query( + default=None, examples={ "example1": {"summary": "Query example 1", "value": "query1"}, "example2": {"value": "query2"}, @@ -148,8 +145,8 @@ def query_examples( @app.get("/query_example_examples/") def query_example_examples( - data: str = Query( - None, + data: Union[str, None] = Query( + default=None, example="query_overriden", examples={ "example1": {"summary": "Qeury example 1", "value": "query1"}, @@ -162,8 +159,8 @@ def query_example_examples( @app.get("/header_example/") def header_example( - data: str = Header( - None, + data: Union[str, None] = Header( + default=None, example="header1", ), ): @@ -172,8 +169,8 @@ def header_example( @app.get("/header_examples/") def header_examples( - data: str = Header( - None, + data: Union[str, None] = Header( + default=None, examples={ "example1": {"summary": "header example 1", "value": "header1"}, "example2": {"value": "header2"}, @@ -185,8 +182,8 @@ def header_examples( @app.get("/header_example_examples/") def header_example_examples( - data: str = Header( - None, + data: Union[str, None] = Header( + default=None, example="header_overriden", examples={ "example1": {"summary": "Qeury example 1", "value": "header1"}, @@ -199,8 +196,8 @@ def header_example_examples( @app.get("/cookie_example/") def cookie_example( - data: str = Cookie( - None, + data: Union[str, None] = Cookie( + default=None, example="cookie1", ), ): @@ -209,8 +206,8 @@ def cookie_example( @app.get("/cookie_examples/") def cookie_examples( - data: str = Cookie( - None, + data: Union[str, None] = Cookie( + default=None, examples={ "example1": {"summary": "cookie example 1", "value": "cookie1"}, "example2": {"value": "cookie2"}, @@ -222,8 +219,8 @@ def cookie_examples( @app.get("/cookie_example_examples/") def cookie_example_examples( - data: str = Cookie( - None, + data: Union[str, None] = Cookie( + default=None, example="cookie_overriden", examples={ "example1": {"summary": "Qeury example 1", "value": "cookie1"}, diff --git a/tests/test_serialize_response_model.py b/tests/test_serialize_response_model.py index 295667437..3bb46b2e9 100644 --- a/tests/test_serialize_response_model.py +++ b/tests/test_serialize_response_model.py @@ -8,7 +8,7 @@ app = FastAPI() class Item(BaseModel): - name: str = Field(..., alias="aliased_name") + name: str = Field(alias="aliased_name") price: Optional[float] = None owner_ids: Optional[List[int]] = None diff --git a/tests/test_starlette_urlconvertors.py b/tests/test_starlette_urlconvertors.py index 2320c7005..5a980cbf6 100644 --- a/tests/test_starlette_urlconvertors.py +++ b/tests/test_starlette_urlconvertors.py @@ -5,17 +5,17 @@ app = FastAPI() @app.get("/int/{param:int}") -def int_convertor(param: int = Path(...)): +def int_convertor(param: int = Path()): return {"int": param} @app.get("/float/{param:float}") -def float_convertor(param: float = Path(...)): +def float_convertor(param: float = Path()): return {"float": param} @app.get("/path/{param:path}") -def path_convertor(param: str = Path(...)): +def path_convertor(param: str = Path()): return {"path": param} diff --git a/tests/test_tuples.py b/tests/test_tuples.py index 2085dc367..18ec2d048 100644 --- a/tests/test_tuples.py +++ b/tests/test_tuples.py @@ -27,7 +27,7 @@ def post_tuple_of_models(square: Tuple[Coordinate, Coordinate]): @app.post("/tuple-form/") -def hello(values: Tuple[int, int] = Form(...)): +def hello(values: Tuple[int, int] = Form()): return values From c5be1b0550f17d827721a5be1dc4344e73b1993f Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 13 May 2022 23:39:00 +0000 Subject: [PATCH 558/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5c73818fe..416983bc1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for not needing `...` as default value in required Query(), Path(), Header(), etc.. PR [#4906](https://github.com/tiangolo/fastapi/pull/4906) by [@tiangolo](https://github.com/tiangolo). * 🎨 Fix default value as set in tutorial for Path Operations Advanced Configurations. PR [#4899](https://github.com/tiangolo/fastapi/pull/4899) by [@tiangolo](https://github.com/tiangolo). * ♻ Refactor dict value extraction to minimize key lookups `fastapi/utils.py`. PR [#3139](https://github.com/tiangolo/fastapi/pull/3139) by [@ShahriyarR](https://github.com/ShahriyarR). * 👷 Fix installing Material for MkDocs Insiders in CI. PR [#4897](https://github.com/tiangolo/fastapi/pull/4897) by [@tiangolo](https://github.com/tiangolo). From ca437cdfabe7673b838cf42889ba1c653acd2228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 14 May 2022 06:59:59 -0500 Subject: [PATCH 559/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20docs=20recommendin?= =?UTF-8?q?g=20`Union`=20over=20`Optional`=20and=20migrate=20source=20exam?= =?UTF-8?q?ples=20(#4908)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 📝 Add docs recommending Union over Optional * 📝 Update docs recommending Union over Optional * 📝 Update source examples for docs, recommend Union over Optional * 📝 Update highlighted lines with updated source examples * 📝 Update highlighted lines in Markdown with recent code changes * 📝 Update docs, use Union instead of Optional * ♻️ Update source examples to recommend Union over Optional * 🎨 Update highlighted code in Markdown after moving from Optional to Union --- README.md | 14 +++---- docs/de/docs/index.md | 14 +++---- .../docs/advanced/additional-status-codes.md | 2 +- docs/en/docs/advanced/testing-dependencies.md | 2 +- docs/en/docs/deployment/docker.md | 4 +- docs/en/docs/index.md | 14 +++---- docs/en/docs/python-types.md | 42 +++++++++++++++++++ docs/en/docs/tutorial/body-multiple-params.md | 11 +++-- docs/en/docs/tutorial/body.md | 2 +- .../dependencies/classes-as-dependencies.md | 2 +- docs/en/docs/tutorial/dependencies/index.md | 4 +- .../tutorial/dependencies/sub-dependencies.md | 2 +- .../path-params-numeric-validations.md | 4 +- docs/en/docs/tutorial/response-model.md | 2 +- docs/en/docs/tutorial/schema-extra-example.md | 8 ++-- .../docs/advanced/additional-status-codes.md | 2 +- docs/es/docs/index.md | 14 +++---- docs/es/docs/tutorial/query-params.md | 2 +- docs/fa/docs/index.md | 14 +++---- docs/fr/docs/index.md | 14 +++---- .../docs/advanced/additional-status-codes.md | 2 +- .../tutorial/query-params-str-validations.md | 16 +++---- docs/ko/docs/index.md | 14 +++---- .../path-params-numeric-validations.md | 4 +- docs/ko/docs/tutorial/query-params.md | 2 +- docs/nl/docs/index.md | 14 +++---- docs/pl/docs/index.md | 14 +++---- docs/pt/docs/index.md | 14 ++++--- docs/pt/docs/tutorial/body.md | 2 +- .../tutorial/query-params-str-validations.md | 24 +++++------ docs/ru/docs/index.md | 14 +++---- docs/sq/docs/index.md | 14 +++---- docs/tr/docs/index.md | 14 +++---- docs/uk/docs/index.md | 14 +++---- .../docs/advanced/additional-status-codes.md | 2 +- docs/zh/docs/index.md | 14 +++---- docs/zh/docs/tutorial/body-multiple-params.md | 4 +- docs/zh/docs/tutorial/dependencies/index.md | 4 +- .../tutorial/dependencies/sub-dependencies.md | 2 +- .../path-params-numeric-validations.md | 4 +- .../tutorial/query-params-str-validations.md | 12 +++--- docs/zh/docs/tutorial/response-model.md | 2 +- docs/zh/docs/tutorial/schema-extra-example.md | 2 +- docs_src/additional_responses/tutorial002.py | 4 +- docs_src/additional_responses/tutorial004.py | 4 +- docs_src/background_tasks/tutorial002.py | 4 +- docs_src/body/tutorial001.py | 6 +-- docs_src/body/tutorial002.py | 6 +-- docs_src/body/tutorial003.py | 6 +-- docs_src/body/tutorial004.py | 8 ++-- docs_src/body_multiple_params/tutorial002.py | 8 ++-- docs_src/body_nested_models/tutorial001.py | 6 +-- docs_src/body_nested_models/tutorial002.py | 6 +-- .../body_nested_models/tutorial002_py39.py | 6 +-- docs_src/body_nested_models/tutorial003.py | 6 +-- .../body_nested_models/tutorial003_py39.py | 6 +-- docs_src/body_nested_models/tutorial004.py | 8 ++-- .../body_nested_models/tutorial004_py39.py | 8 ++-- docs_src/body_nested_models/tutorial005.py | 8 ++-- .../body_nested_models/tutorial005_py39.py | 8 ++-- docs_src/body_nested_models/tutorial006.py | 8 ++-- .../body_nested_models/tutorial006_py39.py | 8 ++-- docs_src/body_nested_models/tutorial007.py | 10 ++--- .../body_nested_models/tutorial007_py39.py | 10 ++--- docs_src/body_updates/tutorial001.py | 8 ++-- docs_src/body_updates/tutorial001_py39.py | 8 ++-- docs_src/body_updates/tutorial002.py | 8 ++-- docs_src/body_updates/tutorial002_py39.py | 8 ++-- docs_src/dataclasses/tutorial001.py | 6 +-- docs_src/dataclasses/tutorial002.py | 6 +-- docs_src/dataclasses/tutorial003.py | 4 +- docs_src/dependencies/tutorial001.py | 6 ++- docs_src/dependencies/tutorial002.py | 4 +- docs_src/dependencies/tutorial003.py | 4 +- docs_src/dependencies/tutorial004.py | 4 +- docs_src/dependencies/tutorial005.py | 7 ++-- docs_src/dependency_testing/tutorial001.py | 8 ++-- docs_src/encoder/tutorial001.py | 4 +- docs_src/extra_data_types/tutorial001.py | 10 ++--- docs_src/extra_models/tutorial001.py | 8 ++-- docs_src/extra_models/tutorial002.py | 4 +- docs_src/header_params/tutorial001.py | 4 +- docs_src/header_params/tutorial002.py | 4 +- docs_src/header_params/tutorial003.py | 4 +- docs_src/header_params/tutorial003_py39.py | 4 +- docs_src/nosql_databases/tutorial001.py | 8 ++-- docs_src/openapi_callbacks/tutorial001.py | 6 +-- .../tutorial004.py | 6 +-- .../tutorial001.py | 6 +-- .../tutorial001_py39.py | 6 +-- .../tutorial002.py | 6 +-- .../tutorial002_py39.py | 6 +-- .../tutorial003.py | 6 +-- .../tutorial003_py39.py | 6 +-- .../tutorial004.py | 6 +-- .../tutorial004_py39.py | 6 +-- .../tutorial005.py | 6 +-- .../tutorial005_py39.py | 6 +-- docs_src/python_types/tutorial009c.py | 5 +++ docs_src/python_types/tutorial009c_py310.py | 2 + docs_src/python_types/tutorial011.py | 4 +- docs_src/python_types/tutorial011_py39.py | 4 +- docs_src/python_types/tutorial012.py | 8 ++++ docs_src/query_params/tutorial002.py | 4 +- docs_src/query_params/tutorial003.py | 4 +- docs_src/query_params/tutorial004.py | 4 +- docs_src/query_params/tutorial006.py | 4 +- .../tutorial001.py | 4 +- docs_src/request_files/tutorial001_02.py | 6 +-- docs_src/response_directly/tutorial001.py | 4 +- docs_src/response_model/tutorial001.py | 6 +-- docs_src/response_model/tutorial001_py39.py | 6 +-- docs_src/response_model/tutorial002.py | 4 +- docs_src/response_model/tutorial003.py | 6 +-- docs_src/response_model/tutorial004.py | 4 +- docs_src/response_model/tutorial004_py39.py | 4 +- docs_src/response_model/tutorial005.py | 4 +- docs_src/response_model/tutorial006.py | 4 +- docs_src/schema_extra_example/tutorial001.py | 6 +-- docs_src/schema_extra_example/tutorial002.py | 6 +-- docs_src/schema_extra_example/tutorial003.py | 6 +-- docs_src/schema_extra_example/tutorial004.py | 6 +-- docs_src/security/tutorial002.py | 8 ++-- docs_src/security/tutorial003.py | 8 ++-- docs_src/security/tutorial004.py | 12 +++--- docs_src/security/tutorial005.py | 12 +++--- docs_src/security/tutorial005_py39.py | 12 +++--- docs_src/sql_databases/sql_app/schemas.py | 4 +- .../sql_databases/sql_app_py39/schemas.py | 4 +- .../sql_databases_peewee/sql_app/schemas.py | 4 +- docs_src/websockets/tutorial002.py | 8 ++-- 131 files changed, 489 insertions(+), 426 deletions(-) create mode 100644 docs_src/python_types/tutorial009c.py create mode 100644 docs_src/python_types/tutorial009c_py310.py create mode 100644 docs_src/python_types/tutorial012.py diff --git a/README.md b/README.md index 9ad50f271..5e9e97a2a 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ $ pip install "uvicorn[standard]" * Create a file `main.py` with: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -164,7 +164,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -174,7 +174,7 @@ def read_item(item_id: int, q: Optional[str] = None): If your code uses `async` / `await`, use `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -187,7 +187,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -266,7 +266,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request. Declare the body using standard Python types, thanks to Pydantic. ```Python hl_lines="4 9-12 25-27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -277,7 +277,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -286,7 +286,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/de/docs/index.md b/docs/de/docs/index.md index ce13bcc4a..929754462 100644 --- a/docs/de/docs/index.md +++ b/docs/de/docs/index.md @@ -149,7 +149,7 @@ $ pip install uvicorn[standard] * Create a file `main.py` with: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -162,7 +162,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None): If your code uses `async` / `await`, use `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -185,7 +185,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request. Declare the body using standard Python types, thanks to Pydantic. ```Python hl_lines="4 9-12 25-27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -275,7 +275,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -284,7 +284,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/en/docs/advanced/additional-status-codes.md b/docs/en/docs/advanced/additional-status-codes.md index 37ec283ff..b61f88b93 100644 --- a/docs/en/docs/advanced/additional-status-codes.md +++ b/docs/en/docs/advanced/additional-status-codes.md @@ -14,7 +14,7 @@ But you also want it to accept new items. And when the items didn't exist before To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want: -```Python hl_lines="4 23" +```Python hl_lines="4 25" {!../../../docs_src/additional_status_codes/tutorial001.py!} ``` diff --git a/docs/en/docs/advanced/testing-dependencies.md b/docs/en/docs/advanced/testing-dependencies.md index 79208e8dc..7bba82fb7 100644 --- a/docs/en/docs/advanced/testing-dependencies.md +++ b/docs/en/docs/advanced/testing-dependencies.md @@ -28,7 +28,7 @@ To override a dependency for testing, you put as a key the original dependency ( And then **FastAPI** will call that override instead of the original dependency. -```Python hl_lines="26-27 30" +```Python hl_lines="28-29 32" {!../../../docs_src/dependency_testing/tutorial001.py!} ``` diff --git a/docs/en/docs/deployment/docker.md b/docs/en/docs/deployment/docker.md index 651b0e840..8a542622e 100644 --- a/docs/en/docs/deployment/docker.md +++ b/docs/en/docs/deployment/docker.md @@ -142,7 +142,7 @@ Successfully installed fastapi pydantic uvicorn * Create a `main.py` file with: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -155,7 +155,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index 7de1e50df..17163ba01 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -148,7 +148,7 @@ $ pip install "uvicorn[standard]" * Create a file `main.py` with: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -161,7 +161,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -171,7 +171,7 @@ def read_item(item_id: int, q: Optional[str] = None): If your code uses `async` / `await`, use `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -184,7 +184,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -263,7 +263,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request. Declare the body using standard Python types, thanks to Pydantic. ```Python hl_lines="4 9-12 25-27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -274,7 +274,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -283,7 +283,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index 8486ed849..963fcaf1c 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -317,6 +317,45 @@ This also means that in Python 3.10, you can use `Something | None`: {!> ../../../docs_src/python_types/tutorial009_py310.py!} ``` +#### Using `Union` or `Optional` + +If you are using a Python version below 3.10, here's a tip from my very **subjective** point of view: + +* 🚨 Avoid using `Optional[SomeType]` +* Instead ✨ **use `Union[SomeType, None]`** ✨. + +Both are equivalent and underneath they are the same, but I would recommend `Union` instead of `Optional` because the word "**optional**" would seem to imply that the value is optional, and it actually means "it can be `None`", even if it's not optional and is still required. + +I think `Union[str, SomeType]` is more explicit about what it means. + +It's just about the words and names. But those words can affect how you and your teammates think about the code. + +As an example, let's take this function: + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial009c.py!} +``` + +The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter: + +```Python +say_hi() # Oh, no, this throws an error! 😱 +``` + +The `name` parameter is **still required** (not *optional*) because it doesn't have a default value. Still, `name` accepts `None` as the value: + +```Python +say_hi(name=None) # This works, None is valid 🎉 +``` + +The good news is, once you are on Python 3.10 you won't have to worry about that, as you will be able to simply use `|` to define unions of types: + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial009c_py310.py!} +``` + +And then you won't have to worry about names like `Optional` and `Union`. 😎 + #### Generic types These types that take type parameters in square brackets are called **Generic types** or **Generics**, for example: @@ -422,6 +461,9 @@ An example from the official Pydantic docs: You will see a lot more of all this in practice in the [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}. +!!! tip + Pydantic has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about Required Optional fields. + ## Type hints in **FastAPI** **FastAPI** takes advantage of these type hints to do several things. diff --git a/docs/en/docs/tutorial/body-multiple-params.md b/docs/en/docs/tutorial/body-multiple-params.md index 13de4c8ea..31dd27fed 100644 --- a/docs/en/docs/tutorial/body-multiple-params.md +++ b/docs/en/docs/tutorial/body-multiple-params.md @@ -89,13 +89,13 @@ But you can instruct **FastAPI** to treat it as another body key using `Body`: === "Python 3.6 and above" - ```Python hl_lines="23" + ```Python hl_lines="22" {!> ../../../docs_src/body_multiple_params/tutorial003.py!} ``` === "Python 3.10 and above" - ```Python hl_lines="21" + ```Python hl_lines="20" {!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!} ``` @@ -126,7 +126,7 @@ Of course, you can also declare additional query parameters whenever you need, a As, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do: ```Python -q: Optional[str] = None +q: Union[str, None] = None ``` Or in Python 3.10 and above: @@ -139,7 +139,7 @@ For example: === "Python 3.6 and above" - ```Python hl_lines="28" + ```Python hl_lines="27" {!> ../../../docs_src/body_multiple_params/tutorial004.py!} ``` @@ -152,7 +152,6 @@ For example: !!! info `Body` also has all the same extra validation and metadata parameters as `Query`,`Path` and others you will see later. - ## Embed a single body parameter Let's say you only have a single `item` body parameter from a Pydantic model `Item`. @@ -162,7 +161,7 @@ By default, **FastAPI** will then expect its body directly. But if you want it to expect a JSON with a key `item` and inside of it the model contents, as it does when you declare extra body parameters, you can use the special `Body` parameter `embed`: ```Python -item: Item = Body(..., embed=True) +item: Item = Body(embed=True) ``` as in: diff --git a/docs/en/docs/tutorial/body.md b/docs/en/docs/tutorial/body.md index eb21f29a8..509005936 100644 --- a/docs/en/docs/tutorial/body.md +++ b/docs/en/docs/tutorial/body.md @@ -206,7 +206,7 @@ The function parameters will be recognized as follows: !!! note FastAPI will know that the value of `q` is not required because of the default value `= None`. - The `Optional` in `Optional[str]` is not used by FastAPI, but will allow your editor to give you better support and detect errors. + The `Union` in `Union[str, None]` is not used by FastAPI, but will allow your editor to give you better support and detect errors. ## Without Pydantic diff --git a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md index 663fff15b..fb41ba1f6 100644 --- a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md @@ -109,7 +109,7 @@ Pay attention to the `__init__` method used to create the instance of the class: === "Python 3.6 and above" - ```Python hl_lines="8" + ```Python hl_lines="9" {!> ../../../docs_src/dependencies/tutorial001.py!} ``` diff --git a/docs/en/docs/tutorial/dependencies/index.md b/docs/en/docs/tutorial/dependencies/index.md index fe10facfb..5078c0096 100644 --- a/docs/en/docs/tutorial/dependencies/index.md +++ b/docs/en/docs/tutorial/dependencies/index.md @@ -33,7 +33,7 @@ It is just a function that can take all the same parameters that a *path operati === "Python 3.6 and above" - ```Python hl_lines="8-9" + ```Python hl_lines="8-11" {!> ../../../docs_src/dependencies/tutorial001.py!} ``` @@ -81,7 +81,7 @@ The same way you use `Body`, `Query`, etc. with your *path operation function* p === "Python 3.6 and above" - ```Python hl_lines="13 18" + ```Python hl_lines="15 20" {!> ../../../docs_src/dependencies/tutorial001.py!} ``` diff --git a/docs/en/docs/tutorial/dependencies/sub-dependencies.md b/docs/en/docs/tutorial/dependencies/sub-dependencies.md index 51531228d..a5b40c9ad 100644 --- a/docs/en/docs/tutorial/dependencies/sub-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/sub-dependencies.md @@ -55,7 +55,7 @@ Then we can use the dependency with: === "Python 3.6 and above" - ```Python hl_lines="21" + ```Python hl_lines="22" {!> ../../../docs_src/dependencies/tutorial005.py!} ``` diff --git a/docs/en/docs/tutorial/path-params-numeric-validations.md b/docs/en/docs/tutorial/path-params-numeric-validations.md index 31bf91a0e..29235c6e2 100644 --- a/docs/en/docs/tutorial/path-params-numeric-validations.md +++ b/docs/en/docs/tutorial/path-params-numeric-validations.md @@ -59,7 +59,7 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names, So, you can declare your function as: -```Python hl_lines="8" +```Python hl_lines="7" {!../../../docs_src/path_params_numeric_validations/tutorial002.py!} ``` @@ -71,7 +71,7 @@ Pass `*`, as the first parameter of the function. Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as kwargs. Even if they don't have a default value. -```Python hl_lines="8" +```Python hl_lines="7" {!../../../docs_src/path_params_numeric_validations/tutorial003.py!} ``` diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md index c751a9256..e371e86e4 100644 --- a/docs/en/docs/tutorial/response-model.md +++ b/docs/en/docs/tutorial/response-model.md @@ -162,7 +162,7 @@ Your response model could have default values, like: {!> ../../../docs_src/response_model/tutorial004_py310.py!} ``` -* `description: Optional[str] = None` has a default of `None`. +* `description: Union[str, None] = None` has a default of `None`. * `tax: float = 10.5` has a default of `10.5`. * `tags: List[str] = []` as a default of an empty list: `[]`. diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md index c69df51dc..94347018d 100644 --- a/docs/en/docs/tutorial/schema-extra-example.md +++ b/docs/en/docs/tutorial/schema-extra-example.md @@ -68,13 +68,13 @@ Here we pass an `example` of the data expected in `Body()`: === "Python 3.6 and above" - ```Python hl_lines="21-26" + ```Python hl_lines="20-25" {!> ../../../docs_src/schema_extra_example/tutorial003.py!} ``` === "Python 3.10 and above" - ```Python hl_lines="19-24" + ```Python hl_lines="18-23" {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!} ``` @@ -99,13 +99,13 @@ Each specific example `dict` in the `examples` can contain: === "Python 3.6 and above" - ```Python hl_lines="22-48" + ```Python hl_lines="21-47" {!> ../../../docs_src/schema_extra_example/tutorial004.py!} ``` === "Python 3.10 and above" - ```Python hl_lines="20-46" + ```Python hl_lines="19-45" {!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!} ``` diff --git a/docs/es/docs/advanced/additional-status-codes.md b/docs/es/docs/advanced/additional-status-codes.md index 67224fb36..1f28ea85b 100644 --- a/docs/es/docs/advanced/additional-status-codes.md +++ b/docs/es/docs/advanced/additional-status-codes.md @@ -14,7 +14,7 @@ Pero también quieres que acepte nuevos ítems. Cuando los ítems no existan ant Para conseguir esto importa `JSONResponse` y devuelve ahí directamente tu contenido, asignando el `status_code` que quieras: -```Python hl_lines="2 19" +```Python hl_lines="4 25" {!../../../docs_src/additional_status_codes/tutorial001.py!} ``` diff --git a/docs/es/docs/index.md b/docs/es/docs/index.md index 1fa79fdde..ef4850b56 100644 --- a/docs/es/docs/index.md +++ b/docs/es/docs/index.md @@ -145,7 +145,7 @@ $ pip install uvicorn[standard] ```Python from fastapi import FastAPI -from typing import Optional +from typing import Union app = FastAPI() @@ -156,7 +156,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -167,7 +167,7 @@ Si tu código usa `async` / `await`, usa `async def`: ```Python hl_lines="7 12" from fastapi import FastAPI -from typing import Optional +from typing import Union app = FastAPI() @@ -178,7 +178,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -259,7 +259,7 @@ Declara el body usando las declaraciones de tipo estándares de Python gracias a ```Python hl_lines="2 7-10 23-25" from fastapi import FastAPI from pydantic import BaseModel -from typing import Optional +from typing import Union app = FastAPI() @@ -267,7 +267,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -276,7 +276,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/es/docs/tutorial/query-params.md b/docs/es/docs/tutorial/query-params.md index 69caee6e8..482af8dc0 100644 --- a/docs/es/docs/tutorial/query-params.md +++ b/docs/es/docs/tutorial/query-params.md @@ -75,7 +75,7 @@ En este caso el parámetro de la función `q` será opcional y será `None` por !!! note "Nota" FastAPI sabrá que `q` es opcional por el `= None`. - El `Optional` en `Optional[str]` no es usado por FastAPI (FastAPI solo usará la parte `str`), pero el `Optional[str]` le permitirá a tu editor ayudarte a encontrar errores en tu código. + El `Union` en `Union[str, None]` no es usado por FastAPI (FastAPI solo usará la parte `str`), pero el `Union[str, None]` le permitirá a tu editor ayudarte a encontrar errores en tu código. ## Conversión de tipos de parámetros de query diff --git a/docs/fa/docs/index.md b/docs/fa/docs/index.md index 0070de179..fd52f994c 100644 --- a/docs/fa/docs/index.md +++ b/docs/fa/docs/index.md @@ -152,7 +152,7 @@ $ pip install "uvicorn[standard]" * Create a file `main.py` with: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -165,7 +165,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -175,7 +175,7 @@ def read_item(item_id: int, q: Optional[str] = None): If your code uses `async` / `await`, use `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -188,7 +188,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -267,7 +267,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request. Declare the body using standard Python types, thanks to Pydantic. ```Python hl_lines="4 9-12 25-27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -278,7 +278,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -287,7 +287,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md index 0b537054e..f713ee96b 100644 --- a/docs/fr/docs/index.md +++ b/docs/fr/docs/index.md @@ -149,7 +149,7 @@ $ pip install uvicorn[standard] * Create a file `main.py` with: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -162,7 +162,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None): If your code uses `async` / `await`, use `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -185,7 +185,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request. Declare the body using standard Python types, thanks to Pydantic. ```Python hl_lines="4 9 10 11 12 25 26 27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -275,7 +275,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -284,7 +284,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/ja/docs/advanced/additional-status-codes.md b/docs/ja/docs/advanced/additional-status-codes.md index 6c03cd92b..d1f8e6451 100644 --- a/docs/ja/docs/advanced/additional-status-codes.md +++ b/docs/ja/docs/advanced/additional-status-codes.md @@ -14,7 +14,7 @@ これを達成するには、 `JSONResponse` をインポートし、 `status_code` を設定して直接内容を返します。 -```Python hl_lines="4 23" +```Python hl_lines="4 25" {!../../../docs_src/additional_status_codes/tutorial001.py!} ``` diff --git a/docs/ja/docs/tutorial/query-params-str-validations.md b/docs/ja/docs/tutorial/query-params-str-validations.md index ff0af725f..8d375d7ce 100644 --- a/docs/ja/docs/tutorial/query-params-str-validations.md +++ b/docs/ja/docs/tutorial/query-params-str-validations.md @@ -34,12 +34,12 @@ {!../../../docs_src/query_params_str_validations/tutorial002.py!} ``` -デフォルト値`None`を`Query(None)`に置き換える必要があるので、`Query`の最初の引数はデフォルト値を定義するのと同じです。 +デフォルト値`None`を`Query(default=None)`に置き換える必要があるので、`Query`の最初の引数はデフォルト値を定義するのと同じです。 なので: ```Python -q: Optional[str] = Query(None) +q: Optional[str] = Query(default=None) ``` ...を以下と同じようにパラメータをオプションにします: @@ -60,7 +60,7 @@ q: Optional[str] = None もしくは: ```Python - = Query(None) + = Query(default=None) ``` そして、 `None` を利用することでクエリパラメータが必須ではないと検知します。 @@ -70,7 +70,7 @@ q: Optional[str] = None そして、さらに多くのパラメータを`Query`に渡すことができます。この場合、文字列に適用される、`max_length`パラメータを指定します。 ```Python -q: str = Query(None, max_length=50) +q: Union[str, None] = Query(default=None, max_length=50) ``` これにより、データを検証し、データが有効でない場合は明確なエラーを表示し、OpenAPIスキーマの *path operation* にパラメータを記載します。 @@ -79,7 +79,7 @@ q: str = Query(None, max_length=50) パラメータ`min_length`も追加することができます: -```Python hl_lines="9" +```Python hl_lines="10" {!../../../docs_src/query_params_str_validations/tutorial003.py!} ``` @@ -87,7 +87,7 @@ q: str = Query(None, max_length=50) パラメータが一致するべき正規表現を定義することができます: -```Python hl_lines="10" +```Python hl_lines="11" {!../../../docs_src/query_params_str_validations/tutorial004.py!} ``` @@ -125,13 +125,13 @@ q: str 以下の代わりに: ```Python -q: Optional[str] = None +q: Union[str, None] = None ``` 現在は以下の例のように`Query`で宣言しています: ```Python -q: Optional[str] = Query(None, min_length=3) +q: Union[str, None] = Query(default=None, min_length=3) ``` そのため、`Query`を使用して必須の値を宣言する必要がある場合は、第一引数に`...`を使用することができます: diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md index 284628955..ec4422994 100644 --- a/docs/ko/docs/index.md +++ b/docs/ko/docs/index.md @@ -145,7 +145,7 @@ $ pip install uvicorn[standard] * `main.py` 파일을 만드십시오: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -158,7 +158,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -168,7 +168,7 @@ def read_item(item_id: int, q: Optional[str] = None): 여러분의 코드가 `async` / `await`을 사용한다면, `async def`를 사용하십시오. ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -181,7 +181,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -260,7 +260,7 @@ INFO: Application startup complete. Pydantic을 이용해 파이썬 표준 타입으로 본문을 선언합니다. ```Python hl_lines="4 9 10 11 12 25 26 27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -271,7 +271,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -280,7 +280,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/ko/docs/tutorial/path-params-numeric-validations.md b/docs/ko/docs/tutorial/path-params-numeric-validations.md index abb9d03db..cadf543fc 100644 --- a/docs/ko/docs/tutorial/path-params-numeric-validations.md +++ b/docs/ko/docs/tutorial/path-params-numeric-validations.md @@ -43,7 +43,7 @@ 따라서 함수를 다음과 같이 선언 할 수 있습니다: -```Python hl_lines="8" +```Python hl_lines="7" {!../../../docs_src/path_params_numeric_validations/tutorial002.py!} ``` @@ -55,7 +55,7 @@ 파이썬은 `*`으로 아무런 행동도 하지 않지만, 따르는 매개변수들은 kwargs로도 알려진 키워드 인자(키-값 쌍)여야 함을 인지합니다. 기본값을 가지고 있지 않더라도 그렇습니다. -```Python hl_lines="8" +```Python hl_lines="7" {!../../../docs_src/path_params_numeric_validations/tutorial003.py!} ``` diff --git a/docs/ko/docs/tutorial/query-params.md b/docs/ko/docs/tutorial/query-params.md index 05f2ff9c9..bb631e6ff 100644 --- a/docs/ko/docs/tutorial/query-params.md +++ b/docs/ko/docs/tutorial/query-params.md @@ -75,7 +75,7 @@ http://127.0.0.1:8000/items/?skip=20 !!! note "참고" FastAPI는 `q`가 `= None`이므로 선택적이라는 것을 인지합니다. - `Optional[str]`에 있는 `Optional`은 FastAPI(FastAPI는 `str` 부분만 사용합니다)가 사용하는게 아니지만, `Optional[str]`은 편집기에게 코드에서 오류를 찾아낼 수 있게 도와줍니다. + `Union[str, None]`에 있는 `Union`은 FastAPI(FastAPI는 `str` 부분만 사용합니다)가 사용하는게 아니지만, `Union[str, None]`은 편집기에게 코드에서 오류를 찾아낼 수 있게 도와줍니다. ## 쿼리 매개변수 형변환 diff --git a/docs/nl/docs/index.md b/docs/nl/docs/index.md index 0070de179..fd52f994c 100644 --- a/docs/nl/docs/index.md +++ b/docs/nl/docs/index.md @@ -152,7 +152,7 @@ $ pip install "uvicorn[standard]" * Create a file `main.py` with: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -165,7 +165,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -175,7 +175,7 @@ def read_item(item_id: int, q: Optional[str] = None): If your code uses `async` / `await`, use `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -188,7 +188,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -267,7 +267,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request. Declare the body using standard Python types, thanks to Pydantic. ```Python hl_lines="4 9-12 25-27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -278,7 +278,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -287,7 +287,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/pl/docs/index.md b/docs/pl/docs/index.md index 4a300ae63..bbe1b1ad1 100644 --- a/docs/pl/docs/index.md +++ b/docs/pl/docs/index.md @@ -144,7 +144,7 @@ $ pip install uvicorn[standard] * Utwórz plik o nazwie `main.py` z: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -157,7 +157,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -167,7 +167,7 @@ def read_item(item_id: int, q: Optional[str] = None): Jeżeli twój kod korzysta z `async` / `await`, użyj `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -180,7 +180,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -258,7 +258,7 @@ Zmodyfikuj teraz plik `main.py`, aby otrzmywał treść (body) żądania `PUT`. Zadeklaruj treść żądania, używając standardowych typów w Pythonie dzięki Pydantic. ```Python hl_lines="4 9-12 25-27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -269,7 +269,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -278,7 +278,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md index c1a0dbf0d..b1d0c89f2 100644 --- a/docs/pt/docs/index.md +++ b/docs/pt/docs/index.md @@ -138,7 +138,7 @@ $ pip install uvicorn[standard] * Crie um arquivo `main.py` com: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -151,7 +151,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -161,7 +161,7 @@ def read_item(item_id: int, q: Optional[str] = None): Se seu código utiliza `async` / `await`, use `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -174,7 +174,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -253,6 +253,8 @@ Agora modifique o arquivo `main.py` para receber um corpo para uma requisição Declare o corpo utilizando tipos padrão Python, graças ao Pydantic. ```Python hl_lines="4 9-12 25-27" +from typing import Union + from fastapi import FastAPI from pydantic import BaseModel @@ -262,7 +264,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool] = None @app.get("/") @@ -271,7 +273,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/pt/docs/tutorial/body.md b/docs/pt/docs/tutorial/body.md index 5abc91177..99e05ab77 100644 --- a/docs/pt/docs/tutorial/body.md +++ b/docs/pt/docs/tutorial/body.md @@ -158,7 +158,7 @@ Os parâmetros da função serão reconhecidos conforme abaixo: !!! note "Observação" O FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`. - O `Optional` em `Optional[str]` não é utilizado pelo FastAPI, mas permite ao seu editor de texto lhe dar um suporte melhor e detectar erros. + O `Union` em `Union[str, None]` não é utilizado pelo FastAPI, mas permite ao seu editor de texto lhe dar um suporte melhor e detectar erros. ## Sem o Pydantic diff --git a/docs/pt/docs/tutorial/query-params-str-validations.md b/docs/pt/docs/tutorial/query-params-str-validations.md index baac5f493..9a9e071db 100644 --- a/docs/pt/docs/tutorial/query-params-str-validations.md +++ b/docs/pt/docs/tutorial/query-params-str-validations.md @@ -8,12 +8,12 @@ Vamos utilizar essa aplicação como exemplo: {!../../../docs_src/query_params_str_validations/tutorial001.py!} ``` -O parâmetro de consulta `q` é do tipo `Optional[str]`, o que significa que é do tipo `str` mas que também pode ser `None`, e de fato, o valor padrão é `None`, então o FastAPI saberá que não é obrigatório. +O parâmetro de consulta `q` é do tipo `Union[str, None]`, o que significa que é do tipo `str` mas que também pode ser `None`, e de fato, o valor padrão é `None`, então o FastAPI saberá que não é obrigatório. !!! note "Observação" O FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`. - O `Optional` em `Optional[str]` não é usado pelo FastAPI, mas permitirá que seu editor lhe dê um melhor suporte e detecte erros. + O `Union` em `Union[str, None]` não é usado pelo FastAPI, mas permitirá que seu editor lhe dê um melhor suporte e detecte erros. ## Validação adicional @@ -35,18 +35,18 @@ Agora utilize-o como valor padrão do seu parâmetro, definindo o parâmetro `ma {!../../../docs_src/query_params_str_validations/tutorial002.py!} ``` -Note que substituímos o valor padrão de `None` para `Query(None)`, o primeiro parâmetro de `Query` serve para o mesmo propósito: definir o valor padrão do parâmetro. +Note que substituímos o valor padrão de `None` para `Query(default=None)`, o primeiro parâmetro de `Query` serve para o mesmo propósito: definir o valor padrão do parâmetro. Então: ```Python -q: Optional[str] = Query(None) +q: Union[str, None] = Query(default=None) ``` ...Torna o parâmetro opcional, da mesma maneira que: ```Python -q: Optional[str] = None +q: Union[str, None] = None ``` Mas o declara explicitamente como um parâmetro de consulta. @@ -61,17 +61,17 @@ Mas o declara explicitamente como um parâmetro de consulta. Ou com: ```Python - = Query(None) + = Query(default=None) ``` E irá utilizar o `None` para detectar que o parâmetro de consulta não é obrigatório. - O `Optional` é apenas para permitir que seu editor de texto lhe dê um melhor suporte. + O `Union` é apenas para permitir que seu editor de texto lhe dê um melhor suporte. Então, podemos passar mais parâmetros para `Query`. Neste caso, o parâmetro `max_length` que se aplica a textos: ```Python -q: str = Query(None, max_length=50) +q: str = Query(default=None, max_length=50) ``` Isso irá validar os dados, mostrar um erro claro quando os dados forem inválidos, e documentar o parâmetro na *operação de rota* do esquema OpenAPI.. @@ -80,7 +80,7 @@ Isso irá validar os dados, mostrar um erro claro quando os dados forem inválid Você também pode incluir um parâmetro `min_length`: -```Python hl_lines="9" +```Python hl_lines="10" {!../../../docs_src/query_params_str_validations/tutorial003.py!} ``` @@ -88,7 +88,7 @@ Você também pode incluir um parâmetro `min_length`: Você pode definir uma expressão regular que combine com um padrão esperado pelo parâmetro: -```Python hl_lines="10" +```Python hl_lines="11" {!../../../docs_src/query_params_str_validations/tutorial004.py!} ``` @@ -126,13 +126,13 @@ q: str em vez desta: ```Python -q: Optional[str] = None +q: Union[str, None] = None ``` Mas agora nós o estamos declarando como `Query`, conforme abaixo: ```Python -q: Optional[str] = Query(None, min_length=3) +q: Union[str, None] = Query(default=None, min_length=3) ``` Então, quando você precisa declarar um parâmetro obrigatório utilizando o `Query`, você pode utilizar `...` como o primeiro argumento: diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index a1d302276..9a3957d5f 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -149,7 +149,7 @@ $ pip install uvicorn[standard] * Create a file `main.py` with: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -162,7 +162,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None): If your code uses `async` / `await`, use `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -185,7 +185,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request. Declare the body using standard Python types, thanks to Pydantic. ```Python hl_lines="4 9-12 25-27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -275,7 +275,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -284,7 +284,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/sq/docs/index.md b/docs/sq/docs/index.md index 0bb7b55e3..29f92e020 100644 --- a/docs/sq/docs/index.md +++ b/docs/sq/docs/index.md @@ -149,7 +149,7 @@ $ pip install uvicorn[standard] * Create a file `main.py` with: ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -162,7 +162,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None): If your code uses `async` / `await`, use `async def`: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -185,7 +185,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request. Declare the body using standard Python types, thanks to Pydantic. ```Python hl_lines="4 9-12 25-27" -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -275,7 +275,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Optional[bool] = None + is_offer: Union[bool, None] = None @app.get("/") @@ -284,7 +284,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md index 3195cd440..5693029b5 100644 --- a/docs/tr/docs/index.md +++ b/docs/tr/docs/index.md @@ -157,7 +157,7 @@ $ pip install uvicorn[standard] * `main.py` adında bir dosya oluştur : ```Python -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -170,7 +170,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -180,7 +180,7 @@ def read_item(item_id: int, q: Optional[str] = None): Eğer kodunda `async` / `await` var ise, `async def` kullan: ```Python hl_lines="9 14" -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -193,7 +193,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Optional[str] = None): +async def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q} ``` @@ -272,7 +272,7 @@ Senin için alternatif olarak (kwargs,来调用。即使它们没有默认值。 -```Python hl_lines="8" +```Python hl_lines="7" {!../../../docs_src/path_params_numeric_validations/tutorial003.py!} ``` diff --git a/docs/zh/docs/tutorial/query-params-str-validations.md b/docs/zh/docs/tutorial/query-params-str-validations.md index 1d1d383d4..0b2b9446a 100644 --- a/docs/zh/docs/tutorial/query-params-str-validations.md +++ b/docs/zh/docs/tutorial/query-params-str-validations.md @@ -30,12 +30,12 @@ {!../../../docs_src/query_params_str_validations/tutorial002.py!} ``` -由于我们必须用 `Query(None)` 替换默认值 `None`,`Query` 的第一个参数同样也是用于定义默认值。 +由于我们必须用 `Query(default=None)` 替换默认值 `None`,`Query` 的第一个参数同样也是用于定义默认值。 所以: ```Python -q: str = Query(None) +q: Union[str, None] = Query(default=None) ``` ...使得参数可选,等同于: @@ -49,7 +49,7 @@ q: str = None 然后,我们可以将更多的参数传递给 `Query`。在本例中,适用于字符串的 `max_length` 参数: ```Python -q: str = Query(None, max_length=50) +q: Union[str, None] = Query(default=None, max_length=50) ``` 将会校验数据,在数据无效时展示清晰的错误信息,并在 OpenAPI 模式的*路径操作*中记录该参​​数。 @@ -58,7 +58,7 @@ q: str = Query(None, max_length=50) 你还可以添加 `min_length` 参数: -```Python hl_lines="9" +```Python hl_lines="10" {!../../../docs_src/query_params_str_validations/tutorial003.py!} ``` @@ -66,7 +66,7 @@ q: str = Query(None, max_length=50) 你可以定义一个参数值必须匹配的正则表达式: -```Python hl_lines="10" +```Python hl_lines="11" {!../../../docs_src/query_params_str_validations/tutorial004.py!} ``` @@ -110,7 +110,7 @@ q: str = None 但是现在我们正在用 `Query` 声明它,例如: ```Python -q: str = Query(None, min_length=3) +q: Union[str, None] = Query(default=None, min_length=3) ``` 因此,当你在使用 `Query` 且需要声明一个值是必需的时,可以将 `...` 用作第一个参数值: diff --git a/docs/zh/docs/tutorial/response-model.md b/docs/zh/docs/tutorial/response-model.md index 59a7c17d5..ea3d0666d 100644 --- a/docs/zh/docs/tutorial/response-model.md +++ b/docs/zh/docs/tutorial/response-model.md @@ -94,7 +94,7 @@ FastAPI 将使用此 `response_model` 来: {!../../../docs_src/response_model/tutorial004.py!} ``` -* `description: Optional[str] = None` 具有默认值 `None`。 +* `description: Union[str, None] = None` 具有默认值 `None`。 * `tax: float = 10.5` 具有默认值 `10.5`. * `tags: List[str] = []` 具有一个空列表作为默认值: `[]`. diff --git a/docs/zh/docs/tutorial/schema-extra-example.md b/docs/zh/docs/tutorial/schema-extra-example.md index 6482366b0..8f5fbfe70 100644 --- a/docs/zh/docs/tutorial/schema-extra-example.md +++ b/docs/zh/docs/tutorial/schema-extra-example.md @@ -33,7 +33,7 @@ 比如,你可以将请求体的一个 `example` 传递给 `Body`: -```Python hl_lines="21-26" +```Python hl_lines="20-25" {!../../../docs_src/schema_extra_example/tutorial003.py!} ``` diff --git a/docs_src/additional_responses/tutorial002.py b/docs_src/additional_responses/tutorial002.py index a46e95959..bd0c95704 100644 --- a/docs_src/additional_responses/tutorial002.py +++ b/docs_src/additional_responses/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from fastapi.responses import FileResponse @@ -23,7 +23,7 @@ app = FastAPI() } }, ) -async def read_item(item_id: str, img: Optional[bool] = None): +async def read_item(item_id: str, img: Union[bool, None] = None): if img: return FileResponse("image.png", media_type="image/png") else: diff --git a/docs_src/additional_responses/tutorial004.py b/docs_src/additional_responses/tutorial004.py index 361aecb8e..978bc18c1 100644 --- a/docs_src/additional_responses/tutorial004.py +++ b/docs_src/additional_responses/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from fastapi.responses import FileResponse @@ -25,7 +25,7 @@ app = FastAPI() response_model=Item, responses={**responses, 200: {"content": {"image/png": {}}}}, ) -async def read_item(item_id: str, img: Optional[bool] = None): +async def read_item(item_id: str, img: Union[bool, None] = None): if img: return FileResponse("image.png", media_type="image/png") else: diff --git a/docs_src/background_tasks/tutorial002.py b/docs_src/background_tasks/tutorial002.py index e7517e8cd..2e1b2f6c6 100644 --- a/docs_src/background_tasks/tutorial002.py +++ b/docs_src/background_tasks/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import BackgroundTasks, Depends, FastAPI @@ -10,7 +10,7 @@ def write_log(message: str): log.write(message) -def get_query(background_tasks: BackgroundTasks, q: Optional[str] = None): +def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None): if q: message = f"found query: {q}\n" background_tasks.add_task(write_log, message) diff --git a/docs_src/body/tutorial001.py b/docs_src/body/tutorial001.py index 52144bd2b..f93317274 100644 --- a/docs_src/body/tutorial001.py +++ b/docs_src/body/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -6,9 +6,9 @@ from pydantic import BaseModel class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None app = FastAPI() diff --git a/docs_src/body/tutorial002.py b/docs_src/body/tutorial002.py index 644fabae9..7f5183908 100644 --- a/docs_src/body/tutorial002.py +++ b/docs_src/body/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -6,9 +6,9 @@ from pydantic import BaseModel class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None app = FastAPI() diff --git a/docs_src/body/tutorial003.py b/docs_src/body/tutorial003.py index c99ea694b..89a6b833c 100644 --- a/docs_src/body/tutorial003.py +++ b/docs_src/body/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -6,9 +6,9 @@ from pydantic import BaseModel class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None app = FastAPI() diff --git a/docs_src/body/tutorial004.py b/docs_src/body/tutorial004.py index 7a222a390..e2df0df2b 100644 --- a/docs_src/body/tutorial004.py +++ b/docs_src/body/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -6,16 +6,16 @@ from pydantic import BaseModel class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None app = FastAPI() @app.put("/items/{item_id}") -async def create_item(item_id: int, item: Item, q: Optional[str] = None): +async def create_item(item_id: int, item: Item, q: Union[str, None] = None): result = {"item_id": item_id, **item.dict()} if q: result.update({"q": q}) diff --git a/docs_src/body_multiple_params/tutorial002.py b/docs_src/body_multiple_params/tutorial002.py index 6b8748420..2d7160ae8 100644 --- a/docs_src/body_multiple_params/tutorial002.py +++ b/docs_src/body_multiple_params/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,14 +8,14 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None class User(BaseModel): username: str - full_name: Optional[str] = None + full_name: Union[str, None] = None @app.put("/items/{item_id}") diff --git a/docs_src/body_nested_models/tutorial001.py b/docs_src/body_nested_models/tutorial001.py index fe14fdf93..37ef6dda5 100644 --- a/docs_src/body_nested_models/tutorial001.py +++ b/docs_src/body_nested_models/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: list = [] diff --git a/docs_src/body_nested_models/tutorial002.py b/docs_src/body_nested_models/tutorial002.py index 1770516a4..155cff788 100644 --- a/docs_src/body_nested_models/tutorial002.py +++ b/docs_src/body_nested_models/tutorial002.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: List[str] = [] diff --git a/docs_src/body_nested_models/tutorial002_py39.py b/docs_src/body_nested_models/tutorial002_py39.py index af523a74e..8a93a7233 100644 --- a/docs_src/body_nested_models/tutorial002_py39.py +++ b/docs_src/body_nested_models/tutorial002_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: list[str] = [] diff --git a/docs_src/body_nested_models/tutorial003.py b/docs_src/body_nested_models/tutorial003.py index 33dbbe3a9..84ed18bf4 100644 --- a/docs_src/body_nested_models/tutorial003.py +++ b/docs_src/body_nested_models/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Set, Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() diff --git a/docs_src/body_nested_models/tutorial003_py39.py b/docs_src/body_nested_models/tutorial003_py39.py index 931d92f88..b590ece36 100644 --- a/docs_src/body_nested_models/tutorial003_py39.py +++ b/docs_src/body_nested_models/tutorial003_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() diff --git a/docs_src/body_nested_models/tutorial004.py b/docs_src/body_nested_models/tutorial004.py index 311a4e73f..a07bfacac 100644 --- a/docs_src/body_nested_models/tutorial004.py +++ b/docs_src/body_nested_models/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Set, Union from fastapi import FastAPI from pydantic import BaseModel @@ -13,11 +13,11 @@ class Image(BaseModel): class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() - image: Optional[Image] = None + image: Union[Image, None] = None @app.put("/items/{item_id}") diff --git a/docs_src/body_nested_models/tutorial004_py39.py b/docs_src/body_nested_models/tutorial004_py39.py index ab05da023..dc2b175fb 100644 --- a/docs_src/body_nested_models/tutorial004_py39.py +++ b/docs_src/body_nested_models/tutorial004_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -13,11 +13,11 @@ class Image(BaseModel): class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() - image: Optional[Image] = None + image: Union[Image, None] = None @app.put("/items/{item_id}") diff --git a/docs_src/body_nested_models/tutorial005.py b/docs_src/body_nested_models/tutorial005.py index e76498c3b..5a01264ed 100644 --- a/docs_src/body_nested_models/tutorial005.py +++ b/docs_src/body_nested_models/tutorial005.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Set, Union from fastapi import FastAPI from pydantic import BaseModel, HttpUrl @@ -13,11 +13,11 @@ class Image(BaseModel): class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() - image: Optional[Image] = None + image: Union[Image, None] = None @app.put("/items/{item_id}") diff --git a/docs_src/body_nested_models/tutorial005_py39.py b/docs_src/body_nested_models/tutorial005_py39.py index 504551883..47db90008 100644 --- a/docs_src/body_nested_models/tutorial005_py39.py +++ b/docs_src/body_nested_models/tutorial005_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel, HttpUrl @@ -13,11 +13,11 @@ class Image(BaseModel): class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() - image: Optional[Image] = None + image: Union[Image, None] = None @app.put("/items/{item_id}") diff --git a/docs_src/body_nested_models/tutorial006.py b/docs_src/body_nested_models/tutorial006.py index da7836715..75f1f30e3 100644 --- a/docs_src/body_nested_models/tutorial006.py +++ b/docs_src/body_nested_models/tutorial006.py @@ -1,4 +1,4 @@ -from typing import List, Optional, Set +from typing import List, Set, Union from fastapi import FastAPI from pydantic import BaseModel, HttpUrl @@ -13,11 +13,11 @@ class Image(BaseModel): class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() - images: Optional[List[Image]] = None + images: Union[List[Image], None] = None @app.put("/items/{item_id}") diff --git a/docs_src/body_nested_models/tutorial006_py39.py b/docs_src/body_nested_models/tutorial006_py39.py index 61898178e..b14409703 100644 --- a/docs_src/body_nested_models/tutorial006_py39.py +++ b/docs_src/body_nested_models/tutorial006_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel, HttpUrl @@ -13,11 +13,11 @@ class Image(BaseModel): class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() - images: Optional[list[Image]] = None + images: Union[list[Image], None] = None @app.put("/items/{item_id}") diff --git a/docs_src/body_nested_models/tutorial007.py b/docs_src/body_nested_models/tutorial007.py index dfbbeaab1..641f09dce 100644 --- a/docs_src/body_nested_models/tutorial007.py +++ b/docs_src/body_nested_models/tutorial007.py @@ -1,4 +1,4 @@ -from typing import List, Optional, Set +from typing import List, Set, Union from fastapi import FastAPI from pydantic import BaseModel, HttpUrl @@ -13,16 +13,16 @@ class Image(BaseModel): class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() - images: Optional[List[Image]] = None + images: Union[List[Image], None] = None class Offer(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float items: List[Item] diff --git a/docs_src/body_nested_models/tutorial007_py39.py b/docs_src/body_nested_models/tutorial007_py39.py index 0c7d32fbb..59cf01e23 100644 --- a/docs_src/body_nested_models/tutorial007_py39.py +++ b/docs_src/body_nested_models/tutorial007_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel, HttpUrl @@ -13,16 +13,16 @@ class Image(BaseModel): class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() - images: Optional[list[Image]] = None + images: Union[list[Image], None] = None class Offer(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float items: list[Item] diff --git a/docs_src/body_updates/tutorial001.py b/docs_src/body_updates/tutorial001.py index 9b8f3ccf1..4e65d77e2 100644 --- a/docs_src/body_updates/tutorial001.py +++ b/docs_src/body_updates/tutorial001.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Union from fastapi import FastAPI from fastapi.encoders import jsonable_encoder @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): - name: Optional[str] = None - description: Optional[str] = None - price: Optional[float] = None + name: Union[str, None] = None + description: Union[str, None] = None + price: Union[float, None] = None tax: float = 10.5 tags: List[str] = [] diff --git a/docs_src/body_updates/tutorial001_py39.py b/docs_src/body_updates/tutorial001_py39.py index 5d5388b56..999bcdb82 100644 --- a/docs_src/body_updates/tutorial001_py39.py +++ b/docs_src/body_updates/tutorial001_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from fastapi.encoders import jsonable_encoder @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): - name: Optional[str] = None - description: Optional[str] = None - price: Optional[float] = None + name: Union[str, None] = None + description: Union[str, None] = None + price: Union[float, None] = None tax: float = 10.5 tags: list[str] = [] diff --git a/docs_src/body_updates/tutorial002.py b/docs_src/body_updates/tutorial002.py index 46d27e67e..c3a0fe79e 100644 --- a/docs_src/body_updates/tutorial002.py +++ b/docs_src/body_updates/tutorial002.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Union from fastapi import FastAPI from fastapi.encoders import jsonable_encoder @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): - name: Optional[str] = None - description: Optional[str] = None - price: Optional[float] = None + name: Union[str, None] = None + description: Union[str, None] = None + price: Union[float, None] = None tax: float = 10.5 tags: List[str] = [] diff --git a/docs_src/body_updates/tutorial002_py39.py b/docs_src/body_updates/tutorial002_py39.py index ab85bd5ae..eb35b3521 100644 --- a/docs_src/body_updates/tutorial002_py39.py +++ b/docs_src/body_updates/tutorial002_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from fastapi.encoders import jsonable_encoder @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): - name: Optional[str] = None - description: Optional[str] = None - price: Optional[float] = None + name: Union[str, None] = None + description: Union[str, None] = None + price: Union[float, None] = None tax: float = 10.5 tags: list[str] = [] diff --git a/docs_src/dataclasses/tutorial001.py b/docs_src/dataclasses/tutorial001.py index 43015eb27..2954c391f 100644 --- a/docs_src/dataclasses/tutorial001.py +++ b/docs_src/dataclasses/tutorial001.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -8,8 +8,8 @@ from fastapi import FastAPI class Item: name: str price: float - description: Optional[str] = None - tax: Optional[float] = None + description: Union[str, None] = None + tax: Union[float, None] = None app = FastAPI() diff --git a/docs_src/dataclasses/tutorial002.py b/docs_src/dataclasses/tutorial002.py index aaa7b8799..08a238080 100644 --- a/docs_src/dataclasses/tutorial002.py +++ b/docs_src/dataclasses/tutorial002.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import List, Optional +from typing import List, Union from fastapi import FastAPI @@ -9,8 +9,8 @@ class Item: name: str price: float tags: List[str] = field(default_factory=list) - description: Optional[str] = None - tax: Optional[float] = None + description: Union[str, None] = None + tax: Union[float, None] = None app = FastAPI() diff --git a/docs_src/dataclasses/tutorial003.py b/docs_src/dataclasses/tutorial003.py index 2c1fccdd7..34ce1199e 100644 --- a/docs_src/dataclasses/tutorial003.py +++ b/docs_src/dataclasses/tutorial003.py @@ -1,5 +1,5 @@ from dataclasses import field # (1) -from typing import List, Optional +from typing import List, Union from fastapi import FastAPI from pydantic.dataclasses import dataclass # (2) @@ -8,7 +8,7 @@ from pydantic.dataclasses import dataclass # (2) @dataclass class Item: name: str - description: Optional[str] = None + description: Union[str, None] = None @dataclass diff --git a/docs_src/dependencies/tutorial001.py b/docs_src/dependencies/tutorial001.py index a9da971dc..b1275103a 100644 --- a/docs_src/dependencies/tutorial001.py +++ b/docs_src/dependencies/tutorial001.py @@ -1,11 +1,13 @@ -from typing import Optional +from typing import Union from fastapi import Depends, FastAPI app = FastAPI() -async def common_parameters(q: Optional[str] = None, skip: int = 0, limit: int = 100): +async def common_parameters( + q: Union[str, None] = None, skip: int = 0, limit: int = 100 +): return {"q": q, "skip": skip, "limit": limit} diff --git a/docs_src/dependencies/tutorial002.py b/docs_src/dependencies/tutorial002.py index 458f6b5bb..8e863e4fa 100644 --- a/docs_src/dependencies/tutorial002.py +++ b/docs_src/dependencies/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Depends, FastAPI @@ -9,7 +9,7 @@ fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz" class CommonQueryParams: - def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100): + def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): self.q = q self.skip = skip self.limit = limit diff --git a/docs_src/dependencies/tutorial003.py b/docs_src/dependencies/tutorial003.py index 3f3e940f8..34614e539 100644 --- a/docs_src/dependencies/tutorial003.py +++ b/docs_src/dependencies/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Depends, FastAPI @@ -9,7 +9,7 @@ fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz" class CommonQueryParams: - def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100): + def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): self.q = q self.skip = skip self.limit = limit diff --git a/docs_src/dependencies/tutorial004.py b/docs_src/dependencies/tutorial004.py index daa7b4670..d9fe88148 100644 --- a/docs_src/dependencies/tutorial004.py +++ b/docs_src/dependencies/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Depends, FastAPI @@ -9,7 +9,7 @@ fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz" class CommonQueryParams: - def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100): + def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): self.q = q self.skip = skip self.limit = limit diff --git a/docs_src/dependencies/tutorial005.py b/docs_src/dependencies/tutorial005.py index 24f73c617..697332b5b 100644 --- a/docs_src/dependencies/tutorial005.py +++ b/docs_src/dependencies/tutorial005.py @@ -1,16 +1,17 @@ -from typing import Optional +from typing import Union from fastapi import Cookie, Depends, FastAPI app = FastAPI() -def query_extractor(q: Optional[str] = None): +def query_extractor(q: Union[str, None] = None): return q def query_or_cookie_extractor( - q: str = Depends(query_extractor), last_query: Optional[str] = Cookie(default=None) + q: str = Depends(query_extractor), + last_query: Union[str, None] = Cookie(default=None), ): if not q: return last_query diff --git a/docs_src/dependency_testing/tutorial001.py b/docs_src/dependency_testing/tutorial001.py index 237d3b231..a5fe1d9bf 100644 --- a/docs_src/dependency_testing/tutorial001.py +++ b/docs_src/dependency_testing/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Depends, FastAPI from fastapi.testclient import TestClient @@ -6,7 +6,9 @@ from fastapi.testclient import TestClient app = FastAPI() -async def common_parameters(q: Optional[str] = None, skip: int = 0, limit: int = 100): +async def common_parameters( + q: Union[str, None] = None, skip: int = 0, limit: int = 100 +): return {"q": q, "skip": skip, "limit": limit} @@ -23,7 +25,7 @@ async def read_users(commons: dict = Depends(common_parameters)): client = TestClient(app) -async def override_dependency(q: Optional[str] = None): +async def override_dependency(q: Union[str, None] = None): return {"q": q, "skip": 5, "limit": 10} diff --git a/docs_src/encoder/tutorial001.py b/docs_src/encoder/tutorial001.py index a918fdd64..5f7e7061e 100644 --- a/docs_src/encoder/tutorial001.py +++ b/docs_src/encoder/tutorial001.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Optional +from typing import Union from fastapi import FastAPI from fastapi.encoders import jsonable_encoder @@ -11,7 +11,7 @@ fake_db = {} class Item(BaseModel): title: str timestamp: datetime - description: Optional[str] = None + description: Union[str, None] = None app = FastAPI() diff --git a/docs_src/extra_data_types/tutorial001.py b/docs_src/extra_data_types/tutorial001.py index 9f5e911bf..8ae8472a7 100644 --- a/docs_src/extra_data_types/tutorial001.py +++ b/docs_src/extra_data_types/tutorial001.py @@ -1,5 +1,5 @@ from datetime import datetime, time, timedelta -from typing import Optional +from typing import Union from uuid import UUID from fastapi import Body, FastAPI @@ -10,10 +10,10 @@ app = FastAPI() @app.put("/items/{item_id}") async def read_items( item_id: UUID, - start_datetime: Optional[datetime] = Body(default=None), - end_datetime: Optional[datetime] = Body(default=None), - repeat_at: Optional[time] = Body(default=None), - process_after: Optional[timedelta] = Body(default=None), + start_datetime: Union[datetime, None] = Body(default=None), + end_datetime: Union[datetime, None] = Body(default=None), + repeat_at: Union[time, None] = Body(default=None), + process_after: Union[timedelta, None] = Body(default=None), ): start_process = start_datetime + process_after duration = end_datetime - start_process diff --git a/docs_src/extra_models/tutorial001.py b/docs_src/extra_models/tutorial001.py index e95844f60..4be56cd2a 100644 --- a/docs_src/extra_models/tutorial001.py +++ b/docs_src/extra_models/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel, EmailStr @@ -10,20 +10,20 @@ class UserIn(BaseModel): username: str password: str email: EmailStr - full_name: Optional[str] = None + full_name: Union[str, None] = None class UserOut(BaseModel): username: str email: EmailStr - full_name: Optional[str] = None + full_name: Union[str, None] = None class UserInDB(BaseModel): username: str hashed_password: str email: EmailStr - full_name: Optional[str] = None + full_name: Union[str, None] = None def fake_password_hasher(raw_password: str): diff --git a/docs_src/extra_models/tutorial002.py b/docs_src/extra_models/tutorial002.py index 5bc6e707f..70fa16441 100644 --- a/docs_src/extra_models/tutorial002.py +++ b/docs_src/extra_models/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel, EmailStr @@ -9,7 +9,7 @@ app = FastAPI() class UserBase(BaseModel): username: str email: EmailStr - full_name: Optional[str] = None + full_name: Union[str, None] = None class UserIn(UserBase): diff --git a/docs_src/header_params/tutorial001.py b/docs_src/header_params/tutorial001.py index 1df561a12..74429c8e2 100644 --- a/docs_src/header_params/tutorial001.py +++ b/docs_src/header_params/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Header @@ -6,5 +6,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(user_agent: Optional[str] = Header(default=None)): +async def read_items(user_agent: Union[str, None] = Header(default=None)): return {"User-Agent": user_agent} diff --git a/docs_src/header_params/tutorial002.py b/docs_src/header_params/tutorial002.py index 2250727f6..639ab1735 100644 --- a/docs_src/header_params/tutorial002.py +++ b/docs_src/header_params/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Header @@ -7,6 +7,6 @@ app = FastAPI() @app.get("/items/") async def read_items( - strange_header: Optional[str] = Header(default=None, convert_underscores=False) + strange_header: Union[str, None] = Header(default=None, convert_underscores=False) ): return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial003.py b/docs_src/header_params/tutorial003.py index 1ef131cee..a61314aed 100644 --- a/docs_src/header_params/tutorial003.py +++ b/docs_src/header_params/tutorial003.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Union from fastapi import FastAPI, Header @@ -6,5 +6,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(x_token: Optional[List[str]] = Header(default=None)): +async def read_items(x_token: Union[List[str], None] = Header(default=None)): return {"X-Token values": x_token} diff --git a/docs_src/header_params/tutorial003_py39.py b/docs_src/header_params/tutorial003_py39.py index 78dda58da..34437db16 100644 --- a/docs_src/header_params/tutorial003_py39.py +++ b/docs_src/header_params/tutorial003_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, Header @@ -6,5 +6,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(x_token: Optional[list[str]] = Header(default=None)): +async def read_items(x_token: Union[list[str], None] = Header(default=None)): return {"X-Token values": x_token} diff --git a/docs_src/nosql_databases/tutorial001.py b/docs_src/nosql_databases/tutorial001.py index 39548d862..91893e528 100644 --- a/docs_src/nosql_databases/tutorial001.py +++ b/docs_src/nosql_databases/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from couchbase import LOCKMODE_WAIT from couchbase.bucket import Bucket @@ -23,9 +23,9 @@ def get_bucket(): class User(BaseModel): username: str - email: Optional[str] = None - full_name: Optional[str] = None - disabled: Optional[bool] = None + email: Union[str, None] = None + full_name: Union[str, None] = None + disabled: Union[bool, None] = None class UserInDB(User): diff --git a/docs_src/openapi_callbacks/tutorial001.py b/docs_src/openapi_callbacks/tutorial001.py index 2fb836751..3f1bac6e2 100644 --- a/docs_src/openapi_callbacks/tutorial001.py +++ b/docs_src/openapi_callbacks/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import APIRouter, FastAPI from pydantic import BaseModel, HttpUrl @@ -8,7 +8,7 @@ app = FastAPI() class Invoice(BaseModel): id: str - title: Optional[str] = None + title: Union[str, None] = None customer: str total: float @@ -33,7 +33,7 @@ def invoice_notification(body: InvoiceEvent): @app.post("/invoices/", callbacks=invoices_callback_router.routes) -def create_invoice(invoice: Invoice, callback_url: Optional[HttpUrl] = None): +def create_invoice(invoice: Invoice, callback_url: Union[HttpUrl, None] = None): """ Create an invoice. diff --git a/docs_src/path_operation_advanced_configuration/tutorial004.py b/docs_src/path_operation_advanced_configuration/tutorial004.py index da678aed3..a3aad4ac4 100644 --- a/docs_src/path_operation_advanced_configuration/tutorial004.py +++ b/docs_src/path_operation_advanced_configuration/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Set, Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial001.py b/docs_src/path_operation_configuration/tutorial001.py index 1316d9237..83fd8377a 100644 --- a/docs_src/path_operation_configuration/tutorial001.py +++ b/docs_src/path_operation_configuration/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Set, Union from fastapi import FastAPI, status from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial001_py39.py b/docs_src/path_operation_configuration/tutorial001_py39.py index 5c04d8bac..a9dcbf389 100644 --- a/docs_src/path_operation_configuration/tutorial001_py39.py +++ b/docs_src/path_operation_configuration/tutorial001_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, status from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial002.py b/docs_src/path_operation_configuration/tutorial002.py index 2df537d86..798b0c231 100644 --- a/docs_src/path_operation_configuration/tutorial002.py +++ b/docs_src/path_operation_configuration/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Set, Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial002_py39.py b/docs_src/path_operation_configuration/tutorial002_py39.py index 766d9fb0b..e7ced7de7 100644 --- a/docs_src/path_operation_configuration/tutorial002_py39.py +++ b/docs_src/path_operation_configuration/tutorial002_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial003.py b/docs_src/path_operation_configuration/tutorial003.py index 269a1a253..26bf7daba 100644 --- a/docs_src/path_operation_configuration/tutorial003.py +++ b/docs_src/path_operation_configuration/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Set, Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial003_py39.py b/docs_src/path_operation_configuration/tutorial003_py39.py index 446198b5c..607c5707e 100644 --- a/docs_src/path_operation_configuration/tutorial003_py39.py +++ b/docs_src/path_operation_configuration/tutorial003_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial004.py b/docs_src/path_operation_configuration/tutorial004.py index de83be836..8f865c58a 100644 --- a/docs_src/path_operation_configuration/tutorial004.py +++ b/docs_src/path_operation_configuration/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Set, Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial004_py39.py b/docs_src/path_operation_configuration/tutorial004_py39.py index bf6005b95..fc25680c5 100644 --- a/docs_src/path_operation_configuration/tutorial004_py39.py +++ b/docs_src/path_operation_configuration/tutorial004_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial005.py b/docs_src/path_operation_configuration/tutorial005.py index 0f62c3814..2c1be4a34 100644 --- a/docs_src/path_operation_configuration/tutorial005.py +++ b/docs_src/path_operation_configuration/tutorial005.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Set, Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: Set[str] = set() diff --git a/docs_src/path_operation_configuration/tutorial005_py39.py b/docs_src/path_operation_configuration/tutorial005_py39.py index 5ef320405..ddf29b733 100644 --- a/docs_src/path_operation_configuration/tutorial005_py39.py +++ b/docs_src/path_operation_configuration/tutorial005_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: set[str] = set() diff --git a/docs_src/python_types/tutorial009c.py b/docs_src/python_types/tutorial009c.py new file mode 100644 index 000000000..2f539a34b --- /dev/null +++ b/docs_src/python_types/tutorial009c.py @@ -0,0 +1,5 @@ +from typing import Optional + + +def say_hi(name: Optional[str]): + print(f"Hey {name}!") diff --git a/docs_src/python_types/tutorial009c_py310.py b/docs_src/python_types/tutorial009c_py310.py new file mode 100644 index 000000000..96b1220fc --- /dev/null +++ b/docs_src/python_types/tutorial009c_py310.py @@ -0,0 +1,2 @@ +def say_hi(name: str | None): + print(f"Hey {name}!") diff --git a/docs_src/python_types/tutorial011.py b/docs_src/python_types/tutorial011.py index 047b633b5..c8634cbff 100644 --- a/docs_src/python_types/tutorial011.py +++ b/docs_src/python_types/tutorial011.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import List, Optional +from typing import List, Union from pydantic import BaseModel @@ -7,7 +7,7 @@ from pydantic import BaseModel class User(BaseModel): id: int name = "John Doe" - signup_ts: Optional[datetime] = None + signup_ts: Union[datetime, None] = None friends: List[int] = [] diff --git a/docs_src/python_types/tutorial011_py39.py b/docs_src/python_types/tutorial011_py39.py index af79e2df0..468496f51 100644 --- a/docs_src/python_types/tutorial011_py39.py +++ b/docs_src/python_types/tutorial011_py39.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Optional +from typing import Union from pydantic import BaseModel @@ -7,7 +7,7 @@ from pydantic import BaseModel class User(BaseModel): id: int name = "John Doe" - signup_ts: Optional[datetime] = None + signup_ts: Union[datetime, None] = None friends: list[int] = [] diff --git a/docs_src/python_types/tutorial012.py b/docs_src/python_types/tutorial012.py new file mode 100644 index 000000000..74fa94c43 --- /dev/null +++ b/docs_src/python_types/tutorial012.py @@ -0,0 +1,8 @@ +from typing import Optional + +from pydantic import BaseModel + + +class User(BaseModel): + name: str + age: Optional[int] diff --git a/docs_src/query_params/tutorial002.py b/docs_src/query_params/tutorial002.py index 32918465e..8465f45ee 100644 --- a/docs_src/query_params/tutorial002.py +++ b/docs_src/query_params/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/{item_id}") -async def read_item(item_id: str, q: Optional[str] = None): +async def read_item(item_id: str, q: Union[str, None] = None): if q: return {"item_id": item_id, "q": q} return {"item_id": item_id} diff --git a/docs_src/query_params/tutorial003.py b/docs_src/query_params/tutorial003.py index c81a96785..3362715b3 100644 --- a/docs_src/query_params/tutorial003.py +++ b/docs_src/query_params/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/{item_id}") -async def read_item(item_id: str, q: Optional[str] = None, short: bool = False): +async def read_item(item_id: str, q: Union[str, None] = None, short: bool = False): item = {"item_id": item_id} if q: item.update({"q": q}) diff --git a/docs_src/query_params/tutorial004.py b/docs_src/query_params/tutorial004.py index 37f97fa2a..049c3ae93 100644 --- a/docs_src/query_params/tutorial004.py +++ b/docs_src/query_params/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -7,7 +7,7 @@ app = FastAPI() @app.get("/users/{user_id}/items/{item_id}") async def read_user_item( - user_id: int, item_id: str, q: Optional[str] = None, short: bool = False + user_id: int, item_id: str, q: Union[str, None] = None, short: bool = False ): item = {"item_id": item_id, "owner_id": user_id} if q: diff --git a/docs_src/query_params/tutorial006.py b/docs_src/query_params/tutorial006.py index ffe328340..f0dbfe08f 100644 --- a/docs_src/query_params/tutorial006.py +++ b/docs_src/query_params/tutorial006.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -7,7 +7,7 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_user_item( - item_id: str, needy: str, skip: int = 0, limit: Optional[int] = None + item_id: str, needy: str, skip: int = 0, limit: Union[int, None] = None ): item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit} return item diff --git a/docs_src/query_params_str_validations/tutorial001.py b/docs_src/query_params_str_validations/tutorial001.py index 5d7bfb0ee..e38326b18 100644 --- a/docs_src/query_params_str_validations/tutorial001.py +++ b/docs_src/query_params_str_validations/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Optional[str] = None): +async def read_items(q: Union[str, None] = None): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/request_files/tutorial001_02.py b/docs_src/request_files/tutorial001_02.py index 3f311c4b8..ac30be2d3 100644 --- a/docs_src/request_files/tutorial001_02.py +++ b/docs_src/request_files/tutorial001_02.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI, File, UploadFile @@ -6,7 +6,7 @@ app = FastAPI() @app.post("/files/") -async def create_file(file: Optional[bytes] = File(default=None)): +async def create_file(file: Union[bytes, None] = File(default=None)): if not file: return {"message": "No file sent"} else: @@ -14,7 +14,7 @@ async def create_file(file: Optional[bytes] = File(default=None)): @app.post("/uploadfile/") -async def create_upload_file(file: Optional[UploadFile] = None): +async def create_upload_file(file: Union[UploadFile, None] = None): if not file: return {"message": "No upload file sent"} else: diff --git a/docs_src/response_directly/tutorial001.py b/docs_src/response_directly/tutorial001.py index 6acdc0fc8..5ab655a8a 100644 --- a/docs_src/response_directly/tutorial001.py +++ b/docs_src/response_directly/tutorial001.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Optional +from typing import Union from fastapi import FastAPI from fastapi.encoders import jsonable_encoder @@ -10,7 +10,7 @@ from pydantic import BaseModel class Item(BaseModel): title: str timestamp: datetime - description: Optional[str] = None + description: Union[str, None] = None app = FastAPI() diff --git a/docs_src/response_model/tutorial001.py b/docs_src/response_model/tutorial001.py index 57992ecfc..0f6e03e5b 100644 --- a/docs_src/response_model/tutorial001.py +++ b/docs_src/response_model/tutorial001.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: List[str] = [] diff --git a/docs_src/response_model/tutorial001_py39.py b/docs_src/response_model/tutorial001_py39.py index 37b866864..cdcca39d2 100644 --- a/docs_src/response_model/tutorial001_py39.py +++ b/docs_src/response_model/tutorial001_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None tags: list[str] = [] diff --git a/docs_src/response_model/tutorial002.py b/docs_src/response_model/tutorial002.py index 373317eb9..c68e8b138 100644 --- a/docs_src/response_model/tutorial002.py +++ b/docs_src/response_model/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel, EmailStr @@ -10,7 +10,7 @@ class UserIn(BaseModel): username: str password: str email: EmailStr - full_name: Optional[str] = None + full_name: Union[str, None] = None # Don't do this in production! diff --git a/docs_src/response_model/tutorial003.py b/docs_src/response_model/tutorial003.py index e14026dd8..37e493dcb 100644 --- a/docs_src/response_model/tutorial003.py +++ b/docs_src/response_model/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel, EmailStr @@ -10,13 +10,13 @@ class UserIn(BaseModel): username: str password: str email: EmailStr - full_name: Optional[str] = None + full_name: Union[str, None] = None class UserOut(BaseModel): username: str email: EmailStr - full_name: Optional[str] = None + full_name: Union[str, None] = None @app.post("/user/", response_model=UserOut) diff --git a/docs_src/response_model/tutorial004.py b/docs_src/response_model/tutorial004.py index 1e18f989d..10b48039a 100644 --- a/docs_src/response_model/tutorial004.py +++ b/docs_src/response_model/tutorial004.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,7 +8,7 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float tax: float = 10.5 tags: List[str] = [] diff --git a/docs_src/response_model/tutorial004_py39.py b/docs_src/response_model/tutorial004_py39.py index 07ccbbf41..9463b45ec 100644 --- a/docs_src/response_model/tutorial004_py39.py +++ b/docs_src/response_model/tutorial004_py39.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,7 +8,7 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float tax: float = 10.5 tags: list[str] = [] diff --git a/docs_src/response_model/tutorial005.py b/docs_src/response_model/tutorial005.py index 03933d1f7..30eb9f8e3 100644 --- a/docs_src/response_model/tutorial005.py +++ b/docs_src/response_model/tutorial005.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,7 +8,7 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float tax: float = 10.5 diff --git a/docs_src/response_model/tutorial006.py b/docs_src/response_model/tutorial006.py index 629ab8a3a..3ffdb512b 100644 --- a/docs_src/response_model/tutorial006.py +++ b/docs_src/response_model/tutorial006.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,7 +8,7 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float tax: float = 10.5 diff --git a/docs_src/schema_extra_example/tutorial001.py b/docs_src/schema_extra_example/tutorial001.py index fab4d7a44..a5ae28127 100644 --- a/docs_src/schema_extra_example/tutorial001.py +++ b/docs_src/schema_extra_example/tutorial001.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None class Config: schema_extra = { diff --git a/docs_src/schema_extra_example/tutorial002.py b/docs_src/schema_extra_example/tutorial002.py index a2aec46f5..6de434f81 100644 --- a/docs_src/schema_extra_example/tutorial002.py +++ b/docs_src/schema_extra_example/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import FastAPI from pydantic import BaseModel, Field @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str = Field(example="Foo") - description: Optional[str] = Field(default=None, example="A very nice Item") + description: Union[str, None] = Field(default=None, example="A very nice Item") price: float = Field(example=35.4) - tax: Optional[float] = Field(default=None, example=3.2) + tax: Union[float, None] = Field(default=None, example=3.2) @app.put("/items/{item_id}") diff --git a/docs_src/schema_extra_example/tutorial003.py b/docs_src/schema_extra_example/tutorial003.py index 43d46b81b..ce1736bba 100644 --- a/docs_src/schema_extra_example/tutorial003.py +++ b/docs_src/schema_extra_example/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Body, FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None @app.put("/items/{item_id}") diff --git a/docs_src/schema_extra_example/tutorial004.py b/docs_src/schema_extra_example/tutorial004.py index 42d7a04a3..b67edf30c 100644 --- a/docs_src/schema_extra_example/tutorial004.py +++ b/docs_src/schema_extra_example/tutorial004.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Body, FastAPI from pydantic import BaseModel @@ -8,9 +8,9 @@ app = FastAPI() class Item(BaseModel): name: str - description: Optional[str] = None + description: Union[str, None] = None price: float - tax: Optional[float] = None + tax: Union[float, None] = None @app.put("/items/{item_id}") diff --git a/docs_src/security/tutorial002.py b/docs_src/security/tutorial002.py index 03e0cd5fc..bfd035221 100644 --- a/docs_src/security/tutorial002.py +++ b/docs_src/security/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Depends, FastAPI from fastapi.security import OAuth2PasswordBearer @@ -11,9 +11,9 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") class User(BaseModel): username: str - email: Optional[str] = None - full_name: Optional[str] = None - disabled: Optional[bool] = None + email: Union[str, None] = None + full_name: Union[str, None] = None + disabled: Union[bool, None] = None def fake_decode_token(token): diff --git a/docs_src/security/tutorial003.py b/docs_src/security/tutorial003.py index a6bb176e4..4b324866f 100644 --- a/docs_src/security/tutorial003.py +++ b/docs_src/security/tutorial003.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm @@ -33,9 +33,9 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") class User(BaseModel): username: str - email: Optional[str] = None - full_name: Optional[str] = None - disabled: Optional[bool] = None + email: Union[str, None] = None + full_name: Union[str, None] = None + disabled: Union[bool, None] = None class UserInDB(User): diff --git a/docs_src/security/tutorial004.py b/docs_src/security/tutorial004.py index 18e2c428f..64099abe9 100644 --- a/docs_src/security/tutorial004.py +++ b/docs_src/security/tutorial004.py @@ -1,5 +1,5 @@ from datetime import datetime, timedelta -from typing import Optional +from typing import Union from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm @@ -31,14 +31,14 @@ class Token(BaseModel): class TokenData(BaseModel): - username: Optional[str] = None + username: Union[str, None] = None class User(BaseModel): username: str - email: Optional[str] = None - full_name: Optional[str] = None - disabled: Optional[bool] = None + email: Union[str, None] = None + full_name: Union[str, None] = None + disabled: Union[bool, None] = None class UserInDB(User): @@ -75,7 +75,7 @@ def authenticate_user(fake_db, username: str, password: str): return user -def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): +def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta diff --git a/docs_src/security/tutorial005.py b/docs_src/security/tutorial005.py index 5b34a09f1..ab3af9a6a 100644 --- a/docs_src/security/tutorial005.py +++ b/docs_src/security/tutorial005.py @@ -1,5 +1,5 @@ from datetime import datetime, timedelta -from typing import List, Optional +from typing import List, Union from fastapi import Depends, FastAPI, HTTPException, Security, status from fastapi.security import ( @@ -42,15 +42,15 @@ class Token(BaseModel): class TokenData(BaseModel): - username: Optional[str] = None + username: Union[str, None] = None scopes: List[str] = [] class User(BaseModel): username: str - email: Optional[str] = None - full_name: Optional[str] = None - disabled: Optional[bool] = None + email: Union[str, None] = None + full_name: Union[str, None] = None + disabled: Union[bool, None] = None class UserInDB(User): @@ -90,7 +90,7 @@ def authenticate_user(fake_db, username: str, password: str): return user -def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): +def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py index d45c08ce6..38391308a 100644 --- a/docs_src/security/tutorial005_py39.py +++ b/docs_src/security/tutorial005_py39.py @@ -1,5 +1,5 @@ from datetime import datetime, timedelta -from typing import Optional +from typing import Union from fastapi import Depends, FastAPI, HTTPException, Security, status from fastapi.security import ( @@ -42,15 +42,15 @@ class Token(BaseModel): class TokenData(BaseModel): - username: Optional[str] = None + username: Union[str, None] = None scopes: list[str] = [] class User(BaseModel): username: str - email: Optional[str] = None - full_name: Optional[str] = None - disabled: Optional[bool] = None + email: Union[str, None] = None + full_name: Union[str, None] = None + disabled: Union[bool, None] = None class UserInDB(User): @@ -90,7 +90,7 @@ def authenticate_user(fake_db, username: str, password: str): return user -def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): +def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta diff --git a/docs_src/sql_databases/sql_app/schemas.py b/docs_src/sql_databases/sql_app/schemas.py index 51655663a..c49beba88 100644 --- a/docs_src/sql_databases/sql_app/schemas.py +++ b/docs_src/sql_databases/sql_app/schemas.py @@ -1,11 +1,11 @@ -from typing import List, Optional +from typing import List, Union from pydantic import BaseModel class ItemBase(BaseModel): title: str - description: Optional[str] = None + description: Union[str, None] = None class ItemCreate(ItemBase): diff --git a/docs_src/sql_databases/sql_app_py39/schemas.py b/docs_src/sql_databases/sql_app_py39/schemas.py index a19f1cdfe..dadc403d9 100644 --- a/docs_src/sql_databases/sql_app_py39/schemas.py +++ b/docs_src/sql_databases/sql_app_py39/schemas.py @@ -1,11 +1,11 @@ -from typing import Optional +from typing import Union from pydantic import BaseModel class ItemBase(BaseModel): title: str - description: Optional[str] = None + description: Union[str, None] = None class ItemCreate(ItemBase): diff --git a/docs_src/sql_databases_peewee/sql_app/schemas.py b/docs_src/sql_databases_peewee/sql_app/schemas.py index b715604ee..d8775cb30 100644 --- a/docs_src/sql_databases_peewee/sql_app/schemas.py +++ b/docs_src/sql_databases_peewee/sql_app/schemas.py @@ -1,4 +1,4 @@ -from typing import Any, List, Optional +from typing import Any, List, Union import peewee from pydantic import BaseModel @@ -15,7 +15,7 @@ class PeeweeGetterDict(GetterDict): class ItemBase(BaseModel): title: str - description: Optional[str] = None + description: Union[str, None] = None class ItemCreate(ItemBase): diff --git a/docs_src/websockets/tutorial002.py b/docs_src/websockets/tutorial002.py index b01008530..cf5c7e805 100644 --- a/docs_src/websockets/tutorial002.py +++ b/docs_src/websockets/tutorial002.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from fastapi import Cookie, Depends, FastAPI, Query, WebSocket, status from fastapi.responses import HTMLResponse @@ -57,8 +57,8 @@ async def get(): async def get_cookie_or_token( websocket: WebSocket, - session: Optional[str] = Cookie(default=None), - token: Optional[str] = Query(default=None), + session: Union[str, None] = Cookie(default=None), + token: Union[str, None] = Query(default=None), ): if session is None and token is None: await websocket.close(code=status.WS_1008_POLICY_VIOLATION) @@ -69,7 +69,7 @@ async def get_cookie_or_token( async def websocket_endpoint( websocket: WebSocket, item_id: str, - q: Optional[int] = None, + q: Union[int, None] = None, cookie_or_token: str = Depends(get_cookie_or_token), ): await websocket.accept() From 0a8d6871fb860a1dcedd169035c9df847825439a Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 14 May 2022 12:00:32 +0000 Subject: [PATCH 560/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 416983bc1..2a43718a1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add docs recommending `Union` over `Optional` and migrate source examples. PR [#4908](https://github.com/tiangolo/fastapi/pull/4908) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for not needing `...` as default value in required Query(), Path(), Header(), etc.. PR [#4906](https://github.com/tiangolo/fastapi/pull/4906) by [@tiangolo](https://github.com/tiangolo). * 🎨 Fix default value as set in tutorial for Path Operations Advanced Configurations. PR [#4899](https://github.com/tiangolo/fastapi/pull/4899) by [@tiangolo](https://github.com/tiangolo). * ♻ Refactor dict value extraction to minimize key lookups `fastapi/utils.py`. PR [#3139](https://github.com/tiangolo/fastapi/pull/3139) by [@ShahriyarR](https://github.com/ShahriyarR). From acab64b3c355a2aeb13c7739a639f9fe2a03bc1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 14 May 2022 14:08:31 -0500 Subject: [PATCH 561/814] =?UTF-8?q?=E2=9C=85=20Add=20tests=20for=20require?= =?UTF-8?q?d=20nonable=20parameters=20and=20body=20fields=20(#4907)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_required_noneable.py | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/test_required_noneable.py diff --git a/tests/test_required_noneable.py b/tests/test_required_noneable.py new file mode 100644 index 000000000..5da8cd4d0 --- /dev/null +++ b/tests/test_required_noneable.py @@ -0,0 +1,62 @@ +from typing import Union + +from fastapi import Body, FastAPI, Query +from fastapi.testclient import TestClient + +app = FastAPI() + + +@app.get("/query") +def read_query(q: Union[str, None]): + return q + + +@app.get("/explicit-query") +def read_explicit_query(q: Union[str, None] = Query()): + return q + + +@app.post("/body-embed") +def send_body_embed(b: Union[str, None] = Body(embed=True)): + return b + + +client = TestClient(app) + + +def test_required_nonable_query_invalid(): + response = client.get("/query") + assert response.status_code == 422 + + +def test_required_noneable_query_value(): + response = client.get("/query", params={"q": "foo"}) + assert response.status_code == 200 + assert response.json() == "foo" + + +def test_required_nonable_explicit_query_invalid(): + response = client.get("/explicit-query") + assert response.status_code == 422 + + +def test_required_nonable_explicit_query_value(): + response = client.get("/explicit-query", params={"q": "foo"}) + assert response.status_code == 200 + assert response.json() == "foo" + + +def test_required_nonable_body_embed_no_content(): + response = client.post("/body-embed") + assert response.status_code == 422 + + +def test_required_nonable_body_embed_invalid(): + response = client.post("/body-embed", json={"invalid": "invalid"}) + assert response.status_code == 422 + + +def test_required_noneable_body_embed_value(): + response = client.post("/body-embed", json={"b": "foo"}) + assert response.status_code == 200 + assert response.json() == "foo" From 1711403732cf092ac69cfca0783862631489ad21 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 14 May 2022 19:09:00 +0000 Subject: [PATCH 562/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2a43718a1..81bc21645 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✅ Add tests for required nonable parameters and body fields. PR [#4907](https://github.com/tiangolo/fastapi/pull/4907) by [@tiangolo](https://github.com/tiangolo). * 📝 Add docs recommending `Union` over `Optional` and migrate source examples. PR [#4908](https://github.com/tiangolo/fastapi/pull/4908) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for not needing `...` as default value in required Query(), Path(), Header(), etc.. PR [#4906](https://github.com/tiangolo/fastapi/pull/4906) by [@tiangolo](https://github.com/tiangolo). * 🎨 Fix default value as set in tutorial for Path Operations Advanced Configurations. PR [#4899](https://github.com/tiangolo/fastapi/pull/4899) by [@tiangolo](https://github.com/tiangolo). From 1673b3ec118d5b7efe4865d1d752ff2a878282c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 14 May 2022 14:53:50 -0500 Subject: [PATCH 563/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 106 ++++++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 12 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 81bc21645..a671fe276 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,27 +2,109 @@ ## Latest Changes -* ✅ Add tests for required nonable parameters and body fields. PR [#4907](https://github.com/tiangolo/fastapi/pull/4907) by [@tiangolo](https://github.com/tiangolo). -* 📝 Add docs recommending `Union` over `Optional` and migrate source examples. PR [#4908](https://github.com/tiangolo/fastapi/pull/4908) by [@tiangolo](https://github.com/tiangolo). -* ✨ Add support for not needing `...` as default value in required Query(), Path(), Header(), etc.. PR [#4906](https://github.com/tiangolo/fastapi/pull/4906) by [@tiangolo](https://github.com/tiangolo). +### Features + +* ✨ Add support for omitting `...` as default value when declaring required parameters with: + +* `Path()` +* `Query()` +* `Header()` +* `Cookie()` +* `Body()` +* `Form()` +* `File()` + +New docs at [Tutorial - Query Parameters and String Validations - Make it required](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#make-it-required). PR [#4906](https://github.com/tiangolo/fastapi/pull/4906) by [@tiangolo](https://github.com/tiangolo). + +Up to now, declaring a required parameter while adding additional validation or metadata needed using `...` (Ellipsis). + +For example: + +```Python +from fastapi import Cookie, FastAPI, Header, Path, Query + +app = FastAPI() + + +@app.get("/items/{item_id}") +def main( + item_id: int = Path(default=..., gt=0), + query: str = Query(default=..., max_length=10), + session: str = Cookie(default=..., min_length=3), + x_trace: str = Header(default=..., title="Tracing header"), +): + return {"message": "Hello World"} +``` + +...all these parameters are required because the default value is `...` (Ellipsis). + +But now it's possible and supported to just omit the default value, as would be done with Pydantic fields, and the parameters would still be required. + +✨ For example, this is now supported: + +```Python +from fastapi import Cookie, FastAPI, Header, Path, Query + +app = FastAPI() + + +@app.get("/items/{item_id}") +def main( + item_id: int = Path(gt=0), + query: str = Query(max_length=10), + session: str = Cookie(min_length=3), + x_trace: str = Header(title="Tracing header"), +): + return {"message": "Hello World"} +``` + +To declare parameters as optional (not required), you can set a default value as always, for example using `None`: + +```Python +from typing import Union +from fastapi import Cookie, FastAPI, Header, Path, Query + +app = FastAPI() + + +@app.get("/items/{item_id}") +def main( + item_id: int = Path(gt=0), + query: Union[str, None] = Query(default=None, max_length=10), + session: Union[str, None] = Cookie(default=None, min_length=3), + x_trace: Union[str, None] = Header(default=None, title="Tracing header"), +): + return {"message": "Hello World"} +``` + +### Docs + +* 📝 Add docs recommending `Union` over `Optional` and migrate source examples. New docs at [Python Types Intro - Using `Union` or `Optional`](https://fastapi.tiangolo.com/python-types/#using-union-or-optional). PR [#4908](https://github.com/tiangolo/fastapi/pull/4908) by [@tiangolo](https://github.com/tiangolo). * 🎨 Fix default value as set in tutorial for Path Operations Advanced Configurations. PR [#4899](https://github.com/tiangolo/fastapi/pull/4899) by [@tiangolo](https://github.com/tiangolo). +* 📝 Add documentation for redefined path operations. PR [#4864](https://github.com/tiangolo/fastapi/pull/4864) by [@madkinsz](https://github.com/madkinsz). +* 📝 Updates links for Celery documentation. PR [#4736](https://github.com/tiangolo/fastapi/pull/4736) by [@sammyzord](https://github.com/sammyzord). +* ✏ Fix example code with sets in tutorial for body nested models. PR [#3030](https://github.com/tiangolo/fastapi/pull/3030) by [@hitrust](https://github.com/hitrust). +* ✏ Fix links to Pydantic docs. PR [#4670](https://github.com/tiangolo/fastapi/pull/4670) by [@kinuax](https://github.com/kinuax). +* 📝 Update docs about Swagger UI self-hosting with newer source links. PR [#4813](https://github.com/tiangolo/fastapi/pull/4813) by [@Kastakin](https://github.com/Kastakin). +* 📝 Add link to external article: Building the Poll App From Django Tutorial With FastAPI And React. PR [#4778](https://github.com/tiangolo/fastapi/pull/4778) by [@jbrocher](https://github.com/jbrocher). +* 📝 Add OpenAPI warning to "Body - Fields" docs with extra schema extensions. PR [#4846](https://github.com/tiangolo/fastapi/pull/4846) by [@ml-evs](https://github.com/ml-evs). + +### Translations + +* 🌐 Fix code examples in Japanese translation for `docs/ja/docs/tutorial/testing.md`. PR [#4623](https://github.com/tiangolo/fastapi/pull/4623) by [@hirotoKirimaru](https://github.com/hirotoKirimaru). + +### Internal + * ♻ Refactor dict value extraction to minimize key lookups `fastapi/utils.py`. PR [#3139](https://github.com/tiangolo/fastapi/pull/3139) by [@ShahriyarR](https://github.com/ShahriyarR). +* ✅ Add tests for required nonable parameters and body fields. PR [#4907](https://github.com/tiangolo/fastapi/pull/4907) by [@tiangolo](https://github.com/tiangolo). * 👷 Fix installing Material for MkDocs Insiders in CI. PR [#4897](https://github.com/tiangolo/fastapi/pull/4897) by [@tiangolo](https://github.com/tiangolo). * 👷 Add pre-commit CI instead of custom GitHub Action. PR [#4896](https://github.com/tiangolo/fastapi/pull/4896) by [@tiangolo](https://github.com/tiangolo). * 👷 Add pre-commit GitHub Action workflow. PR [#4895](https://github.com/tiangolo/fastapi/pull/4895) by [@tiangolo](https://github.com/tiangolo). -* 📝 Add documentation for redefined path operations. PR [#4864](https://github.com/tiangolo/fastapi/pull/4864) by [@madkinsz](https://github.com/madkinsz). +* 📝 Add dark mode auto switch to docs based on OS preference. PR [#4869](https://github.com/tiangolo/fastapi/pull/4869) by [@ComicShrimp](https://github.com/ComicShrimp). * 🔥 Remove un-used old pending tests, already covered in other places. PR [#4891](https://github.com/tiangolo/fastapi/pull/4891) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add Python formatting hooks to pre-commit. PR [#4890](https://github.com/tiangolo/fastapi/pull/4890) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add pre-commit with first config and first formatting pass. PR [#4888](https://github.com/tiangolo/fastapi/pull/4888) by [@tiangolo](https://github.com/tiangolo). * 👷 Disable CI installing Material for MkDocs in forks. PR [#4410](https://github.com/tiangolo/fastapi/pull/4410) by [@dolfinus](https://github.com/dolfinus). -* 📝 Add OpenAPI warning to "Body - Fields" docs with extra schema extensions. PR [#4846](https://github.com/tiangolo/fastapi/pull/4846) by [@ml-evs](https://github.com/ml-evs). -* 📝 Add dark mode auto switch to docs based on OS preference. PR [#4869](https://github.com/tiangolo/fastapi/pull/4869) by [@ComicShrimp](https://github.com/ComicShrimp). -* 📝 Update docs about Swagger UI self-hosting with newer source links. PR [#4813](https://github.com/tiangolo/fastapi/pull/4813) by [@Kastakin](https://github.com/Kastakin). -* 📝 Add link to external article: Building the Poll App From Django Tutorial With FastAPI And React. PR [#4778](https://github.com/tiangolo/fastapi/pull/4778) by [@jbrocher](https://github.com/jbrocher). -* 🌐 Fix code examples in Japanese translation for `docs/ja/docs/tutorial/testing.md`. PR [#4623](https://github.com/tiangolo/fastapi/pull/4623) by [@hirotoKirimaru](https://github.com/hirotoKirimaru). -* 📝 Updates links for Celery documentation. PR [#4736](https://github.com/tiangolo/fastapi/pull/4736) by [@sammyzord](https://github.com/sammyzord). -* ✏ Fix example code with sets in tutorial for body nested models. PR [#3030](https://github.com/tiangolo/fastapi/pull/3030) by [@hitrust](https://github.com/hitrust). -* ✏ Fix links to Pydantic docs. PR [#4670](https://github.com/tiangolo/fastapi/pull/4670) by [@kinuax](https://github.com/kinuax). ## 0.77.1 From 1876ebc77949a9a254909ec61ea0c09365169ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 14 May 2022 14:58:04 -0500 Subject: [PATCH 564/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.78?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a671fe276..edc58171b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.78.0 + ### Features * ✨ Add support for omitting `...` as default value when declaring required parameters with: diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 1a4d00162..2465e2c27 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.77.1" +__version__ = "0.78.0" from starlette import status as status From d8f3e8f20de8ebca5293f5b3ce71ee93c9124328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 25 Jun 2022 21:49:44 +0200 Subject: [PATCH 565/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20sponsors,=20rem?= =?UTF-8?q?ove=20Classiq,=20add=20ImgWhale=20(#5079)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔧 Update sponsors, remove Classiq, add ImgWhale * 🔧 Update README --- README.md | 2 +- docs/en/data/sponsors.yml | 6 ++-- docs/en/data/sponsors_badge.yml | 1 + docs/en/docs/img/sponsors/imgwhale-banner.svg | 14 ++++++++++ docs/en/docs/img/sponsors/imgwhale.svg | 28 +++++++++++++++++++ docs/en/overrides/main.html | 12 ++++---- 6 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 docs/en/docs/img/sponsors/imgwhale-banner.svg create mode 100644 docs/en/docs/img/sponsors/imgwhale.svg diff --git a/README.md b/README.md index 5e9e97a2a..d605affac 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,8 @@ The key features are: - + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index ac825193b..2fc08b3a5 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -5,12 +5,12 @@ gold: - url: https://cryptapi.io/ title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway." img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg - - url: https://classiq.link/n4s - title: Join the team building a new SaaS platform that will change the computing world - img: https://fastapi.tiangolo.com/img/sponsors/classiq.png - url: https://www.dropbase.io/careers title: Dropbase - seamlessly collect, clean, and centralize data. img: https://fastapi.tiangolo.com/img/sponsors/dropbase.svg + - url: https://app.imgwhale.xyz/ + title: The ultimate solution to unlimited and forever cloud storage. + img: https://fastapi.tiangolo.com/img/sponsors/imgwhale.svg silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index 1c8b0cde7..10a31b86a 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -10,3 +10,4 @@ logins: - InesIvanova - DropbaseHQ - VincentParedes + - BLUE-DEVIL1134 diff --git a/docs/en/docs/img/sponsors/imgwhale-banner.svg b/docs/en/docs/img/sponsors/imgwhale-banner.svg new file mode 100644 index 000000000..db87cc4c9 --- /dev/null +++ b/docs/en/docs/img/sponsors/imgwhale-banner.svg @@ -0,0 +1,14 @@ + + + + + + + + + + ImgWhale + The ultimate solution to unlimited and forevercloud storage. + + diff --git a/docs/en/docs/img/sponsors/imgwhale.svg b/docs/en/docs/img/sponsors/imgwhale.svg new file mode 100644 index 000000000..46aefd930 --- /dev/null +++ b/docs/en/docs/img/sponsors/imgwhale.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + ImgWhale + + The ultimate solution to unlimited and forever cloud storage. + + The ultimate solution to unlimited and forever cloud storage. + + + + diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index eb1cb5c82..62063da47 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -40,18 +40,18 @@ - + {% endblock %} From f8c875bb3fd2f01112df666c4ab4ff4d1fe7d49b Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 25 Jun 2022 19:50:20 +0000 Subject: [PATCH 566/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index edc58171b..0e60b0abf 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update sponsors, remove Classiq, add ImgWhale. PR [#5079](https://github.com/tiangolo/fastapi/pull/5079) by [@tiangolo](https://github.com/tiangolo). ## 0.78.0 From 6c6382df4d2d2c9f003658dae42f84fd2fbad36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 1 Jul 2022 10:58:40 +0200 Subject: [PATCH 567/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20sponsors,=20rem?= =?UTF-8?q?ove=20Dropbase,=20add=20Doist=20(#5096)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- docs/en/data/sponsors.yml | 6 +-- docs/en/docs/img/sponsors/doist-banner.svg | 46 ++++++++++++++++++ docs/en/docs/img/sponsors/doist.svg | 54 ++++++++++++++++++++++ docs/en/overrides/main.html | 12 ++--- 5 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 docs/en/docs/img/sponsors/doist-banner.svg create mode 100644 docs/en/docs/img/sponsors/doist.svg diff --git a/README.md b/README.md index d605affac..505005ae9 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,8 @@ The key features are: - + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 2fc08b3a5..c99c4b57a 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -5,12 +5,12 @@ gold: - url: https://cryptapi.io/ title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway." img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg - - url: https://www.dropbase.io/careers - title: Dropbase - seamlessly collect, clean, and centralize data. - img: https://fastapi.tiangolo.com/img/sponsors/dropbase.svg - url: https://app.imgwhale.xyz/ title: The ultimate solution to unlimited and forever cloud storage. img: https://fastapi.tiangolo.com/img/sponsors/imgwhale.svg + - url: https://doist.com/careers/9B437B1615-wa-senior-backend-engineer-python + title: Help us migrate doist to FastAPI + img: https://fastapi.tiangolo.com/img/sponsors/doist.svg silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas diff --git a/docs/en/docs/img/sponsors/doist-banner.svg b/docs/en/docs/img/sponsors/doist-banner.svg new file mode 100644 index 000000000..3a4d9a295 --- /dev/null +++ b/docs/en/docs/img/sponsors/doist-banner.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/docs/img/sponsors/doist.svg b/docs/en/docs/img/sponsors/doist.svg new file mode 100644 index 000000000..b55855f06 --- /dev/null +++ b/docs/en/docs/img/sponsors/doist.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 62063da47..9bed0253f 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -40,18 +40,18 @@ - + {% endblock %} From 80472301817d3581f56163874b42d06c26d99942 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 1 Jul 2022 08:59:26 +0000 Subject: [PATCH 568/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0e60b0abf..2ae0a2ed0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update sponsors, remove Dropbase, add Doist. PR [#5096](https://github.com/tiangolo/fastapi/pull/5096) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, remove Classiq, add ImgWhale. PR [#5079](https://github.com/tiangolo/fastapi/pull/5079) by [@tiangolo](https://github.com/tiangolo). ## 0.78.0 From b7686435777d1d4f79adad8f29191039bbc558b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 11 Jul 2022 21:30:41 +0200 Subject: [PATCH 569/814] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20from=20`Opt?= =?UTF-8?q?ional[X]`=20to=20`Union[X,=20None]`=20for=20internal=20utils=20?= =?UTF-8?q?(#5124)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../comment-docs-preview-in-pr/app/main.py | 6 +++--- .../actions/notify-translations/app/main.py | 6 +++--- .github/actions/people/app/main.py | 18 +++++++++--------- .github/actions/watch-previews/app/main.py | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/actions/comment-docs-preview-in-pr/app/main.py b/.github/actions/comment-docs-preview-in-pr/app/main.py index c9fb7cbbe..68914fdb9 100644 --- a/.github/actions/comment-docs-preview-in-pr/app/main.py +++ b/.github/actions/comment-docs-preview-in-pr/app/main.py @@ -1,7 +1,7 @@ import logging import sys from pathlib import Path -from typing import Optional +from typing import Union import httpx from github import Github @@ -14,7 +14,7 @@ github_api = "https://api.github.com" class Settings(BaseSettings): github_repository: str github_event_path: Path - github_event_name: Optional[str] = None + github_event_name: Union[str, None] = None input_token: SecretStr input_deploy_url: str @@ -42,7 +42,7 @@ if __name__ == "__main__": except ValidationError as e: logging.error(f"Error parsing event file: {e.errors()}") sys.exit(0) - use_pr: Optional[PullRequest] = None + use_pr: Union[PullRequest, None] = None for pr in repo.get_pulls(): if pr.head.sha == event.workflow_run.head_commit.id: use_pr = pr diff --git a/.github/actions/notify-translations/app/main.py b/.github/actions/notify-translations/app/main.py index 823685e00..d4ba0ecfc 100644 --- a/.github/actions/notify-translations/app/main.py +++ b/.github/actions/notify-translations/app/main.py @@ -2,7 +2,7 @@ import logging import random import time from pathlib import Path -from typing import Dict, Optional +from typing import Dict, Union import yaml from github import Github @@ -18,8 +18,8 @@ class Settings(BaseSettings): github_repository: str input_token: SecretStr github_event_path: Path - github_event_name: Optional[str] = None - input_debug: Optional[bool] = False + github_event_name: Union[str, None] = None + input_debug: Union[bool, None] = False class PartialGitHubEventIssue(BaseModel): diff --git a/.github/actions/people/app/main.py b/.github/actions/people/app/main.py index 9de6fc250..1455d01ca 100644 --- a/.github/actions/people/app/main.py +++ b/.github/actions/people/app/main.py @@ -4,7 +4,7 @@ import sys from collections import Counter, defaultdict from datetime import datetime, timedelta, timezone from pathlib import Path -from typing import Container, DefaultDict, Dict, List, Optional, Set +from typing import Container, DefaultDict, Dict, List, Set, Union import httpx import yaml @@ -133,7 +133,7 @@ class Author(BaseModel): class CommentsNode(BaseModel): createdAt: datetime - author: Optional[Author] = None + author: Union[Author, None] = None class Comments(BaseModel): @@ -142,7 +142,7 @@ class Comments(BaseModel): class IssuesNode(BaseModel): number: int - author: Optional[Author] = None + author: Union[Author, None] = None title: str createdAt: datetime state: str @@ -179,7 +179,7 @@ class Labels(BaseModel): class ReviewNode(BaseModel): - author: Optional[Author] = None + author: Union[Author, None] = None state: str @@ -190,7 +190,7 @@ class Reviews(BaseModel): class PullRequestNode(BaseModel): number: int labels: Labels - author: Optional[Author] = None + author: Union[Author, None] = None title: str createdAt: datetime state: str @@ -263,7 +263,7 @@ class Settings(BaseSettings): def get_graphql_response( - *, settings: Settings, query: str, after: Optional[str] = None + *, settings: Settings, query: str, after: Union[str, None] = None ): headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"} variables = {"after": after} @@ -280,19 +280,19 @@ def get_graphql_response( return data -def get_graphql_issue_edges(*, settings: Settings, after: Optional[str] = None): +def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = None): data = get_graphql_response(settings=settings, query=issues_query, after=after) graphql_response = IssuesResponse.parse_obj(data) return graphql_response.data.repository.issues.edges -def get_graphql_pr_edges(*, settings: Settings, after: Optional[str] = None): +def get_graphql_pr_edges(*, settings: Settings, after: Union[str, None] = None): data = get_graphql_response(settings=settings, query=prs_query, after=after) graphql_response = PRsResponse.parse_obj(data) return graphql_response.data.repository.pullRequests.edges -def get_graphql_sponsor_edges(*, settings: Settings, after: Optional[str] = None): +def get_graphql_sponsor_edges(*, settings: Settings, after: Union[str, None] = None): data = get_graphql_response(settings=settings, query=sponsors_query, after=after) graphql_response = SponsorsResponse.parse_obj(data) return graphql_response.data.user.sponsorshipsAsMaintainer.edges diff --git a/.github/actions/watch-previews/app/main.py b/.github/actions/watch-previews/app/main.py index 3b3520599..51285d02b 100644 --- a/.github/actions/watch-previews/app/main.py +++ b/.github/actions/watch-previews/app/main.py @@ -1,7 +1,7 @@ import logging from datetime import datetime from pathlib import Path -from typing import List, Optional +from typing import List, Union import httpx from github import Github @@ -16,7 +16,7 @@ class Settings(BaseSettings): input_token: SecretStr github_repository: str github_event_path: Path - github_event_name: Optional[str] = None + github_event_name: Union[str, None] = None class Artifact(BaseModel): @@ -74,7 +74,7 @@ if __name__ == "__main__": logging.info(f"Docs preview was notified: {notified}") if not notified: artifact_name = f"docs-zip-{commit}" - use_artifact: Optional[Artifact] = None + use_artifact: Union[Artifact, None] = None for artifact in artifacts_response.artifacts: if artifact.name == artifact_name: use_artifact = artifact From bea5194ffcbc943f7666a8ac46950936a0a43811 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 11 Jul 2022 19:31:26 +0000 Subject: [PATCH 570/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2ae0a2ed0..9e5ed6371 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻️ Move from `Optional[X]` to `Union[X, None]` for internal utils. PR [#5124](https://github.com/tiangolo/fastapi/pull/5124) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, remove Dropbase, add Doist. PR [#5096](https://github.com/tiangolo/fastapi/pull/5096) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, remove Classiq, add ImgWhale. PR [#5079](https://github.com/tiangolo/fastapi/pull/5079) by [@tiangolo](https://github.com/tiangolo). From 1d5bbe5552a7eb9f7cefd3ae265c12c18dd67974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 12 Jul 2022 18:53:38 +0200 Subject: [PATCH 571/814] =?UTF-8?q?=F0=9F=91=B7=20Add=20Dependabot=20(#512?= =?UTF-8?q?8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..946f2358c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + # Python + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" From a0fd613527d4bb3e035b5c00051c654777dcbca1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 12 Jul 2022 16:54:11 +0000 Subject: [PATCH 572/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9e5ed6371..e7326d0f1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Add Dependabot. PR [#5128](https://github.com/tiangolo/fastapi/pull/5128) by [@tiangolo](https://github.com/tiangolo). * ♻️ Move from `Optional[X]` to `Union[X, None]` for internal utils. PR [#5124](https://github.com/tiangolo/fastapi/pull/5124) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, remove Dropbase, add Doist. PR [#5096](https://github.com/tiangolo/fastapi/pull/5096) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, remove Classiq, add ImgWhale. PR [#5079](https://github.com/tiangolo/fastapi/pull/5079) by [@tiangolo](https://github.com/tiangolo). From c43120258fa89bc20d6f8ee671b6ead9ab223fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 14 Jul 2022 13:19:42 +0200 Subject: [PATCH 573/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20removing=20body=20?= =?UTF-8?q?from=20status=20codes=20that=20do=20not=20support=20it=20(#5145?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/openapi/constants.py | 1 - fastapi/openapi/utils.py | 12 ++++------- fastapi/routing.py | 33 +++++++++++++++++------------ fastapi/utils.py | 7 ++++++ tests/test_response_code_no_body.py | 9 +++++++- 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/fastapi/openapi/constants.py b/fastapi/openapi/constants.py index 3e69e5524..1897ad750 100644 --- a/fastapi/openapi/constants.py +++ b/fastapi/openapi/constants.py @@ -1,3 +1,2 @@ METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"} -STATUS_CODES_WITH_NO_BODY = {100, 101, 102, 103, 204, 304} REF_PREFIX = "#/components/schemas/" diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 4eb727bd4..5d3d95c24 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -9,11 +9,7 @@ from fastapi.datastructures import DefaultPlaceholder from fastapi.dependencies.models import Dependant from fastapi.dependencies.utils import get_flat_dependant, get_flat_params from fastapi.encoders import jsonable_encoder -from fastapi.openapi.constants import ( - METHODS_WITH_BODY, - REF_PREFIX, - STATUS_CODES_WITH_NO_BODY, -) +from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX from fastapi.openapi.models import OpenAPI from fastapi.params import Body, Param from fastapi.responses import Response @@ -21,6 +17,7 @@ from fastapi.utils import ( deep_dict_update, generate_operation_id_for_path, get_model_definitions, + is_body_allowed_for_status_code, ) from pydantic import BaseModel from pydantic.fields import ModelField, Undefined @@ -265,9 +262,8 @@ def get_openapi_path( operation.setdefault("responses", {}).setdefault(status_code, {})[ "description" ] = route.response_description - if ( - route_response_media_type - and route.status_code not in STATUS_CODES_WITH_NO_BODY + if route_response_media_type and is_body_allowed_for_status_code( + route.status_code ): response_schema = {"type": "string"} if lenient_issubclass(current_response_class, JSONResponse): diff --git a/fastapi/routing.py b/fastapi/routing.py index a6542c15a..6f1a8e900 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -29,13 +29,13 @@ from fastapi.dependencies.utils import ( ) from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError -from fastapi.openapi.constants import STATUS_CODES_WITH_NO_BODY from fastapi.types import DecoratedCallable from fastapi.utils import ( create_cloned_field, create_response_field, generate_unique_id, get_value_or_default, + is_body_allowed_for_status_code, ) from pydantic import BaseModel from pydantic.error_wrappers import ErrorWrapper, ValidationError @@ -232,7 +232,17 @@ def get_request_handler( if raw_response.background is None: raw_response.background = background_tasks return raw_response - response_data = await serialize_response( + response_args: Dict[str, Any] = {"background": background_tasks} + # If status_code was set, use it, otherwise use the default from the + # response class, in the case of redirect it's 307 + current_status_code = ( + status_code if status_code else sub_response.status_code + ) + if current_status_code is not None: + response_args["status_code"] = current_status_code + if sub_response.status_code: + response_args["status_code"] = sub_response.status_code + content = await serialize_response( field=response_field, response_content=raw_response, include=response_model_include, @@ -243,15 +253,10 @@ def get_request_handler( exclude_none=response_model_exclude_none, is_coroutine=is_coroutine, ) - response_args: Dict[str, Any] = {"background": background_tasks} - # If status_code was set, use it, otherwise use the default from the - # response class, in the case of redirect it's 307 - if status_code is not None: - response_args["status_code"] = status_code - response = actual_response_class(response_data, **response_args) + response = actual_response_class(content, **response_args) + if not is_body_allowed_for_status_code(status_code): + response.body = b"" response.headers.raw.extend(sub_response.headers.raw) - if sub_response.status_code: - response.status_code = sub_response.status_code return response return app @@ -377,8 +382,8 @@ class APIRoute(routing.Route): status_code = int(status_code) self.status_code = status_code if self.response_model: - assert ( - status_code not in STATUS_CODES_WITH_NO_BODY + assert is_body_allowed_for_status_code( + status_code ), f"Status code {status_code} must not have a response body" response_name = "Response_" + self.unique_id self.response_field = create_response_field( @@ -410,8 +415,8 @@ class APIRoute(routing.Route): assert isinstance(response, dict), "An additional response must be a dict" model = response.get("model") if model: - assert ( - additional_status_code not in STATUS_CODES_WITH_NO_BODY + assert is_body_allowed_for_status_code( + additional_status_code ), f"Status code {additional_status_code} must not have a response body" response_name = f"Response_{additional_status_code}_{self.unique_id}" response_field = create_response_field(name=response_name, type_=model) diff --git a/fastapi/utils.py b/fastapi/utils.py index a7e135bca..887d57c90 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -18,6 +18,13 @@ if TYPE_CHECKING: # pragma: nocover from .routing import APIRoute +def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool: + if status_code is None: + return True + current_status_code = int(status_code) + return not (current_status_code < 200 or current_status_code in {204, 304}) + + def get_model_definitions( *, flat_models: Set[Union[Type[BaseModel], Type[Enum]]], diff --git a/tests/test_response_code_no_body.py b/tests/test_response_code_no_body.py index 45e2fabc7..6d9b5c333 100644 --- a/tests/test_response_code_no_body.py +++ b/tests/test_response_code_no_body.py @@ -28,7 +28,7 @@ class JsonApiError(BaseModel): responses={500: {"description": "Error", "model": JsonApiError}}, ) async def a(): - pass # pragma: no cover + pass @app.get("/b", responses={204: {"description": "No Content"}}) @@ -106,3 +106,10 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == openapi_schema + + +def test_get_response(): + response = client.get("/a") + assert response.status_code == 204, response.text + assert "content-length" not in response.headers + assert response.content == b"" From 43d8ebfb4d118b5c904b40f66a5faaedff298611 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:20:21 +0000 Subject: [PATCH 574/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e7326d0f1..042d4a921 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix removing body from status codes that do not support it. PR [#5145](https://github.com/tiangolo/fastapi/pull/5145) by [@tiangolo](https://github.com/tiangolo). * 👷 Add Dependabot. PR [#5128](https://github.com/tiangolo/fastapi/pull/5128) by [@tiangolo](https://github.com/tiangolo). * ♻️ Move from `Optional[X]` to `Union[X, None]` for internal utils. PR [#5124](https://github.com/tiangolo/fastapi/pull/5124) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, remove Dropbase, add Doist. PR [#5096](https://github.com/tiangolo/fastapi/pull/5096) by [@tiangolo](https://github.com/tiangolo). From ff47d50a9b59bbb96d64fb12bd6d584c9aed6595 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 13:20:51 +0200 Subject: [PATCH 575/814] =?UTF-8?q?=E2=AC=86=20Bump=20actions/setup-python?= =?UTF-8?q?=20from=202=20to=204=20(#5129)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 4. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-docs.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 505d66f9f..7f0c4fa66 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -15,7 +15,7 @@ jobs: run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: "3.7" - uses: actions/cache@v2 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9dde4e066..ad61ff7a8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,7 @@ jobs: run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: "3.6" - uses: actions/cache@v2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f0a82344e..dbc452048 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - uses: actions/cache@v2 From 2fcf044a9009e299ed22b4ae2c376ea3163cd256 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:21:27 +0000 Subject: [PATCH 576/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 042d4a921..d522ed333 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump actions/setup-python from 2 to 4. PR [#5129](https://github.com/tiangolo/fastapi/pull/5129) by [@dependabot[bot]](https://github.com/apps/dependabot). * 🐛 Fix removing body from status codes that do not support it. PR [#5145](https://github.com/tiangolo/fastapi/pull/5145) by [@tiangolo](https://github.com/tiangolo). * 👷 Add Dependabot. PR [#5128](https://github.com/tiangolo/fastapi/pull/5128) by [@tiangolo](https://github.com/tiangolo). * ♻️ Move from `Optional[X]` to `Union[X, None]` for internal utils. PR [#5124](https://github.com/tiangolo/fastapi/pull/5124) by [@tiangolo](https://github.com/tiangolo). From 397a2e3484e043cfce857bc8a709691dad690ac4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 13:21:37 +0200 Subject: [PATCH 577/814] =?UTF-8?q?=E2=AC=86=20Bump=20dawidd6/action-downl?= =?UTF-8?q?oad-artifact=20from=202.9.0=20to=202.21.1=20(#5130)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump dawidd6/action-download-artifact from 2.9.0 to 2.21.1 Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 2.9.0 to 2.21.1. - [Release notes](https://github.com/dawidd6/action-download-artifact/releases) - [Commits](https://github.com/dawidd6/action-download-artifact/compare/v2.9.0...v2.21.1) --- updated-dependencies: - dependency-name: dawidd6/action-download-artifact dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/preview-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml index 104c2677f..49a9a50c1 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/preview-docs.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Download Artifact Docs - uses: dawidd6/action-download-artifact@v2.9.0 + uses: dawidd6/action-download-artifact@v2.21.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} workflow: build-docs.yml From 7c3137301b2b5051c78ae4b42c9c36fc7bbc2769 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 13:22:02 +0200 Subject: [PATCH 578/814] =?UTF-8?q?=E2=AC=86=20Bump=20codecov/codecov-acti?= =?UTF-8?q?on=20from=202=20to=203=20(#5131)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 2 to 3. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v2...v3) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dbc452048..dfa3ed2df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,4 +38,4 @@ jobs: - name: Test run: bash scripts/test.sh - name: Upload coverage - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v3 From 6497cb08f5314e78f3bad842fbfc17f43be79add Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 13:22:16 +0200 Subject: [PATCH 579/814] =?UTF-8?q?=E2=AC=86=20Bump=20nwtgck/actions-netli?= =?UTF-8?q?fy=20from=201.1.5=20to=201.2.3=20(#5132)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-docs.yml | 2 +- .github/workflows/preview-docs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 7f0c4fa66..bdc664429 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -41,7 +41,7 @@ jobs: name: docs-zip path: ./docs.zip - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v1.1.5 + uses: nwtgck/actions-netlify@v1.2.3 with: publish-dir: './site' production-branch: master diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml index 49a9a50c1..a05b367d4 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/preview-docs.yml @@ -25,7 +25,7 @@ jobs: rm -f docs.zip - name: Deploy to Netlify id: netlify - uses: nwtgck/actions-netlify@v1.1.5 + uses: nwtgck/actions-netlify@v1.2.3 with: publish-dir: './site' production-deploy: false From 3ccb9604781cdc0d5cdfe7b112b96b0bea4044b8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:22:19 +0000 Subject: [PATCH 580/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d522ed333..86e26372d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump dawidd6/action-download-artifact from 2.9.0 to 2.21.1. PR [#5130](https://github.com/tiangolo/fastapi/pull/5130) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump actions/setup-python from 2 to 4. PR [#5129](https://github.com/tiangolo/fastapi/pull/5129) by [@dependabot[bot]](https://github.com/apps/dependabot). * 🐛 Fix removing body from status codes that do not support it. PR [#5145](https://github.com/tiangolo/fastapi/pull/5145) by [@tiangolo](https://github.com/tiangolo). * 👷 Add Dependabot. PR [#5128](https://github.com/tiangolo/fastapi/pull/5128) by [@tiangolo](https://github.com/tiangolo). From b7bd3c1d55b98b475c9d1e11edf5b1a2ab96fedc Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:23:15 +0000 Subject: [PATCH 581/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 86e26372d..44d08b86b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump codecov/codecov-action from 2 to 3. PR [#5131](https://github.com/tiangolo/fastapi/pull/5131) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump dawidd6/action-download-artifact from 2.9.0 to 2.21.1. PR [#5130](https://github.com/tiangolo/fastapi/pull/5130) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump actions/setup-python from 2 to 4. PR [#5129](https://github.com/tiangolo/fastapi/pull/5129) by [@dependabot[bot]](https://github.com/apps/dependabot). * 🐛 Fix removing body from status codes that do not support it. PR [#5145](https://github.com/tiangolo/fastapi/pull/5145) by [@tiangolo](https://github.com/tiangolo). From c15fce3248f83444106409e82d31fa0381ce7600 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:24:11 +0000 Subject: [PATCH 582/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 44d08b86b..8ff9f8fcc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump nwtgck/actions-netlify from 1.1.5 to 1.2.3. PR [#5132](https://github.com/tiangolo/fastapi/pull/5132) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump codecov/codecov-action from 2 to 3. PR [#5131](https://github.com/tiangolo/fastapi/pull/5131) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump dawidd6/action-download-artifact from 2.9.0 to 2.21.1. PR [#5130](https://github.com/tiangolo/fastapi/pull/5130) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump actions/setup-python from 2 to 4. PR [#5129](https://github.com/tiangolo/fastapi/pull/5129) by [@dependabot[bot]](https://github.com/apps/dependabot). From 100799cde2c7a9ea86c9addcf6b9a8766c9a8415 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 13:25:32 +0200 Subject: [PATCH 583/814] =?UTF-8?q?=E2=AC=86=20[pre-commit.ci]=20pre-commi?= =?UTF-8?q?t=20autoupdate=20(#5030)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.2.0 → v4.3.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.2.0...v4.3.0) - [github.com/asottile/pyupgrade: v2.32.1 → v2.37.1](https://github.com/asottile/pyupgrade/compare/v2.32.1...v2.37.1) - [github.com/psf/black: 22.3.0 → 22.6.0](https://github.com/psf/black/compare/22.3.0...22.6.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5c278571e..6944e4a25 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.3.0 hooks: - id: check-added-large-files - id: check-toml @@ -12,7 +12,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/asottile/pyupgrade - rev: v2.32.1 + rev: v2.37.1 hooks: - id: pyupgrade args: @@ -43,7 +43,7 @@ repos: name: isort (pyi) types: [pyi] - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 22.6.0 hooks: - id: black ci: From 606028dc8c395d1f93ee9ec59047834634f5ac9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 11:26:14 +0000 Subject: [PATCH 584/814] =?UTF-8?q?=E2=AC=86=20Bump=20actions/checkout=20f?= =?UTF-8?q?rom=202=20to=203=20(#5133)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump actions/checkout from 2 to 3 Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-docs.yml | 2 +- .github/workflows/latest-changes.yml | 2 +- .github/workflows/notify-translations.yml | 2 +- .github/workflows/people.yml | 2 +- .github/workflows/preview-docs.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/test.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index bdc664429..512d70078 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -13,7 +13,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml index 5783c993a..4aa8475b6 100644 --- a/.github/workflows/latest-changes.yml +++ b/.github/workflows/latest-changes.yml @@ -20,7 +20,7 @@ jobs: latest-changes: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: # To allow latest-changes to commit to master token: ${{ secrets.ACTIONS_TOKEN }} diff --git a/.github/workflows/notify-translations.yml b/.github/workflows/notify-translations.yml index 7e414ab95..2fcb7595e 100644 --- a/.github/workflows/notify-translations.yml +++ b/.github/workflows/notify-translations.yml @@ -9,7 +9,7 @@ jobs: notify-translations: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 diff --git a/.github/workflows/people.yml b/.github/workflows/people.yml index 2004ee7b3..4b47b4072 100644 --- a/.github/workflows/people.yml +++ b/.github/workflows/people.yml @@ -14,7 +14,7 @@ jobs: fastapi-people: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml index a05b367d4..9e71a461a 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/preview-docs.yml @@ -10,7 +10,7 @@ jobs: preview-docs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Download Artifact Docs uses: dawidd6/action-download-artifact@v2.21.1 with: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ad61ff7a8..4686fd0d4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,7 +13,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dfa3ed2df..763dbc44b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: From 19701d12fb9078c81072d1c4907d255554f286fd Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:26:52 +0000 Subject: [PATCH 585/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8ff9f8fcc..fcd57540b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5030](https://github.com/tiangolo/fastapi/pull/5030) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * ⬆ Bump nwtgck/actions-netlify from 1.1.5 to 1.2.3. PR [#5132](https://github.com/tiangolo/fastapi/pull/5132) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump codecov/codecov-action from 2 to 3. PR [#5131](https://github.com/tiangolo/fastapi/pull/5131) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump dawidd6/action-download-artifact from 2.9.0 to 2.21.1. PR [#5130](https://github.com/tiangolo/fastapi/pull/5130) by [@dependabot[bot]](https://github.com/apps/dependabot). From 48b7804a791579648359353ed06400d9cc595dc7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:27:49 +0000 Subject: [PATCH 586/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fcd57540b..3fe585e72 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump actions/checkout from 2 to 3. PR [#5133](https://github.com/tiangolo/fastapi/pull/5133) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5030](https://github.com/tiangolo/fastapi/pull/5030) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * ⬆ Bump nwtgck/actions-netlify from 1.1.5 to 1.2.3. PR [#5132](https://github.com/tiangolo/fastapi/pull/5132) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump codecov/codecov-action from 2 to 3. PR [#5131](https://github.com/tiangolo/fastapi/pull/5131) by [@dependabot[bot]](https://github.com/apps/dependabot). From 120cf49089f2ce0e1d34534a3295157e29026636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Wo=C5=BAniak?= <41345824+Valaraucoo@users.noreply.github.com> Date: Thu, 14 Jul 2022 13:30:09 +0200 Subject: [PATCH 587/814] =?UTF-8?q?=F0=9F=8C=90=F0=9F=87=B5=F0=9F=87=B1=20?= =?UTF-8?q?Add=20Polish=20translation=20for=20`docs/pl/docs/tutorial/first?= =?UTF-8?q?-steps.md`=20(#5024)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: Polish translation for tutorial/first-steps.md * docs: Polish translation / fixes after cr --- docs/pl/docs/tutorial/first-steps.md | 334 +++++++++++++++++++++++++++ docs/pl/mkdocs.yml | 1 + 2 files changed, 335 insertions(+) create mode 100644 docs/pl/docs/tutorial/first-steps.md diff --git a/docs/pl/docs/tutorial/first-steps.md b/docs/pl/docs/tutorial/first-steps.md new file mode 100644 index 000000000..9406d703d --- /dev/null +++ b/docs/pl/docs/tutorial/first-steps.md @@ -0,0 +1,334 @@ +# Pierwsze kroki + +Najprostszy plik FastAPI może wyglądać tak: + +```Python +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Skopiuj to do pliku `main.py`. + +Uruchom serwer: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +!!! note + Polecenie `uvicorn main:app` odnosi się do: + + * `main`: plik `main.py` ("moduł" Python). + * `app`: obiekt utworzony w pliku `main.py` w lini `app = FastAPI()`. + * `--reload`: sprawia, że serwer uruchamia się ponownie po zmianie kodu. Używany tylko w trakcie tworzenia oprogramowania. + +Na wyjściu znajduje się linia z czymś w rodzaju: + +```hl_lines="4" +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +Ta linia pokazuje adres URL, pod którym Twoja aplikacja jest obsługiwana, na Twoim lokalnym komputerze. + +### Sprawdź to + +Otwórz w swojej przeglądarce http://127.0.0.1:8000. + +Zobaczysz odpowiedź w formacie JSON: + +```JSON +{"message": "Hello World"} +``` + +### Interaktywna dokumentacja API + +Przejdź teraz do http://127.0.0.1:8000/docs. + +Zobaczysz automatyczną i interaktywną dokumentację API (dostarczoną przez Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Alternatywna dokumentacja API + +Teraz przejdź do http://127.0.0.1:8000/redoc. + +Zobaczysz alternatywną automatycznie wygenerowaną dokumentację API (dostarczoną przez ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +### OpenAPI + +**FastAPI** generuje "schemat" z całym Twoim API przy użyciu standardu **OpenAPI** służącego do definiowania API. + +#### Schema + +"Schema" jest definicją lub opisem czegoś. Nie jest to kod, który go implementuje, ale po prostu abstrakcyjny opis. + +#### API "Schema" + +W typ przypadku, OpenAPI to specyfikacja, która dyktuje sposób definiowania schematu interfejsu API. + +Definicja schematu zawiera ścieżki API, możliwe parametry, które są przyjmowane przez endpointy, itp. + +#### "Schemat" danych + +Termin "schemat" może również odnosić się do wyglądu niektórych danych, takich jak zawartość JSON. + +W takim przypadku będzie to oznaczać atrybuty JSON, ich typy danych itp. + +#### OpenAPI i JSON Schema + +OpenAPI definiuje API Schema dla Twojego API, który zawiera definicje (lub "schematy") danych wysyłanych i odbieranych przez Twój interfejs API przy użyciu **JSON Schema**, standardu dla schematów danych w formacie JSON. + +#### Sprawdź `openapi.json` + +Jeśli jesteś ciekawy, jak wygląda surowy schemat OpenAPI, FastAPI automatycznie generuje JSON Schema z opisami wszystkich Twoich API. + +Możesz to zobaczyć bezpośrednio pod adresem: http://127.0.0.1:8000/openapi.json. + +Zobaczysz JSON zaczynający się od czegoś takiego: + +```JSON +{ + "openapi": "3.0.2", + "info": { + "title": "FastAPI", + "version": "0.1.0" + }, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + + + +... +``` + +#### Do czego służy OpenAPI + +Schemat OpenAPI jest tym, co zasila dwa dołączone interaktywne systemy dokumentacji. + +Istnieją dziesiątki alternatyw, wszystkie oparte na OpenAPI. Możesz łatwo dodać dowolną z nich do swojej aplikacji zbudowanej za pomocą **FastAPI**. + +Możesz go również użyć do automatycznego generowania kodu dla klientów, którzy komunikują się z Twoim API. Na przykład aplikacje frontendowe, mobilne lub IoT. + +## Przypomnijmy, krok po kroku + +### Krok 1: zaimportuj `FastAPI` + +```Python hl_lines="1" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +`FastAPI` jest klasą, która zapewnia wszystkie funkcjonalności Twojego API. + +!!! note "Szczegóły techniczne" + `FastAPI` jest klasą, która dziedziczy bezpośrednio z `Starlette`. + + Oznacza to, że możesz korzystać ze wszystkich funkcjonalności Starlette również w `FastAPI`. + + +### Krok 2: utwórz instancję `FastAPI` + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Zmienna `app` będzie tutaj "instancją" klasy `FastAPI`. + +Będzie to główny punkt interakcji przy tworzeniu całego interfejsu API. + +Ta zmienna `app` jest tą samą zmienną, do której odnosi się `uvicorn` w poleceniu: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Jeśli stworzysz swoją aplikację, np.: + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial002.py!} +``` + +I umieścisz to w pliku `main.py`, to będziesz mógł tak wywołać `uvicorn`: + +
+ +```console +$ uvicorn main:my_awesome_api --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +### Krok 3: wykonaj *operację na ścieżce* + +#### Ścieżka + +"Ścieżka" tutaj odnosi się do ostatniej części adresu URL, zaczynając od pierwszego `/`. + +Więc, w adresie URL takim jak: + +``` +https://example.com/items/foo +``` + +...ścieżką będzie: + +``` +/items/foo +``` + +!!! info + "Ścieżka" jest zazwyczaj nazywana "path", "endpoint" lub "route'. + +Podczas budowania API, "ścieżka" jest głównym sposobem na oddzielenie "odpowiedzialności" i „zasobów”. + +#### Operacje + +"Operacje" tutaj odnoszą się do jednej z "metod" HTTP. + +Jedna z: + +* `POST` +* `GET` +* `PUT` +* `DELETE` + +...i te bardziej egzotyczne: + +* `OPTIONS` +* `HEAD` +* `PATCH` +* `TRACE` + +W protokole HTTP można komunikować się z każdą ścieżką za pomocą jednej (lub więcej) "metod". + +--- + +Podczas tworzenia API zwykle używasz tych metod HTTP do wykonania określonej akcji. + +Zazwyczaj używasz: + +* `POST`: do tworzenia danych. +* `GET`: do odczytywania danych. +* `PUT`: do aktualizacji danych. +* `DELETE`: do usuwania danych. + +Tak więc w OpenAPI każda z metod HTTP nazywana jest "operacją". + +Będziemy je również nazywali "**operacjami**". + +#### Zdefiniuj *dekorator operacji na ścieżce* + +```Python hl_lines="6" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +`@app.get("/")` mówi **FastAPI** że funkcja poniżej odpowiada za obsługę żądań, które trafiają do: + +* ścieżki `/` +* używając operacji get + +!!! info "`@decorator` Info" + Składnia `@something` jest w Pythonie nazywana "dekoratorem". + + Umieszczasz to na szczycie funkcji. Jak ładną ozdobną czapkę (chyba stąd wzięła się nazwa). + + "Dekorator" przyjmuje funkcję znajdującą się poniżej jego i coś z nią robi. + + W naszym przypadku dekorator mówi **FastAPI**, że poniższa funkcja odpowiada **ścieżce** `/` z **operacją** `get`. + + Jest to "**dekorator operacji na ścieżce**". + +Możesz również użyć innej operacji: + +* `@app.post()` +* `@app.put()` +* `@app.delete()` + +Oraz tych bardziej egzotycznych: + +* `@app.options()` +* `@app.head()` +* `@app.patch()` +* `@app.trace()` + +!!! tip + Możesz dowolnie używać każdej operacji (metody HTTP). + + **FastAPI** nie narzuca żadnego konkretnego znaczenia. + + Informacje tutaj są przedstawione jako wskazówka, a nie wymóg. + + Na przykład, używając GraphQL, normalnie wykonujesz wszystkie akcje używając tylko operacji `POST`. + +### Krok 4: zdefiniuj **funkcję obsługującą ścieżkę** + +To jest nasza "**funkcja obsługująca ścieżkę**": + +* **ścieżka**: to `/`. +* **operacja**: to `get`. +* **funkcja**: to funkcja poniżej "dekoratora" (poniżej `@app.get("/")`). + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Jest to funkcja Python. + +Zostanie ona wywołana przez **FastAPI** za każdym razem, gdy otrzyma żądanie do adresu URL "`/`" przy użyciu operacji `GET`. + +W tym przypadku jest to funkcja "asynchroniczna". + +--- + +Możesz również zdefiniować to jako normalną funkcję zamiast `async def`: + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial003.py!} +``` + +!!! note + Jeśli nie znasz różnicy, sprawdź [Async: *"In a hurry?"*](/async/#in-a-hurry){.internal-link target=_blank}. + +### Krok 5: zwróć zawartość + +```Python hl_lines="8" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Możesz zwrócić `dict`, `list`, pojedynczą wartość jako `str`, `int`, itp. + +Możesz również zwrócić modele Pydantic (więcej o tym później). + +Istnieje wiele innych obiektów i modeli, które zostaną automatycznie skonwertowane do formatu JSON (w tym ORM itp.). Spróbuj użyć swoich ulubionych, jest bardzo prawdopodobne, że są już obsługiwane. + +## Podsumowanie + +* Zaimportuj `FastAPI`. +* Stwórz instancję `app`. +* Dodaj **dekorator operacji na ścieżce** (taki jak `@app.get("/")`). +* Napisz **funkcję obsługującą ścieżkę** (taką jak `def root(): ...` powyżej). +* Uruchom serwer deweloperski (`uvicorn main:app --reload`). diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 0c3d100e7..86383d985 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -58,6 +58,7 @@ nav: - zh: /zh/ - Samouczek: - tutorial/index.md + - tutorial/first-steps.md markdown_extensions: - toc: permalink: true From fb26c1ee70c271edb0796c20ccf4c187d1d536e9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:30:45 +0000 Subject: [PATCH 588/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3fe585e72..b43845e06 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐🇵🇱 Add Polish translation for `docs/pl/docs/tutorial/first-steps.md`. PR [#5024](https://github.com/tiangolo/fastapi/pull/5024) by [@Valaraucoo](https://github.com/Valaraucoo). * ⬆ Bump actions/checkout from 2 to 3. PR [#5133](https://github.com/tiangolo/fastapi/pull/5133) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5030](https://github.com/tiangolo/fastapi/pull/5030) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * ⬆ Bump nwtgck/actions-netlify from 1.1.5 to 1.2.3. PR [#5132](https://github.com/tiangolo/fastapi/pull/5132) by [@dependabot[bot]](https://github.com/apps/dependabot). From 80cb57e4b22ca81708129da3ee79beea5b574f23 Mon Sep 17 00:00:00 2001 From: wakabame <35513518+wakabame@users.noreply.github.com> Date: Thu, 14 Jul 2022 20:34:38 +0900 Subject: [PATCH 589/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Japanese=20transla?= =?UTF-8?q?tion=20for=20`docs/ja/docs/advanced/index.md`=20(#5043)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Amazyra Co-authored-by: tokusumi <41147016+tokusumi@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/ja/docs/advanced/index.md | 24 ++++++++++++++++++++++++ docs/ja/mkdocs.yml | 1 + 2 files changed, 25 insertions(+) create mode 100644 docs/ja/docs/advanced/index.md diff --git a/docs/ja/docs/advanced/index.md b/docs/ja/docs/advanced/index.md new file mode 100644 index 000000000..676f60359 --- /dev/null +++ b/docs/ja/docs/advanced/index.md @@ -0,0 +1,24 @@ +# ユーザーガイド 応用編 + +## さらなる機能 + +[チュートリアル - ユーザーガイド](../tutorial/){.internal-link target=_blank}により、**FastAPI**の主要な機能は十分に理解できたことでしょう。 + +以降のセクションでは、チュートリアルでは説明しきれなかったオプションや設定、および機能について説明します。 + +!!! tip "豆知識" + 以降のセクションは、 **必ずしも"応用編"ではありません**。 + + ユースケースによっては、その中から解決策を見つけられるかもしれません。 + +## 先にチュートリアルを読む + +[チュートリアル - ユーザーガイド](../tutorial/){.internal-link target=_blank}の知識があれば、**FastAPI**の主要な機能を利用することができます。 + +以降のセクションは、すでにチュートリアルを読んで、その主要なアイデアを理解できていることを前提としています。 + +## テスト駆動開発のコース + +このセクションの内容を補完するために脱初心者用コースを受けたい場合は、**TestDriven.io**による、Test-Driven Development with FastAPI and Dockerを確認するのがよいかもしれません。 + +現在、このコースで得られた利益の10%が**FastAPI**の開発のために寄付されています。🎉 😄 diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 055404fea..1548b1905 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -78,6 +78,7 @@ nav: - tutorial/testing.md - tutorial/debugging.md - 高度なユーザーガイド: + - advanced/index.md - advanced/path-operation-advanced-configuration.md - advanced/additional-status-codes.md - advanced/response-directly.md From c5954d3bc0852a0b0450a54dea014733c63413f5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:35:16 +0000 Subject: [PATCH 590/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b43845e06..eb078f165 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Japanese translation for `docs/ja/docs/advanced/index.md`. PR [#5043](https://github.com/tiangolo/fastapi/pull/5043) by [@wakabame](https://github.com/wakabame). * 🌐🇵🇱 Add Polish translation for `docs/pl/docs/tutorial/first-steps.md`. PR [#5024](https://github.com/tiangolo/fastapi/pull/5024) by [@Valaraucoo](https://github.com/Valaraucoo). * ⬆ Bump actions/checkout from 2 to 3. PR [#5133](https://github.com/tiangolo/fastapi/pull/5133) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5030](https://github.com/tiangolo/fastapi/pull/5030) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). From b4a98a7224b642e9a728366137cc5675269a731d Mon Sep 17 00:00:00 2001 From: Robin <51365552+MrRawbin@users.noreply.github.com> Date: Thu, 14 Jul 2022 13:45:01 +0200 Subject: [PATCH 591/814] =?UTF-8?q?=F0=9F=8C=90=20Start=20of=20Swedish=20t?= =?UTF-8?q?ranslation=20(#5062)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/az/mkdocs.yml | 7 +- docs/de/mkdocs.yml | 7 +- docs/en/mkdocs.yml | 7 +- docs/es/mkdocs.yml | 7 +- docs/fa/mkdocs.yml | 7 +- docs/fr/mkdocs.yml | 7 +- docs/id/mkdocs.yml | 7 +- docs/it/mkdocs.yml | 7 +- docs/ja/mkdocs.yml | 7 +- docs/ko/mkdocs.yml | 7 +- docs/nl/mkdocs.yml | 7 +- docs/pl/mkdocs.yml | 7 +- docs/pt/mkdocs.yml | 7 +- docs/ru/mkdocs.yml | 7 +- docs/sq/mkdocs.yml | 7 +- docs/sv/docs/index.md | 468 +++++++++++++++++++++++++++++++++++ docs/sv/mkdocs.yml | 140 +++++++++++ docs/sv/overrides/.gitignore | 0 docs/tr/mkdocs.yml | 7 +- docs/uk/mkdocs.yml | 7 +- docs/zh/mkdocs.yml | 7 +- 21 files changed, 698 insertions(+), 36 deletions(-) create mode 100644 docs/sv/docs/index.md create mode 100644 docs/sv/mkdocs.yml create mode 100644 docs/sv/overrides/.gitignore diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index 60bd8eaad..7ebf94384 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -123,6 +124,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index c72f325f6..c617e55af 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -124,6 +125,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 322de0f2f..04639200d 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -230,6 +231,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index b544f9b38..cd1c04ed3 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -133,6 +134,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/fa/mkdocs.yml b/docs/fa/mkdocs.yml index 3966a6026..79975288a 100644 --- a/docs/fa/mkdocs.yml +++ b/docs/fa/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -123,6 +124,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index bf0d2b21c..69a323cec 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -138,6 +139,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index 769547d11..6c9f88c90 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -123,6 +124,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index ebec9a642..5f0b7c73b 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -123,6 +124,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 1548b1905..66694ef36 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -165,6 +166,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 60cf7d30a..ddadebe7b 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -133,6 +134,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/nl/mkdocs.yml b/docs/nl/mkdocs.yml index 9cd1e0401..620a4b25f 100644 --- a/docs/nl/mkdocs.yml +++ b/docs/nl/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -123,6 +124,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index 86383d985..c04f3c1c6 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -126,6 +127,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 2bb0b568d..51d448c95 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -148,6 +149,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index bb0702489..816a0d3a0 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -124,6 +125,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index 8914395fe..4df6d5b1f 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -123,6 +124,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/sv/docs/index.md b/docs/sv/docs/index.md new file mode 100644 index 000000000..fd52f994c --- /dev/null +++ b/docs/sv/docs/index.md @@ -0,0 +1,468 @@ + +{!../../../docs/missing-translation.md!} + + +

+ FastAPI +

+

+ FastAPI framework, high performance, easy to learn, fast to code, ready for production +

+

+ + Test + + + Coverage + + + Package version + + + Supported Python versions + +

+ +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: https://github.com/tiangolo/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. + +The key features are: + +* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). + +* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * +* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. + +* estimation based on tests on an internal development team, building production applications. + +## Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + + + +Other sponsors + +## Opinions + +"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" + +
Kabir Khan - Microsoft (ref)
+ +--- + +"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" + +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
+ +--- + +"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" + +
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
+ +--- + +"_I’m over the moon excited about **FastAPI**. It’s so fun!_" + +
Brian Okken - Python Bytes podcast host (ref)
+ +--- + +"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" + +
Timothy Crosley - Hug creator (ref)
+ +--- + +"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" + +"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" + +
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +## **Typer**, the FastAPI of CLIs + + + +If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. + +**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 + +## Requirements + +Python 3.6+ + +FastAPI stands on the shoulders of giants: + +* Starlette for the web parts. +* Pydantic for the data parts. + +## Installation + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+ +You will also need an ASGI server, for production such as Uvicorn or Hypercorn. + +
+ +```console +$ pip install "uvicorn[standard]" + +---> 100% +``` + +
+ +## Example + +### Create it + +* Create a file `main.py` with: + +```Python +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} +``` + +
+Or use async def... + +If your code uses `async` / `await`, use `async def`: + +```Python hl_lines="9 14" +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} +``` + +**Note**: + +If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. + +
+ +### Run it + +Run the server with: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+About the command uvicorn main:app --reload... + +The command `uvicorn main:app` refers to: + +* `main`: the file `main.py` (the Python "module"). +* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. +* `--reload`: make the server restart after code changes. Only do this for development. + +
+ +### Check it + +Open your browser at http://127.0.0.1:8000/items/5?q=somequery. + +You will see the JSON response as: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +You already created an API that: + +* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. +* Both _paths_ take `GET` operations (also known as HTTP _methods_). +* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. +* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. + +### Interactive API docs + +Now go to http://127.0.0.1:8000/docs. + +You will see the automatic interactive API documentation (provided by Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Alternative API docs + +And now, go to http://127.0.0.1:8000/redoc. + +You will see the alternative automatic documentation (provided by ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Example upgrade + +Now modify the file `main.py` to receive a body from a `PUT` request. + +Declare the body using standard Python types, thanks to Pydantic. + +```Python hl_lines="4 9-12 25-27" +from typing import Union + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Union[bool, None] = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} +``` + +The server should reload automatically (because you added `--reload` to the `uvicorn` command above). + +### Interactive API docs upgrade + +Now go to http://127.0.0.1:8000/docs. + +* The interactive API documentation will be automatically updated, including the new body: + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) + +* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) + +### Alternative API docs upgrade + +And now, go to http://127.0.0.1:8000/redoc. + +* The alternative documentation will also reflect the new query parameter and body: + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Recap + +In summary, you declare **once** the types of parameters, body, etc. as function parameters. + +You do that with standard modern Python types. + +You don't have to learn a new syntax, the methods or classes of a specific library, etc. + +Just standard **Python 3.6+**. + +For example, for an `int`: + +```Python +item_id: int +``` + +or for a more complex `Item` model: + +```Python +item: Item +``` + +...and with that single declaration you get: + +* Editor support, including: + * Completion. + * Type checks. +* Validation of data: + * Automatic and clear errors when the data is invalid. + * Validation even for deeply nested JSON objects. +* Conversion of input data: coming from the network to Python data and types. Reading from: + * JSON. + * Path parameters. + * Query parameters. + * Cookies. + * Headers. + * Forms. + * Files. +* Conversion of output data: converting from Python data and types to network data (as JSON): + * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). + * `datetime` objects. + * `UUID` objects. + * Database models. + * ...and many more. +* Automatic interactive API documentation, including 2 alternative user interfaces: + * Swagger UI. + * ReDoc. + +--- + +Coming back to the previous code example, **FastAPI** will: + +* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. +* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. + * If it is not, the client will see a useful, clear error. +* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. + * As the `q` parameter is declared with `= None`, it is optional. + * Without the `None` it would be required (as is the body in the case with `PUT`). +* For `PUT` requests to `/items/{item_id}`, Read the body as JSON: + * Check that it has a required attribute `name` that should be a `str`. + * Check that it has a required attribute `price` that has to be a `float`. + * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. + * All this would also work for deeply nested JSON objects. +* Convert from and to JSON automatically. +* Document everything with OpenAPI, that can be used by: + * Interactive documentation systems. + * Automatic client code generation systems, for many languages. +* Provide 2 interactive documentation web interfaces directly. + +--- + +We just scratched the surface, but you already get the idea of how it all works. + +Try changing the line with: + +```Python + return {"item_name": item.name, "item_id": item_id} +``` + +...from: + +```Python + ... "item_name": item.name ... +``` + +...to: + +```Python + ... "item_price": item.price ... +``` + +...and see how your editor will auto-complete the attributes and know their types: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +For a more complete example including more features, see the Tutorial - User Guide. + +**Spoiler alert**: the tutorial - user guide includes: + +* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. +* How to set **validation constraints** as `maximum_length` or `regex`. +* A very powerful and easy to use **Dependency Injection** system. +* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. +* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). +* **GraphQL** integration with Strawberry and other libraries. +* Many extra features (thanks to Starlette) as: + * **WebSockets** + * extremely easy tests based on `requests` and `pytest` + * **CORS** + * **Cookie Sessions** + * ...and more. + +## Performance + +Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) + +To understand more about it, see the section Benchmarks. + +## Optional Dependencies + +Used by Pydantic: + +* ujson - for faster JSON "parsing". +* email_validator - for email validation. + +Used by Starlette: + +* requests - Required if you want to use the `TestClient`. +* jinja2 - Required if you want to use the default template configuration. +* python-multipart - Required if you want to support form "parsing", with `request.form()`. +* itsdangerous - Required for `SessionMiddleware` support. +* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). +* ujson - Required if you want to use `UJSONResponse`. + +Used by FastAPI / Starlette: + +* uvicorn - for the server that loads and serves your application. +* orjson - Required if you want to use `ORJSONResponse`. + +You can install all of these with `pip install "fastapi[all]"`. + +## License + +This project is licensed under the terms of the MIT license. diff --git a/docs/sv/mkdocs.yml b/docs/sv/mkdocs.yml new file mode 100644 index 000000000..fa0296d5c --- /dev/null +++ b/docs/sv/mkdocs.yml @@ -0,0 +1,140 @@ +site_name: FastAPI +site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production +site_url: https://fastapi.tiangolo.com/sv/ +theme: + name: material + custom_dir: overrides + palette: + - media: '(prefers-color-scheme: light)' + scheme: default + primary: teal + accent: amber + toggle: + icon: material/lightbulb + name: Switch to light mode + - media: '(prefers-color-scheme: dark)' + scheme: slate + primary: teal + accent: amber + toggle: + icon: material/lightbulb-outline + name: Switch to dark mode + features: + - search.suggest + - search.highlight + - content.tabs.link + icon: + repo: fontawesome/brands/github-alt + logo: https://fastapi.tiangolo.com/img/icon-white.svg + favicon: https://fastapi.tiangolo.com/img/favicon.png + language: sv +repo_name: tiangolo/fastapi +repo_url: https://github.com/tiangolo/fastapi +edit_uri: '' +plugins: +- search +- markdownextradata: + data: data +nav: +- FastAPI: index.md +- Languages: + - en: / + - az: /az/ + - de: /de/ + - es: /es/ + - fa: /fa/ + - fr: /fr/ + - id: /id/ + - it: /it/ + - ja: /ja/ + - ko: /ko/ + - nl: /nl/ + - pl: /pl/ + - pt: /pt/ + - ru: /ru/ + - sq: /sq/ + - sv: /sv/ + - tr: /tr/ + - uk: /uk/ + - zh: /zh/ +markdown_extensions: +- toc: + permalink: true +- markdown.extensions.codehilite: + guess_lang: false +- mdx_include: + base_path: docs +- admonition +- codehilite +- extra +- pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format '' +- pymdownx.tabbed: + alternate_style: true +extra: + analytics: + provider: google + property: UA-133183413-1 + social: + - icon: fontawesome/brands/github-alt + link: https://github.com/tiangolo/fastapi + - icon: fontawesome/brands/discord + link: https://discord.gg/VQjSZaeJmf + - icon: fontawesome/brands/twitter + link: https://twitter.com/fastapi + - icon: fontawesome/brands/linkedin + link: https://www.linkedin.com/in/tiangolo + - icon: fontawesome/brands/dev + link: https://dev.to/tiangolo + - icon: fontawesome/brands/medium + link: https://medium.com/@tiangolo + - icon: fontawesome/solid/globe + link: https://tiangolo.com + alternate: + - link: / + name: en - English + - link: /az/ + name: az + - link: /de/ + name: de + - link: /es/ + name: es - español + - link: /fa/ + name: fa + - link: /fr/ + name: fr - français + - link: /id/ + name: id + - link: /it/ + name: it - italiano + - link: /ja/ + name: ja - 日本語 + - link: /ko/ + name: ko - 한국어 + - link: /nl/ + name: nl + - link: /pl/ + name: pl + - link: /pt/ + name: pt - português + - link: /ru/ + name: ru - русский язык + - link: /sq/ + name: sq - shqip + - link: /sv/ + name: sv - svenska + - link: /tr/ + name: tr - Türkçe + - link: /uk/ + name: uk - українська мова + - link: /zh/ + name: zh - 汉语 +extra_css: +- https://fastapi.tiangolo.com/css/termynal.css +- https://fastapi.tiangolo.com/css/custom.css +extra_javascript: +- https://fastapi.tiangolo.com/js/termynal.js +- https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/sv/overrides/.gitignore b/docs/sv/overrides/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 74186033c..5371cb71f 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -126,6 +127,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index ddf299d8b..fd371765a 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -123,6 +124,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index a72ecb657..c1c35c6ed 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -5,14 +5,14 @@ theme: name: material custom_dir: overrides palette: - - media: "(prefers-color-scheme: light)" + - media: '(prefers-color-scheme: light)' scheme: default primary: teal accent: amber toggle: icon: material/lightbulb name: Switch to light mode - - media: "(prefers-color-scheme: dark)" + - media: '(prefers-color-scheme: dark)' scheme: slate primary: teal accent: amber @@ -53,6 +53,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -174,6 +175,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ From 2226f962ffffeae09d959ab96f65d6692c1ec87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 14 Jul 2022 13:45:26 +0200 Subject: [PATCH 592/814] =?UTF-8?q?=F0=9F=94=A7=20Add=20config=20for=20Swe?= =?UTF-8?q?dish=20translations=20notification=20(#5147)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/notify-translations/app/translations.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/notify-translations/app/translations.yml b/.github/actions/notify-translations/app/translations.yml index 0e5093f3a..a68167ff8 100644 --- a/.github/actions/notify-translations/app/translations.yml +++ b/.github/actions/notify-translations/app/translations.yml @@ -15,3 +15,4 @@ id: 3717 az: 3994 nl: 4701 uz: 4883 +sv: 5146 From 86fb017aadf973200e7a0f79281d73fb5bc4ccc8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:45:51 +0000 Subject: [PATCH 593/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index eb078f165..0c97db5ca 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Start of Swedish translation. PR [#5062](https://github.com/tiangolo/fastapi/pull/5062) by [@MrRawbin](https://github.com/MrRawbin). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/index.md`. PR [#5043](https://github.com/tiangolo/fastapi/pull/5043) by [@wakabame](https://github.com/wakabame). * 🌐🇵🇱 Add Polish translation for `docs/pl/docs/tutorial/first-steps.md`. PR [#5024](https://github.com/tiangolo/fastapi/pull/5024) by [@Valaraucoo](https://github.com/Valaraucoo). * ⬆ Bump actions/checkout from 2 to 3. PR [#5133](https://github.com/tiangolo/fastapi/pull/5133) by [@dependabot[bot]](https://github.com/apps/dependabot). From 801e90863a51108ea4e363d3836b095a48c264df Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 11:46:23 +0000 Subject: [PATCH 594/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0c97db5ca..714401fde 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add config for Swedish translations notification. PR [#5147](https://github.com/tiangolo/fastapi/pull/5147) by [@tiangolo](https://github.com/tiangolo). * 🌐 Start of Swedish translation. PR [#5062](https://github.com/tiangolo/fastapi/pull/5062) by [@MrRawbin](https://github.com/MrRawbin). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/index.md`. PR [#5043](https://github.com/tiangolo/fastapi/pull/5043) by [@wakabame](https://github.com/wakabame). * 🌐🇵🇱 Add Polish translation for `docs/pl/docs/tutorial/first-steps.md`. PR [#5024](https://github.com/tiangolo/fastapi/pull/5024) by [@Valaraucoo](https://github.com/Valaraucoo). From 85dc173d192b5514cd81bc1e6f62dc3b867930fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 14 Jul 2022 14:37:37 +0200 Subject: [PATCH 595/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20Jina=20sponsor?= =?UTF-8?q?=20badges=20(#5151)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🍱 Update Jina badges * 💄 Tweak sponsors badge CSS * 🔧 Update Jina sponsor * 📝 Re-generate README --- README.md | 2 +- docs/en/data/sponsors.yml | 6 +++--- docs/en/docs/css/custom.css | 2 +- docs/en/docs/img/sponsors/jina-ai-banner.png | Bin 0 -> 14153 bytes docs/en/docs/img/sponsors/jina-ai.png | Bin 0 -> 26112 bytes docs/en/overrides/main.html | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 docs/en/docs/img/sponsors/jina-ai-banner.png create mode 100644 docs/en/docs/img/sponsors/jina-ai.png diff --git a/README.md b/README.md index 505005ae9..bcea9fe73 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ The key features are: - + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index c99c4b57a..efd0f00f8 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -1,7 +1,7 @@ gold: - - url: https://bit.ly/2QSouzH - title: "Jina: build neural search-as-a-service for any kind of data in just minutes." - img: https://fastapi.tiangolo.com/img/sponsors/jina.svg + - url: https://bit.ly/3PjOZqc + title: "DiscoArt: Create compelling Disco Diffusion artworks in just one line" + img: https://fastapi.tiangolo.com/img/sponsors/jina-ai.png - url: https://cryptapi.io/ title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway." img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css index 7d3503e49..42b752bcf 100644 --- a/docs/en/docs/css/custom.css +++ b/docs/en/docs/css/custom.css @@ -94,7 +94,7 @@ a.announce-link:hover { .announce-wrapper .sponsor-badge { display: block; position: absolute; - top: -5px; + top: -10px; right: 0; font-size: 0.5rem; color: #999; diff --git a/docs/en/docs/img/sponsors/jina-ai-banner.png b/docs/en/docs/img/sponsors/jina-ai-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..3ac6b44adcf4b0c28df130ca0e16c674ea43e229 GIT binary patch literal 14153 zcmV-PH@3)$P)l00009a7bBm000id z000id0mpBsWB>pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H1AOJ~3 zK~#90-CcK_6h+#8-tL~6p4r5*gassn2Z#g%f+AuA_1!m@);`}9mnb|Z=7={7EFu=?yWk5tM%QAdEpL;zJ z2p|v$fQXhKVlg&N zvtvJG7Ra&;Ns@MHn!EFTTLWF!xuKzQ>5{U#c zGXjAC0Kg#bfaK58dW^T>Mwq0Ql zW+2P*E=g}!OFXRsGb0j-a6BGw^|xtjTZ}{^L_{f)NJoL0QC(e)^73*fBI;-zg7ZRd zN6{RSc<-f$3kHKJ*V0F?MAU>dawV8-`RZs=F-_AY4IxB6AD?X!AOOhLVQZQO02~Me z$SDuQFglV*NYgZS)MqWe#IBJ*b`?ow1F=<+n25+xN#+YXj@_=#aipMKK_a_~s9Fml z1R5I~S=aS8eV2A1O4fB9b#--6RTZkLb}0F3nnrbXbzE9n+Hn#HfuPDkgp@+~r2r|C z!T{h%^=`*OR#*Taa{f!k;ef#uiWj>TnC(F&v;B)1PJf@?@n4_nI18jq%F#LTR!sw)L{B#{UqNZ0ke?I9h2 z-63^k0|8(m1h+F8BHa4O?Y&31{?Cmy8%#2tp zhFC0yKp?=Xs!~VU858On}C5DCC1o zN|GyV3Ev_R>ypzerU>l=(X`KJZ>P_IXmZ;M)8t|nq?1IpM>y>&Gqy*zVo}8x{Q0`~ z(7<)}<=pHUIU?>;!r$M- z5m)Yuoj*3>+b1_$Y9`_o;z)T(_nMsyTff<{tiaO=aa!N+Ugjp(GUeYPnI?521ECNA z5)2sxi8+nsfVdIG+zs#Y8!MjWs21_ONt?iS=aUkbq9{3gyeW#p!CH70ic<$E;NnlN-r0wF1>zOqzXuzToa{PsU9tcMs_04yxk z6?;@zb^z;7hEYQLB~D`w_a~?Pac_7Zmk0^X*XW=1$1=0qaV-Y=O~8%}@L=kw(h&@c=%Ha0?*WvHr( zTdnIK8lbHW6KDPZah(`2ylNFvVPCN>N2iF1vc-18C&x#!Ij2^jD*p_FC# z$&pkTwb3d(@YM~xxnXUdrJM5p8As}pB(-V;FUvAQp-@g0x2;6d!u*iD+{kEl=I_lA(B8Kkd^4#Xyof~;z*Y;a&>%g z+^lmg;O10XwyS6!x!!%qg+!#WWAXbN?xbJIAynMG7Vw#uTXDl}zvit{cI}1V?{BjTn21~=X^q!gs|jRG z>12%UG}-c!06_q#l1vDRJ?bZqq~S;(l0_DZkD&OadQk6%t_+#-eY!tc*1%M#Z`R~3UnaA zNfOyozZ!q}@)9;VcNb1Cc}RtYDDT_{W>p<_L@NMGd~H+Zkt7MBP$;hvh+}Ne=NY?_ zX4Lb_vfNq{>=5$EKp6R^!M18D@7Kzv(%KcH@FSjmk*1Xo1^^UpiQ~avU&>2DOIj6| zEX!GS`a)H4(Py92Y`>*?F$D1PxEJ_-{r;@+MWa#fs1Ce2BoYY@hr=B*|7O}7b7At zQfG`RI-E?WGi64-j{zBwJT?nQ`hWyTWT~nonIQWl_*Dsk0tLY$1%Z%)K!J=vP(mOi z!>?LQ7;DfGt}~#=1tghJ+%9P^ejBclt9zh>S#1^1I*R?rAeg zf&|%MY&q{e{9*GSn3e)Lhg<5yOr z^lOawj(nb}Vzu~AxzLH?xPUXg%7JqHmsX7`PhWqFs{ zfNXcz4khiu2aLku1y)}sdIqtVu@_4A>Xj0vbYxFpPUh!3!seuD8flsapU($XRdX`9 zw~9cxq0h-Zao`Cr(%iE@!4;pM$0l00Iy|r>L~{R0Dc*uqB2j>R12v?RaDTW*pJKHwZvg74Y(! zml@62f_J4Mote?t*qHOWd+mw$-+Gg;Is0rX1P~X%XV1T#F&ueTq38(cx(;2}A+YDs-2psuWXwKNtVG}k_n0;!LQ2bRIZ||cR|*) zBq9`bQ88$Yf{jb+AuFkcrWW`R2q};i2_ylbA_XPoD*QniM%+L{l@47KC@4|Df?*nr zXoCq!vZN0^A)qG&5>XRc%!Hu{mjG;sDhQKZf-w!Yr4_HXikhmjJf)i;hHNn{R9`Vh zbf17lTi_s}~RUO=6i3k9IW2TXb4DEOy5Nwa@AH|q#48%UA>VU2ntkqAPe zP*$C)6E^)#y+qQIU%amCDTaSZlF^ifv%>M9M#GpfI9c^K3D9*6VNzleUiQ75H4@V> zIcnrEvLu28g5aDw?_7-KdBG{uye87+m*;kcB*_pWbr2(jpe7RznX%yX8GObm=VGkX zAK(1v-&pBe*=*dhqJR=wle(8Hven&mn5M~%jg4@O<+(nWZ`f?ue#V|2W2#3RvB+2#MN++(o31n|&G#C<0+m>J|7BM6H?t>AJk&2lkf)>bm>LNIiJc%zOri)*oCeH4;nxlhRoArO)+ z7e$Sch?+=54RBo8Gv6)MRr;jGOyB@ugxM8NM)o|C7Hxe$TPeGbEzbx+eds%pJ^4da62ujV6Pxt`AM*##eu ze;vQudIb-;;yPS$&iOR1a}Zq!NHDOz+Qd(fFToxEn8gjD2G^LzJ$m5u`yQp!Mh?cW zWP;AXnvFVMzvmsE@X%BmDO;7PVZMpqi^X{MuyH9b)BpM5_zXW#|8axrs0gc4`-cpM9(+_ zUtIBfXY7J_1>@F9vw5*^G2(*;;mQBL=9YQ&t=lp6&7;{rW(>}|?$318!0s3*6J!9} z62SV!^?3KD`}p13H?4GzJ{n)&cRvN~j=cUKjhGpGobR~wa@u>RgjcduW_|zt@ywG? z(@;6taWt$las3&yS-t&qoOAd@8eE{D2LaV4u%p(*x+j+5zUQvsYPs5(aF{|Oliz-q zuIttn0C3?Y$KZi|?%)sa9!l?6WeH+n`K8P8-i1D#J#sJxN<TKn+>U4da4j!NECK)&UVlA4J@-6!`1|wh<#_3A z4YS9N!rpeBU%f%coOAxccQ3m=C5?XP&&G9E-AIRaFG5cOGyt3G1%7^E74EqGT>e@A zxy5{@#P{&S^!AA-0RW_nCgayrPr-~%Pw>Kj{hPWt-|fXXuJV6`Yfqd)qXH6S02^u; zOaAZ$ZvXIi9H+P&UtsK5Ty)DlbX5Ot7$93J@QN6)?(-_Vc;hWRFY;+l`Lb2r&J6by zgL~ct($zPB9O=V~L2{)J*Le!51VRKzl0_u4hRh!~qW&{fr^d6zO zQb({*X-Xifj9`I+(jEcy99rB&%u)g}y7VtfQE2=867-k}Ns-`JB>000y7fz-u~LI3 zn*b4t%6!=O=3k9c{NyPu#xP4vUf$^Ob|>Y4f^Gw{*Xw@I1-Q~35VZ# zmo(CIZPUjZ&iM5~yp?QkjCoJvqXkp=nS1_D#gav^iY{>MkmC>u_~EE^8bXAVKE0dH z4OyR9_+(6Z?_+v+-y!gh-2(&+=^|sujr(EriHoEwk2{r@smp*NLvYW3U!$o3UrN}0 z`uWi3? zXN>n_??3E~H+k?6u+bB8*YS;LF69(DvI8;}psLcAw8%gsxX#gJ;h^i~6Lc z(=!0{JhTL(KK&C-Ja00t`QJs%J|9XXLdXuY`rr^=8hsV@0#GRdnMOlqQ4ucv`#)%$ zNAjbxJopb`m#E*^qWCoQBujJuFu55Jx{pBW%~%RmNHMFlGgiY0Q}+P0Ha zyjXZ5dE4;7&V&IEABF)}zCpj9GlflRnKak4M@UiF_b-bf_ZAnQ5`I0+}^nLD8KO*hkhY2@L>;0!k?EpNw< zErWxIYofx_Jo_E( z$8CGxo?@jk41;r3$L&{;xoav=fJqO}q-^%2vRiJ!Gil_JjxGhjsc)T6$BJX2n`TOe zMipgFHz)&>p8hokih(G*_FDWqjXcuPs~6!Jnz~H+EV5%_{ z+W!0Fi45f7MQ0V5`o?c)3QuWOJ`#xp>g((CClDW%z!2;nT1+4jF`FJyk^CFA$V7`; z_q3RR7BvyAH!Qn@4S!HZs6;_YH$S@d4?*!KTWzF9gBCMW^udbHk`|OeGF)S29BaO+ z#;OI?SocjWv{Y+yr=wSnT z)PNQ-EP@Oh(831vu-WWk=oWbxf?+b?lTxdIGf`0V?1{l1RY83%@MZm%O~U4)YgYi6 z41B#o!@Ki$VE8e;-HIm|n0NC}7}ru?$0p4&_50Jc2Jh`<@U-RrwcyIC7?zt=hlP6Ej%NAi472$&8 zj!UuQuJ|&6D~`K`kG}kRe!4!|lq*X*noA{EySN1!YTJ3{MCazX3QA= z(|_+{M^Q%vjNN-I86_pyucT?0)NR7vBuNqu*mtCxSnNX```>zMiW+a#LJhOVUcv{Q zF_RyvYH+Ws3NY#BGs!1X2LlR#oeAKRm0^4{XGIg;{nks5!ru=ZowA(vimTV-ruElw zui?YVOO)RqI~V6q7{w<)@^}8aR>R_21B+`7aQ_g}K=vkDEuvlnUb=W5CQUk(&wT3> z-tH}vQH04nxydu4xEPn6eg=6{{of0u~@NJAW2`q$m589-}1Ow(o82 zYK&(93;wzV$B#XYC*6JzFYvU*f&egm)N~qq!;Q4BC)G7yXqY+bY#u&i2LGd`(Y;<$ z1YCC7b#2OD-ULFdz+`q036%L@Kqi7r&fnxAF+c*=$llYz2TKF!JGv8k?^}XmkGpOn zqN8#{3`RUvDv^B>g2l;(!2ouw4kKJ+ARZQI*r}s-b86#f2270+t4mH?Qi2MKItLIc z@uBzdVwbptU~Krd4vDY;42$I@5R~-yvF$wB4nc6s%V35~Ny2mHdH?{2Lhx38y&kBc zn$+^o!%qACIZH9)kO6%5V^{N7kDaPw1MqtFJl_AuQ7D|2^hFB!LLg*SQ93!U2&dnGbiNirim zY7~z25O-w-@R!*a@)z6Zp!&;?aR01xc~K7WR4ij$bJ!_->v>1<9iLy3b*NqN#TS_C zA?==r4ngCvVHjhddo6=BA&4&OKUV!`0 zo5|mL;wU^!MnA28N*?OMz=NZ2qy*l&&M=vO&R`p#56vC!e~B!!f5{Or!!k^QI0&&fP25bnyaeTVEOIW z;&0W-b|4cluux%YSH_m2cJ2qb`u1D7+7muFy(0*-yr~>LgY1*M!7b0KxB#0BHW(~hY9}v*37Cc@(RAu%b=Q(iDC+8m zzd%M=-=tSq_4+U>*T-QdteNh_7CEy0K1?2OtY*s0FwK<7jKVYB(L0irYHCpBd9I)w z=r8)?XC#erxw`Ke0(kM=r=-nIM82gSOJb3@CCh92%CFPwdy0Yo0KYHYmIKeYpwq`!#lfWk^TolFI z2_2W(D!1-KfoXwhco;1kTLAz)d!|S=<`*WGtIOT` z+_H^#|(+6dqb6%)ngMWj2E*34qQUHfL;md&nPW1wfeZLLDV-H%hVI9yX zIT$f|6r-mneAiOoo+r=E+Ln}o%_+KCfmMtOrNTYkymBSu_~YI5_09p5E6Fw@6L7)b zCg1{0$e2gD9O!OzN0nTa>2{0An?Pa-1Co>+^^>eX%1R)1#|Ud;R8m3#AOJQPS|mB% zVgS+VIAZk%A~hQ7cW4M#YcLW5l0xtY2*O~^U1fq2YgkWptJAlGc1;yP0kZkWJJ!W9j_YH_Q>M#=mFd4+`N)!@tMgqwsAPB*5 zm+E4MDXfj2nk>z}Z5zIAj9_w+RjCVtz;6yXlRjAbfi)||nqWrk^P%5}aVS%g4XXaf zA5+qd$AB7Gqc#zbLq}%aX(kwHQ%VAX0CZh<=WvLE^l@7Y@x|jU2l7B@ndh_|aO!E) z*>heufN|+F|0Mtjc~<-;0**Xx3O)SZ!#VX{Len7N5yuM%5=$`2&W9v%D2Fw>q8`;z zOISGfV;1L~M-qUNVZf;1LGC^2NDgZ+4 zkzHjO1)hP1DS)V%w7UQR@6@3QEvI$3q%sL*RE7=MV5O&N`0SLE_=qDWVe0e?Y2V@f zabV{FI>Rz{?>|h%(6?q$(IE;y5PhJP}1VgjtVR#X5G*H+znP&IFAqbO^2pcHs>UX6K2f|=}VVi;W7(0+4Lg z6$9A*QzPoPCtyScgl@U)65Gp7IMPQZ2_&t)2nG_uQ)_jG!DiNZ1FydE8g4l2EZ3O3 z-)l$X(j%_G-#0%9B4QBH$j6_iw}$y8cciRci=P4PYoBjl4op3AEN_-K z1G0>sBgUZIZ^01c=Ib>bMYh^XU}yx`sjY{y~xX(!8?B9ADL;0UB0D* zfU~-tg+JEV9yL>@V3KE4SGx_^CV8z0*0*x@)3#kQlQtFuc*8XDYumQiYY^d2k3K;c z&OU*+DqBH?h3Hz?1GHizK3IMezge{d^+kjc*Zq+mnQ}Nf0SGC;yN`bcn6V4guBd`L0%6>VjxsyHslx>dSCjd^(s@?&d zHRO2yioOB>bQ^gf`W9HO4Wt{`y5!r;5p@t`16bP-28yjAo+*Gw_kDyPG9Cf|1p4*E z-evp1aUP8P^fT55R<}C6ya}Y**o;mhsbh;90wE>MMTI;P2mxegSF#ThuqLn>0`UeT zxyJ@9l1YROBy0i^Cffug!;D+1q+~jT#+@39%MJK#kE39x0Qw#1hcE zNMxOKw)KuX__67y(8cyL2VF~m>%P5_j@fuMHq|sx;ecWs*~yVW6F8(-eI`zo3{}Da4Fu1Yq-Sj5PM7@JowaHnz!nE zE<9=&{kCssS1DSt4!HKXnY<#jA|0Jhn{eHVBweGy|XK5VqjQAMti1j;jl- zQYa1r=gz;82G0ErS9BB7lyUvh@*MJ}h$Iq#M^+pA;%q8de>Ao~@;Y8$^Ey6i2xF|> z(2ug+dZTe*-j+|XV@*F`_;3KgxX#Ie&FAwzWc;-g|-%4`2NXopb-OEZuM& z%{}o%H~faVIOZ0uZg%P_e85riWN0nVBs?(>GqvYdn|sJ5a@q7ac}dddR~Bu==Vc zSoXu?xaI3_Qby3j2P?Sbj1hFvfHD*yv(0DQmtV41lRB`Mgmb3uO{bhVgP!>7{aoR> zchI3BTz~#}y0mX+cNC*Bu+^gIO%!yfxBYk(nb$HuTN4f-oGiDCP%~M9wejcLTu@$)G ziOaLCm5>#kKVFIppLpEfSJT4a^NaE5X|GV#ORurlRNU`KA6}XN41F;36j#N_09L-a zFz58zWp_W*#Pio)&C5Jd_31*Gb^a*2dE!v?^#t8K-@v8we%q=%!4=|iU)KDk zO$DEK?&5(hyuBu2>GkcSHmau>%rhMTK+d97%+|Dj-BKm7XD)~@AVKJCb@I9Z>(*a0 zA)rT17;)2G8J7XX>U8Yo-SHy*3IxVnS$^F&_4?$}yr_1YyZl5@kQa2@^40z!a7!8PiNugjb@a?uftt9y2G5 z=f7>KLN@Dx0I>Aa2rfNj27jo1*y4B7-g*nC-tlK%mca!V03s%^;Hn?-n@^@P0DN`U zZ}|5s*CEsRY{@bM|I2Va_{k@@VaWY7FVzPU6T+- zX(^@-O0KJAn7}8`|A$vB{Q%x$?sHGDmqr6KJHgL6T7F)A73aU0>bB{ivL5(XIKPo9 zGxOGa?-frrM6-VFO>e)=8`G|tAJw8psX=1F0<22Ar@s}!YSmIV_&09EP3N4&FEqxp z#=mZji907<&hs%pue>{`y6Y~?{^t9XDTYID?S;qaa$NH0W4t;`!Uh9B+*^U0Hr>>| z27p}f*=IQO>Z^F3p4pDZ09Jk$!}&9gE{Msvd+blZ6Dz6-nWWz9lo%Nq-5qP|L)jEYDCre`VOirRWq#(&7E zQSsWf`15|l_=!o!;`FnxqLG98p(N;s88%V*-Bx_|;6M4DO|PbSj4Yl1E#B>Jt^QiD zx&d3|)Cq_?{`n6~e&cnXe#1RDeE$QeTR{-9ssw7k*^HO}d@Fwy`6~JCA`$%e=n1@d z=DE1wtV?Kcmr`)8fzAK^hVOX)4xIngqf`;<1|lG^paKag0hlJ{pFW)@9&r>-KWP?v zl$TSn8i0S%1~3@g{(3J?c=ctTdd2NHc%OZ!ObsAXnLypb4S3^`yTnh@Pvk8_2S%@6 zh^*d;_iQI;^~*}UuQXjxtYH3pJoMd499(3XoQrBT@S4^9PCP_lprBsI4`%lA-+ABN zJpGdo`PA7rNTd4oMxjoqU9cT*K5!=+e>#J@_1zx;P*Rn^dUZV#OTlmNJ&qKiKoX3q zs&Cl_gb?K0whfOQc^H52n+tH%{*%zHYbOdqM$L}J3;;#neTT=sU4ik%y}@Ak5&~=H z{)Yh|xMBsK{bmKmmss!OO9-rfQ`0scMm_0w<=x&%bAOM?ZQQv zGw2|`TN1HEiI!$afhdXJ%Br{4$^X z$}2eP`afgpk;l?ror|GpjM|@SvFQF6`0+*ex`yNE_uupDKUb19&|qv^_gPB3JLb>l zH_Jzm0vZ0OfrT{-835{EdkrUk`YE4y%e^>${NYqy9D-J>qh?73-oEuNp0o3cIf1Z z^;u)RiLK#n_+QN}Y;fuXvs}C*#m%6y?V+MjdNEuYv57 ztVw>lfT;)%Kpp|%}gN=1`yW`Y-_B?*4Rg_B9HX_A@(F_ znnuhFRaM)RM2>RuJ86r!p!8^SH&e1 zS(c$FN?wHG#Nj28Y&L=Pm2~%Xv{VSqZOXML!0D4(MIfeJ15I6us@N!)5fx)vPMKIb?8ysMq+yGHJqf3WU8D@1ArkIo9g4( z8jgFjjksoDYi&K^q8i&{pR}g9E%)74bWXbpx~_wnIT#GKMG_%qZuJ(ut%W2>t!k)k zB@QQ=Hf~_$LRD3=H^$nd>WP<7G|jRj$+FD35{kWFi@W-3CIZoQof{h)>6fx^O17OR zy=dcB&m9JbIGk_R>RiSPzYsz%qssa|6iXQBT2$z6_*5CwQ584PSyj*_9|0fP zyA^synSvp71{vh4n;f@TAgxt7n>YcMUBn>^>#b6y1G1M-_o&ZctImjlvc5qSdgg~T zY>A=rrwEL&2@$iT4@p>C>Pif26DfP|6UX+!L`awd4RHfiQ5`!X2^i@H`EUYNktj^o zv9|G_ELu5XXIE~h(^?pYL9tj2!C2+ew=Uu7Qdih-q!!TfzNUJ1?T{wbl z)doiBwhHW9%Wh!mIKEGD|47iqrXSZ11GWu~_UE(KfvJB}pII zh{L_#k`bMmVJ~Wjcs$-@gC2q(opCA!$(r;eNjgf@A_V<10zL_nYh|aTO$4c(ymOwC zE;7$8@`m$DAa2yQWI~Qq0!#9cB!c26s6hpVB|a1uD+m@UkR-y6EiptIb;P44^n`$E z2#Yj?v-Aj(Tj3&^v800)!!QM6xYl$>c!a_qeUf=>g2!%M3B(n%rkvI^s?n)%N z?yqh~@39@EWYF`oIVrr!JGrEk7C$)^(DwY22|m9Jf29P!UxF-4FinQ8nMfoAbj^fe zuha=&XhMUjG$u!NB zQC(7%MOlA4e>0Lo3aKQIX7a|FyhqxKUxN2lOAtc9CXt*xOWK)0aw3n8lsLTTXw_9Z z6h%QG5I`c4|G;byLdrL^+hR%?Iz*x<3LA#8M-xdlrx@~VEVm2u(dIsDmzw*%9j~j( zV&+IB(yW~&2T&%$aVDlYM3MfxCGzl|XL<+cQfoYVa(by>uJDlpAp|0k2!%o+w6wMl zGm{XaJsMMs-(^=3hm%%EtFAJ^@Atzr&8)Mx_he+US+Vu8GQJBDk3Q+~&PFcj$#x)l{G!!Y>0oRB z3FJZ|?O+FK_PeyxB*5G=vkO&M=^!Ggs!GvlbXU4bw-qTWD=%_+2O@%^C}gX)$eE0| zCm>V3CTiWHiTR+tiNnEebvV{_y`M9+wEJIaQj>qG>Julgii<@<8>V`uk9@SQdIZCvI^mg4*(nm)VhlBqEBG5UX T7SUJA00000NkvXXu0mjfJ5Bsy literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/sponsors/jina-ai.png b/docs/en/docs/img/sponsors/jina-ai.png new file mode 100644 index 0000000000000000000000000000000000000000..d6b0bfb4ec24acce9ab9cb4ca46740bb16c702ae GIT binary patch literal 26112 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 X@XdfIPq1E700000NkvXXu0mjfyQ^GY literal 0 HcmV?d00001 diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 9bed0253f..5c7029b85 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -29,9 +29,9 @@
From e3339f6770eaaa35e89ec6c1df917a5fd02d6f39 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 12:38:22 +0000 Subject: [PATCH 596/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 714401fde..84b511c0a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update Jina sponsor badges. PR [#5151](https://github.com/tiangolo/fastapi/pull/5151) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add config for Swedish translations notification. PR [#5147](https://github.com/tiangolo/fastapi/pull/5147) by [@tiangolo](https://github.com/tiangolo). * 🌐 Start of Swedish translation. PR [#5062](https://github.com/tiangolo/fastapi/pull/5062) by [@MrRawbin](https://github.com/MrRawbin). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/index.md`. PR [#5043](https://github.com/tiangolo/fastapi/pull/5043) by [@wakabame](https://github.com/wakabame). From ec2ec482930b0683b5dd6aa4f580c18f1bdd2f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 14 Jul 2022 16:56:40 +0200 Subject: [PATCH 597/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#5154)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/github_sponsors.yml | 197 +++++++++++++++++-------- docs/en/data/people.yml | 246 +++++++++++++++++-------------- 2 files changed, 269 insertions(+), 174 deletions(-) diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml index db4a9acc6..6c1efcbbd 100644 --- a/docs/en/data/github_sponsors.yml +++ b/docs/en/data/github_sponsors.yml @@ -1,16 +1,25 @@ sponsors: -- - login: cryptapi +- - login: github + avatarUrl: https://avatars.githubusercontent.com/u/9919?v=4 + url: https://github.com/github +- - login: Doist + avatarUrl: https://avatars.githubusercontent.com/u/2565372?v=4 + url: https://github.com/Doist + - login: cryptapi avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4 url: https://github.com/cryptapi + - login: BLUE-DEVIL1134 + avatarUrl: https://avatars.githubusercontent.com/u/55914808?u=f283d674fce31be7fb3ed2665b0f20d89958e541&v=4 + url: https://github.com/BLUE-DEVIL1134 - login: jina-ai avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4 url: https://github.com/jina-ai - login: DropbaseHQ avatarUrl: https://avatars.githubusercontent.com/u/85367855?v=4 url: https://github.com/DropbaseHQ -- - login: sushi2all - avatarUrl: https://avatars.githubusercontent.com/u/1043732?v=4 - url: https://github.com/sushi2all +- - login: ObliviousAI + avatarUrl: https://avatars.githubusercontent.com/u/65656077?v=4 + url: https://github.com/ObliviousAI - login: chaserowbotham avatarUrl: https://avatars.githubusercontent.com/u/97751084?v=4 url: https://github.com/chaserowbotham @@ -32,9 +41,6 @@ sponsors: - login: VincentParedes avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4 url: https://github.com/VincentParedes -- - login: plocher - avatarUrl: https://avatars.githubusercontent.com/u/1082871?v=4 - url: https://github.com/plocher - - login: InesIvanova avatarUrl: https://avatars.githubusercontent.com/u/22920417?u=409882ec1df6dbd77455788bb383a8de223dbf6f&v=4 url: https://github.com/InesIvanova @@ -53,7 +59,10 @@ sponsors: - login: BoostryJP avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4 url: https://github.com/BoostryJP -- - login: johnadjei +- - login: nnfuzzy + avatarUrl: https://avatars.githubusercontent.com/u/687670?v=4 + url: https://github.com/nnfuzzy + - login: johnadjei avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4 url: https://github.com/johnadjei - login: HiredScore @@ -68,9 +77,6 @@ sponsors: - login: RodneyU215 avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4 url: https://github.com/RodneyU215 - - login: grillazz - avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=0b32b7073ae1ab8b7f6d2db0188c2e1e357ff451&v=4 - url: https://github.com/grillazz - login: tizz98 avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4 url: https://github.com/tizz98 @@ -80,30 +86,36 @@ sponsors: - login: marutoraman avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4 url: https://github.com/marutoraman + - login: leynier + avatarUrl: https://avatars.githubusercontent.com/u/36774373?u=2284831c821307de562ebde5b59014d5416c7e0d&v=4 + url: https://github.com/leynier - login: mainframeindustries avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4 url: https://github.com/mainframeindustries - login: A-Edge avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4 url: https://github.com/A-Edge + - login: DelfinaCare + avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4 + url: https://github.com/DelfinaCare +- - login: povilasb + avatarUrl: https://avatars.githubusercontent.com/u/1213442?u=b11f58ed6ceea6e8297c9b310030478ebdac894d&v=4 + url: https://github.com/povilasb - - login: Kludex avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: samuelcolvin avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4 url: https://github.com/samuelcolvin - - login: jokull - avatarUrl: https://avatars.githubusercontent.com/u/701?u=0532b62166893d5160ef795c4c8b7512d971af05&v=4 - url: https://github.com/jokull - login: jefftriplett avatarUrl: https://avatars.githubusercontent.com/u/50527?u=af1ddfd50f6afd6d99f333ba2ac8d0a5b245ea74&v=4 url: https://github.com/jefftriplett + - login: medecau + avatarUrl: https://avatars.githubusercontent.com/u/59870?u=f9341c95adaba780828162fd4c7442357ecfcefa&v=4 + url: https://github.com/medecau - login: kamalgill avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4 url: https://github.com/kamalgill - - login: jsutton - avatarUrl: https://avatars.githubusercontent.com/u/280777?v=4 - url: https://github.com/jsutton - login: deserat avatarUrl: https://avatars.githubusercontent.com/u/299332?v=4 url: https://github.com/deserat @@ -117,14 +129,17 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4 url: https://github.com/koxudaxi - login: jqueguiner - avatarUrl: https://avatars.githubusercontent.com/u/690878?u=e4835b2a985a0f2d52018e4926cb5a58c26a62e8&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/690878?u=bd65cc1f228ce6455e56dfaca3ef47c33bc7c3b0&v=4 url: https://github.com/jqueguiner + - login: alexsantos + avatarUrl: https://avatars.githubusercontent.com/u/932219?v=4 + url: https://github.com/alexsantos + - login: tcsmith + avatarUrl: https://avatars.githubusercontent.com/u/989034?u=7d8d741552b3279e8f4d3878679823a705a46f8f&v=4 + url: https://github.com/tcsmith - login: ltieman avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4 url: https://github.com/ltieman - - login: westonsteimel - avatarUrl: https://avatars.githubusercontent.com/u/1593939?u=0f2c0e3647f916fe295d62fa70da7a4c177115e3&v=4 - url: https://github.com/westonsteimel - login: corleyma avatarUrl: https://avatars.githubusercontent.com/u/2080732?u=aed2ff652294a87d666b1c3f6dbe98104db76d26&v=4 url: https://github.com/corleyma @@ -140,6 +155,9 @@ sponsors: - login: Shark009 avatarUrl: https://avatars.githubusercontent.com/u/3163309?u=0c6f4091b0eda05c44c390466199826e6dc6e431&v=4 url: https://github.com/Shark009 + - login: grillazz + avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=0b32b7073ae1ab8b7f6d2db0188c2e1e357ff451&v=4 + url: https://github.com/grillazz - login: dblackrun avatarUrl: https://avatars.githubusercontent.com/u/3528486?v=4 url: https://github.com/dblackrun @@ -152,6 +170,9 @@ sponsors: - login: peterHoburg avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4 url: https://github.com/peterHoburg + - login: gorhack + avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4 + url: https://github.com/gorhack - login: jaredtrog avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4 url: https://github.com/jaredtrog @@ -182,6 +203,9 @@ sponsors: - login: pkucmus avatarUrl: https://avatars.githubusercontent.com/u/6347418?u=98f5918b32e214a168a2f5d59b0b8ebdf57dca0d&v=4 url: https://github.com/pkucmus + - login: ioalloc + avatarUrl: https://avatars.githubusercontent.com/u/6737824?u=6c3a31449f1c92064287171aa9ebe6363a0c9b7b&v=4 + url: https://github.com/ioalloc - login: s3ich4n avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=ba3025d698e1c986655e776ae383a3d60d9d578e&v=4 url: https://github.com/s3ich4n @@ -200,6 +224,9 @@ sponsors: - login: Ge0f3 avatarUrl: https://avatars.githubusercontent.com/u/11887760?u=ccd80f1ac36dcb8517ef5c4e702e8cc5a80cad2f&v=4 url: https://github.com/Ge0f3 + - login: svats2k + avatarUrl: https://avatars.githubusercontent.com/u/12378398?u=ecf28c19f61052e664bdfeb2391f8107d137915c&v=4 + url: https://github.com/svats2k - login: gokulyc avatarUrl: https://avatars.githubusercontent.com/u/13468848?u=269f269d3e70407b5fb80138c52daba7af783997&v=4 url: https://github.com/gokulyc @@ -215,9 +242,6 @@ sponsors: - login: wedwardbeck avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4 url: https://github.com/wedwardbeck - - login: linusg - avatarUrl: https://avatars.githubusercontent.com/u/19366641?u=125e390abef8fff3b3b0d370c369cba5d7fd4c67&v=4 - url: https://github.com/linusg - login: stradivari96 avatarUrl: https://avatars.githubusercontent.com/u/19752586?u=255f5f06a768f518b20cebd6963e840ac49294fd&v=4 url: https://github.com/stradivari96 @@ -230,6 +254,9 @@ sponsors: - login: shuheng-liu avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4 url: https://github.com/shuheng-liu + - login: Joeriksson + avatarUrl: https://avatars.githubusercontent.com/u/25037079?v=4 + url: https://github.com/Joeriksson - login: cometa-haley avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=cec1a3e0643b785288ae8260cc295a85ab344995&v=4 url: https://github.com/cometa-haley @@ -258,23 +285,32 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/35070513?u=b48c05f669d1ea1d329f90dc70e45f10b569ef55&v=4 url: https://github.com/guligon90 - login: ybressler - avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=6621dc9ab53b697912ab2a32211bb29ae90a9112&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=41e2c00f1eebe3c402635f0325e41b4e6511462c&v=4 url: https://github.com/ybressler - - login: iamkarshe - avatarUrl: https://avatars.githubusercontent.com/u/43641892?u=d08c901b359c931784501740610d416558ff3e24&v=4 - url: https://github.com/iamkarshe + - login: ddilidili + avatarUrl: https://avatars.githubusercontent.com/u/42176885?u=c0a849dde06987434653197b5f638d3deb55fc6c&v=4 + url: https://github.com/ddilidili - login: dbanty avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4 url: https://github.com/dbanty + - login: VictorCalderon + avatarUrl: https://avatars.githubusercontent.com/u/44529243?u=cea69884f826a29aff1415493405209e0706d07a&v=4 + url: https://github.com/VictorCalderon + - login: arthuRHD + avatarUrl: https://avatars.githubusercontent.com/u/48015496?u=05a0d5b8b9320eeb7990d35c9337b823f269d2ff&v=4 + url: https://github.com/arthuRHD - login: rafsaf - avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4 url: https://github.com/rafsaf - login: dudikbender avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4 url: https://github.com/dudikbender - login: daisuke8000 - avatarUrl: https://avatars.githubusercontent.com/u/55035595?u=5025e379cd3655ae1a96039efc85223a873d2e38&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/55035595?u=23a3f2f2925ad3efc27c7420041622b7f5fd2b79&v=4 url: https://github.com/daisuke8000 + - login: dazeddd + avatarUrl: https://avatars.githubusercontent.com/u/59472056?u=7a1b668449bf8b448db13e4c575576d24d7d658b&v=4 + url: https://github.com/dazeddd - login: yakkonaut avatarUrl: https://avatars.githubusercontent.com/u/60633704?u=90a71fd631aa998ba4a96480788f017c9904e07b&v=4 url: https://github.com/yakkonaut @@ -291,11 +327,8 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4 url: https://github.com/daverin - login: anthonycepeda - avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=4252c6b6dc5024af502a823a3ac5e7a03a69963f&v=4 url: https://github.com/anthonycepeda - - login: NinaHwang - avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 - url: https://github.com/NinaHwang - login: dotlas avatarUrl: https://avatars.githubusercontent.com/u/88832003?v=4 url: https://github.com/dotlas @@ -347,27 +380,27 @@ sponsors: - login: hardbyte avatarUrl: https://avatars.githubusercontent.com/u/855189?u=aa29e92f34708814d6b67fcd47ca4cf2ce1c04ed&v=4 url: https://github.com/hardbyte + - login: browniebroke + avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4 + url: https://github.com/browniebroke - login: janfilips avatarUrl: https://avatars.githubusercontent.com/u/870699?u=6034d81731ecb41ae5c717e56a901ed46fc039a8&v=4 url: https://github.com/janfilips - - login: scari - avatarUrl: https://avatars.githubusercontent.com/u/964251?v=4 - url: https://github.com/scari + - login: woodrad + avatarUrl: https://avatars.githubusercontent.com/u/1410765?u=86707076bb03d143b3b11afc1743d2aa496bd8bf&v=4 + url: https://github.com/woodrad - login: Pytlicek avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=169dba3bfbc04ed214a914640ff435969f19ddb3&v=4 url: https://github.com/Pytlicek - - login: Celeborn2BeAlive - avatarUrl: https://avatars.githubusercontent.com/u/1659465?u=944517e4db0f6df65070074e81cabdad9c8a434b&v=4 - url: https://github.com/Celeborn2BeAlive + - login: allen0125 + avatarUrl: https://avatars.githubusercontent.com/u/1448456?u=d4feb3d06a61baa4a69857ce371cc53fb4dffd2c&v=4 + url: https://github.com/allen0125 - login: WillHogan avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4 url: https://github.com/WillHogan - login: cbonoz avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4 url: https://github.com/cbonoz - - login: Abbe98 - avatarUrl: https://avatars.githubusercontent.com/u/2631719?u=8a064aba9a710229ad28c616549d81a24191a5df&v=4 - url: https://github.com/Abbe98 - login: rglsk avatarUrl: https://avatars.githubusercontent.com/u/2768101?u=e349c88673f2155fe021331377c656a9d74bcc25&v=4 url: https://github.com/rglsk @@ -386,6 +419,9 @@ sponsors: - login: Alisa-lisa avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4 url: https://github.com/Alisa-lisa + - login: danielunderwood + avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4 + url: https://github.com/danielunderwood - login: unredundant avatarUrl: https://avatars.githubusercontent.com/u/5607577?u=57dd0023365bec03f4fc566df6b81bc0a264a47d&v=4 url: https://github.com/unredundant @@ -401,9 +437,6 @@ sponsors: - login: yenchenLiu avatarUrl: https://avatars.githubusercontent.com/u/9199638?u=8cdf5ae507448430d90f6f3518d1665a23afe99b&v=4 url: https://github.com/yenchenLiu - - login: VivianSolide - avatarUrl: https://avatars.githubusercontent.com/u/9358572?u=4a38ef72dd39e8b262bd5ab819992128b55c52b4&v=4 - url: https://github.com/VivianSolide - login: xncbf avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=866a1311e4bd3ec5ae84185c4fcc99f397c883d7&v=4 url: https://github.com/xncbf @@ -425,12 +458,24 @@ sponsors: - login: logan-connolly avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4 url: https://github.com/logan-connolly + - login: sanghunka + avatarUrl: https://avatars.githubusercontent.com/u/16280020?u=960f5426ae08303229f045b9cc2ed463dcd41c15&v=4 + url: https://github.com/sanghunka + - login: stevenayers + avatarUrl: https://avatars.githubusercontent.com/u/16361214?u=098b797d8d48afb8cd964b717847943b61d24a6d&v=4 + url: https://github.com/stevenayers - login: cdsre avatarUrl: https://avatars.githubusercontent.com/u/16945936?v=4 url: https://github.com/cdsre + - login: aprilcoskun + avatarUrl: https://avatars.githubusercontent.com/u/17393603?u=29145243b4c7fadc80c7099471309cc2c04b6bcc&v=4 + url: https://github.com/aprilcoskun - login: jangia avatarUrl: https://avatars.githubusercontent.com/u/17927101?u=9261b9bb0c3e3bb1ecba43e8915dc58d8c9a077e&v=4 url: https://github.com/jangia + - login: yannicschroeer + avatarUrl: https://avatars.githubusercontent.com/u/22749683?u=4df05a7296c207b91c5d7c7a11c29df5ab313e2b&v=4 + url: https://github.com/yannicschroeer - login: ghandic avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 url: https://github.com/ghandic @@ -440,9 +485,12 @@ sponsors: - login: mertguvencli avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4 url: https://github.com/mertguvencli - - login: dwreeves - avatarUrl: https://avatars.githubusercontent.com/u/31971762?u=69732aba05aa5cf0780866349ebe109cf632b047&v=4 - url: https://github.com/dwreeves + - login: elisoncrum + avatarUrl: https://avatars.githubusercontent.com/u/30413278?u=531190845bb0935dbc1e4f017cda3cb7b4dd0e54&v=4 + url: https://github.com/elisoncrum + - login: HosamAlmoghraby + avatarUrl: https://avatars.githubusercontent.com/u/32025281?u=aa1b09feabccbf9dc506b81c71155f32d126cefa&v=4 + url: https://github.com/HosamAlmoghraby - login: kitaramu0401 avatarUrl: https://avatars.githubusercontent.com/u/33246506?u=929e6efa2c518033b8097ba524eb5347a069bb3b&v=4 url: https://github.com/kitaramu0401 @@ -452,45 +500,72 @@ sponsors: - login: declon avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4 url: https://github.com/declon + - login: alvarobartt + avatarUrl: https://avatars.githubusercontent.com/u/36760800?u=ac9ccb8b9164eb5fe7d5276142591aa1b8080daf&v=4 + url: https://github.com/alvarobartt - login: d-e-h-i-o avatarUrl: https://avatars.githubusercontent.com/u/36816716?v=4 url: https://github.com/d-e-h-i-o + - login: ww-daniel-mora + avatarUrl: https://avatars.githubusercontent.com/u/38921751?u=ae14bc1e40f2dd5a9c5741fc0b0dffbd416a5fa9&v=4 + url: https://github.com/ww-daniel-mora + - login: rwxd + avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=9ddf8023ca3326381ba8fb77285ae36598a15de3&v=4 + url: https://github.com/rwxd - login: ilias-ant avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4 url: https://github.com/ilias-ant - login: arrrrrmin avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=fee5739394fea074cb0b66929d070114a5067aae&v=4 url: https://github.com/arrrrrmin - - login: Nephilim-Jack - avatarUrl: https://avatars.githubusercontent.com/u/48372168?u=6f2bb405238d7efc467536fe01f58df6779c58a9&v=4 - url: https://github.com/Nephilim-Jack + - login: BomGard + avatarUrl: https://avatars.githubusercontent.com/u/47395385?u=8e9052f54e0b8dc7285099c438fa29c55a7d6407&v=4 + url: https://github.com/BomGard - login: akanz1 avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4 url: https://github.com/akanz1 - - login: rooflexx - avatarUrl: https://avatars.githubusercontent.com/u/58993673?u=f8ba450460f1aea18430ed1e4a3889049a3b4dfa&v=4 - url: https://github.com/rooflexx - - login: denisyao1 - avatarUrl: https://avatars.githubusercontent.com/u/60019356?v=4 - url: https://github.com/denisyao1 + - login: shidenko97 + avatarUrl: https://avatars.githubusercontent.com/u/54946990?u=3fdc0caea36af9217dacf1cc7760c7ed9d67dcfe&v=4 + url: https://github.com/shidenko97 + - login: data-djinn + avatarUrl: https://avatars.githubusercontent.com/u/56449985?u=42146e140806908d49bd59ccc96f222abf587886&v=4 + url: https://github.com/data-djinn + - login: leo-jp-edwards + avatarUrl: https://avatars.githubusercontent.com/u/58213433?u=2c128e8b0794b7a66211cd7d8ebe05db20b7e9c0&v=4 + url: https://github.com/leo-jp-edwards - login: apar-tiwari avatarUrl: https://avatars.githubusercontent.com/u/61064197?v=4 url: https://github.com/apar-tiwari + - login: Vyvy-vi + avatarUrl: https://avatars.githubusercontent.com/u/62864373?u=1a9b0b28779abc2bc9b62cb4d2e44d453973c9c3&v=4 + url: https://github.com/Vyvy-vi - login: 0417taehyun avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4 url: https://github.com/0417taehyun + - login: realabja + avatarUrl: https://avatars.githubusercontent.com/u/66185192?u=001e2dd9297784f4218997981b4e6fa8357bb70b&v=4 + url: https://github.com/realabja - login: alessio-proietti avatarUrl: https://avatars.githubusercontent.com/u/67370599?u=8ac73db1e18e946a7681f173abdb640516f88515&v=4 url: https://github.com/alessio-proietti + - login: Mr-Sunglasses + avatarUrl: https://avatars.githubusercontent.com/u/81439109?u=a5d0762fdcec26e18a028aef05323de3c6fb195c&v=4 + url: https://github.com/Mr-Sunglasses - - login: backbord avatarUrl: https://avatars.githubusercontent.com/u/6814946?v=4 url: https://github.com/backbord - - login: sadikkuzu - avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4 - url: https://github.com/sadikkuzu - login: gabrielmbmb avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=6d1e00b5d558e96718312ff910a2318f47cc3145&v=4 url: https://github.com/gabrielmbmb - login: danburonline avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4 url: https://github.com/danburonline + - login: zachspar + avatarUrl: https://avatars.githubusercontent.com/u/41600414?u=edf29c197137f51bace3f19a2ba759662640771f&v=4 + url: https://github.com/zachspar + - login: sownt + avatarUrl: https://avatars.githubusercontent.com/u/44340502?u=c06e3c45fb00a403075172770805fe57ff17b1cf&v=4 + url: https://github.com/sownt + - login: aahouzi + avatarUrl: https://avatars.githubusercontent.com/u/75032370?u=82677ee9cd86b3ccf4e13d9cb6765d8de5713e1e&v=4 + url: https://github.com/aahouzi diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 92aab109f..031c1ca4d 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,12 +1,12 @@ maintainers: - login: tiangolo - answers: 1243 - prs: 300 - avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=5cad72c846b7aba2e960546af490edc7375dafc4&v=4 + answers: 1248 + prs: 318 + avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 335 + count: 352 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: dmontagu @@ -30,19 +30,23 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 - login: raphaelauv - count: 71 + count: 77 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv - login: ArcLightSlavik count: 71 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4 url: https://github.com/ArcLightSlavik +- login: JarroVGIT + count: 68 + avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 + url: https://github.com/JarroVGIT - login: falkben count: 58 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 url: https://github.com/falkben - login: sm-Fifteen - count: 48 + count: 49 avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 url: https://github.com/sm-Fifteen - login: insomnes @@ -53,22 +57,22 @@ experts: count: 43 avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 url: https://github.com/Dustyposa +- login: adriangb + count: 40 + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 + url: https://github.com/adriangb +- login: jgould22 + count: 40 + avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 + url: https://github.com/jgould22 - login: includeamin count: 39 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 url: https://github.com/includeamin -- login: jgould22 - count: 38 - avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 - url: https://github.com/jgould22 - login: STeveShary count: 37 avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 url: https://github.com/STeveShary -- login: adriangb - count: 36 - avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 - url: https://github.com/adriangb - login: prostomarkeloff count: 33 avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4 @@ -81,18 +85,22 @@ experts: count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 url: https://github.com/krishnardt +- login: chbndrhnns + count: 30 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: wshayes count: 29 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes -- login: chbndrhnns - count: 28 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns - login: panla - count: 26 + count: 27 avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 url: https://github.com/panla +- login: acidjunk + count: 25 + avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 + url: https://github.com/acidjunk - login: ghandic count: 25 avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 @@ -121,14 +129,18 @@ experts: count: 19 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 url: https://github.com/retnikt -- login: acidjunk - count: 18 - avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 - url: https://github.com/acidjunk +- login: odiseo0 + count: 19 + avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4 + url: https://github.com/odiseo0 - login: Hultner count: 18 avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 url: https://github.com/Hultner +- login: rafsaf + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4 + url: https://github.com/rafsaf - login: jorgerpo count: 17 avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4 @@ -141,10 +153,6 @@ experts: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 url: https://github.com/harunyasar -- login: rafsaf - count: 17 - avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4 - url: https://github.com/rafsaf - login: waynerv count: 16 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 @@ -153,6 +161,14 @@ experts: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 url: https://github.com/dstlny +- login: jonatasoli + count: 15 + avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4 + url: https://github.com/jonatasoli +- login: hellocoldworld + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/47581948?u=3d2186796434c507a6cb6de35189ab0ad27c356f&v=4 + url: https://github.com/hellocoldworld - login: haizaar count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 @@ -161,10 +177,6 @@ experts: count: 13 avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4 url: https://github.com/valentin994 -- login: hellocoldworld - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/47581948?v=4 - url: https://github.com/hellocoldworld - login: David-Lor count: 12 avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4 @@ -173,10 +185,10 @@ experts: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4 url: https://github.com/yinziyan1206 -- login: jonatasoli +- login: n8sty count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4 - url: https://github.com/jonatasoli + avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 + url: https://github.com/n8sty - login: lowercase00 count: 11 avatarUrl: https://avatars.githubusercontent.com/u/21188280?v=4 @@ -185,39 +197,31 @@ experts: count: 11 avatarUrl: https://avatars.githubusercontent.com/u/40475662?u=e58ef61034e8d0d6a312cc956fb09b9c3332b449&v=4 url: https://github.com/zamiramir -- login: juntatalor - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4 - url: https://github.com/juntatalor -- login: n8sty - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 - url: https://github.com/n8sty -- login: aalifadv - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/78442260?v=4 - url: https://github.com/aalifadv last_month_active: -- login: jgould22 - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 - url: https://github.com/jgould22 -- login: accelleon +- login: JarroVGIT + count: 30 + avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 + url: https://github.com/JarroVGIT +- login: zoliknemet + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4 + url: https://github.com/zoliknemet +- login: iudeen count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/5001614?v=4 - url: https://github.com/accelleon -- login: jonatasoli - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4 - url: https://github.com/jonatasoli + avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 + url: https://github.com/iudeen - login: Kludex - count: 4 + count: 5 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex -- login: yinziyan1206 +- login: odiseo0 + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4 + url: https://github.com/odiseo0 +- login: jonatasoli count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4 - url: https://github.com/yinziyan1206 + avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4 + url: https://github.com/jonatasoli top_contributors: - login: waynerv count: 25 @@ -243,21 +247,21 @@ top_contributors: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 url: https://github.com/mariacamilagl +- login: Kludex + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 + url: https://github.com/Kludex - login: Smlep - count: 9 + count: 10 avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 url: https://github.com/Smlep - login: Serrones count: 8 avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 url: https://github.com/Serrones -- login: Kludex - count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 - url: https://github.com/Kludex - login: RunningIkkyu count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=efb5b45b55584450507834f279ce48d4d64dea2f&v=4 url: https://github.com/RunningIkkyu - login: hard-coders count: 7 @@ -275,6 +279,10 @@ top_contributors: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4 url: https://github.com/Attsun1031 +- login: dependabot + count: 5 + avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4 + url: https://github.com/apps/dependabot - login: jekirl count: 4 avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4 @@ -291,15 +299,31 @@ top_contributors: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki +- login: hitrust + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/3360631?u=5fa1f475ad784d64eb9666bdd43cc4d285dcc773&v=4 + url: https://github.com/hitrust +- login: lsglucas + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 + url: https://github.com/lsglucas +- login: ComicShrimp + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 + url: https://github.com/ComicShrimp - login: NinaHwang count: 4 avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 url: https://github.com/NinaHwang top_reviewers: - login: Kludex - count: 93 + count: 95 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex +- login: tokusumi + count: 49 + avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 + url: https://github.com/tokusumi - login: waynerv count: 47 avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4 @@ -308,10 +332,10 @@ top_reviewers: count: 47 avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4 url: https://github.com/Laineyzhang55 -- login: tokusumi - count: 46 - avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 - url: https://github.com/tokusumi +- login: BilalAlpaslan + count: 45 + avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 + url: https://github.com/BilalAlpaslan - login: ycd count: 45 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 @@ -320,13 +344,13 @@ top_reviewers: count: 41 avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 url: https://github.com/cikay -- login: BilalAlpaslan - count: 40 - avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 - url: https://github.com/BilalAlpaslan +- login: yezz123 + count: 34 + avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 + url: https://github.com/yezz123 - login: AdrianDeAnda count: 33 - avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=b2ea249c6b41ddf98679c8d110d0f67d4a3ebf93&v=4 url: https://github.com/AdrianDeAnda - login: ArcLightSlavik count: 31 @@ -344,10 +368,6 @@ top_reviewers: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki -- login: yezz123 - count: 19 - avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 - url: https://github.com/yezz123 - login: hard-coders count: 19 avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4 @@ -356,6 +376,14 @@ top_reviewers: count: 19 avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4 url: https://github.com/0417taehyun +- login: lsglucas + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 + url: https://github.com/lsglucas +- login: JarroVGIT + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 + url: https://github.com/JarroVGIT - login: zy7y count: 17 avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4 @@ -364,14 +392,14 @@ top_reviewers: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/21978760?v=4 url: https://github.com/yanever -- login: lsglucas - count: 16 - avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 - url: https://github.com/lsglucas - login: SwftAlpc count: 16 avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4 url: https://github.com/SwftAlpc +- login: rjNemo + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 + url: https://github.com/rjNemo - login: Smlep count: 16 avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 @@ -388,18 +416,18 @@ top_reviewers: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4 url: https://github.com/delhi09 -- login: rjNemo - count: 14 - avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 - url: https://github.com/rjNemo -- login: RunningIkkyu - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4 - url: https://github.com/RunningIkkyu - login: sh0nk - count: 12 + count: 13 avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4 url: https://github.com/sh0nk +- login: RunningIkkyu + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=efb5b45b55584450507834f279ce48d4d64dea2f&v=4 + url: https://github.com/RunningIkkyu +- login: solomein-sv + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 + url: https://github.com/solomein-sv - login: mariacamilagl count: 10 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 @@ -412,10 +440,10 @@ top_reviewers: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4 url: https://github.com/maoyibo -- login: solomein-sv +- login: odiseo0 count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 - url: https://github.com/solomein-sv + avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4 + url: https://github.com/odiseo0 - login: graingert count: 9 avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4 @@ -432,6 +460,10 @@ top_reviewers: count: 9 avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4 url: https://github.com/bezaca +- login: raphaelauv + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 + url: https://github.com/raphaelauv - login: blt232018 count: 8 avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4 @@ -460,10 +492,6 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4 url: https://github.com/ryuckel -- login: raphaelauv - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 - url: https://github.com/raphaelauv - login: NastasiaSaby count: 7 avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4 @@ -472,6 +500,10 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause +- login: wakabame + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/35513518?v=4 + url: https://github.com/wakabame - login: AlexandreBiguet count: 7 avatarUrl: https://avatars.githubusercontent.com/u/1483079?u=ff926455cd4cab03c6c49441aa5dc2b21df3e266&v=4 @@ -480,15 +512,3 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/34248814?v=4 url: https://github.com/krocdort -- login: jovicon - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 - url: https://github.com/jovicon -- login: LorhanSohaky - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4 - url: https://github.com/LorhanSohaky -- login: peidrao - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=88c2cb42a99e0f50cdeae3606992568184783ee5&v=4 - url: https://github.com/peidrao From 21fd708c6e9d9be470e287760e324e970fda7b35 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 14:57:21 +0000 Subject: [PATCH 598/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 84b511c0a..230d501c2 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#5154](https://github.com/tiangolo/fastapi/pull/5154) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Jina sponsor badges. PR [#5151](https://github.com/tiangolo/fastapi/pull/5151) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add config for Swedish translations notification. PR [#5147](https://github.com/tiangolo/fastapi/pull/5147) by [@tiangolo](https://github.com/tiangolo). * 🌐 Start of Swedish translation. PR [#5062](https://github.com/tiangolo/fastapi/pull/5062) by [@MrRawbin](https://github.com/MrRawbin). From 169af0217ed771698f518713b12a0f5a74ca3a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 14 Jul 2022 17:04:37 +0200 Subject: [PATCH 599/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20sponsors=20badg?= =?UTF-8?q?e=20configs=20(#5155)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/data/sponsors_badge.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index 10a31b86a..a8bfb0b1b 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -11,3 +11,5 @@ logins: - DropbaseHQ - VincentParedes - BLUE-DEVIL1134 + - ObliviousAI + - Doist From 0be244ad5273b074109b980cae7ba8e83b223fad Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 15:05:19 +0000 Subject: [PATCH 600/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 230d501c2..160518644 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update sponsors badge configs. PR [#5155](https://github.com/tiangolo/fastapi/pull/5155) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#5154](https://github.com/tiangolo/fastapi/pull/5154) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Jina sponsor badges. PR [#5151](https://github.com/tiangolo/fastapi/pull/5151) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add config for Swedish translations notification. PR [#5147](https://github.com/tiangolo/fastapi/pull/5147) by [@tiangolo](https://github.com/tiangolo). From 35244ee83bb94b4f663ffa957f87ef432c137761 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 18:14:54 +0200 Subject: [PATCH 601/814] =?UTF-8?q?=E2=AC=86=20Bump=20actions/cache=20from?= =?UTF-8?q?=202=20to=203=20(#5149)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/cache](https://github.com/actions/cache) from 2 to 3. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-docs.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 512d70078..a0d895911 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -18,7 +18,7 @@ jobs: uses: actions/setup-python@v4 with: python-version: "3.7" - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: cache with: path: ${{ env.pythonLocation }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4686fd0d4..02846cefd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -18,7 +18,7 @@ jobs: uses: actions/setup-python@v4 with: python-version: "3.6" - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: cache with: path: ${{ env.pythonLocation }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 763dbc44b..14dc141d9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: cache with: path: ${{ env.pythonLocation }} From ec3b6e975c33530343bbbcacaebc6288bdb9466a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 18:15:08 +0200 Subject: [PATCH 602/814] =?UTF-8?q?=E2=AC=86=20Bump=20actions/upload-artif?= =?UTF-8?q?act=20from=202=20to=203=20(#5148)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index a0d895911..0d666b82a 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -36,7 +36,7 @@ jobs: run: python3.7 ./scripts/docs.py build-all - name: Zip docs run: bash ./scripts/zip-docs.sh - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: docs-zip path: ./docs.zip From 84f6a030114bccdcfd49546b12d73423b4db1782 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 16:15:31 +0000 Subject: [PATCH 603/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 160518644..802079cd4 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump actions/cache from 2 to 3. PR [#5149](https://github.com/tiangolo/fastapi/pull/5149) by [@dependabot[bot]](https://github.com/apps/dependabot). * 🔧 Update sponsors badge configs. PR [#5155](https://github.com/tiangolo/fastapi/pull/5155) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#5154](https://github.com/tiangolo/fastapi/pull/5154) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Jina sponsor badges. PR [#5151](https://github.com/tiangolo/fastapi/pull/5151) by [@tiangolo](https://github.com/tiangolo). From 49619c0180c40dfb5039874dfbd279e4fed19479 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 16:15:55 +0000 Subject: [PATCH 604/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 802079cd4..e3265c704 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump actions/upload-artifact from 2 to 3. PR [#5148](https://github.com/tiangolo/fastapi/pull/5148) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump actions/cache from 2 to 3. PR [#5149](https://github.com/tiangolo/fastapi/pull/5149) by [@dependabot[bot]](https://github.com/apps/dependabot). * 🔧 Update sponsors badge configs. PR [#5155](https://github.com/tiangolo/fastapi/pull/5155) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#5154](https://github.com/tiangolo/fastapi/pull/5154) by [@tiangolo](https://github.com/tiangolo). From 71b10e58904aa1543a8761bcf4028eee155c1af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 14 Jul 2022 19:04:20 +0200 Subject: [PATCH 605/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20Dependabot=20co?= =?UTF-8?q?mmit=20message=20(#5156)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 946f2358c..cd972a0ba 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,8 +5,12 @@ updates: directory: "/" schedule: interval: "daily" + commit-message: + prefix: ⬆ # Python - package-ecosystem: "pip" directory: "/" schedule: interval: "daily" + commit-message: + prefix: ⬆ From f30b6c6001186794950eca0553d0466c0b59eaa6 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 17:05:01 +0000 Subject: [PATCH 606/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e3265c704..4dce21b64 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update Dependabot commit message. PR [#5156](https://github.com/tiangolo/fastapi/pull/5156) by [@tiangolo](https://github.com/tiangolo). * ⬆ Bump actions/upload-artifact from 2 to 3. PR [#5148](https://github.com/tiangolo/fastapi/pull/5148) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump actions/cache from 2 to 3. PR [#5149](https://github.com/tiangolo/fastapi/pull/5149) by [@dependabot[bot]](https://github.com/apps/dependabot). * 🔧 Update sponsors badge configs. PR [#5155](https://github.com/tiangolo/fastapi/pull/5155) by [@tiangolo](https://github.com/tiangolo). From 9197cbd36cc2a275ecffb231ade6200dbea62326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 14 Jul 2022 19:14:53 +0200 Subject: [PATCH 607/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20translations=20?= =?UTF-8?q?notification=20for=20Hebrew=20(#5158)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/actions/notify-translations/app/translations.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/notify-translations/app/translations.yml b/.github/actions/notify-translations/app/translations.yml index a68167ff8..ac15978a9 100644 --- a/.github/actions/notify-translations/app/translations.yml +++ b/.github/actions/notify-translations/app/translations.yml @@ -16,3 +16,4 @@ az: 3994 nl: 4701 uz: 4883 sv: 5146 +he: 5157 From ee182c6a0ad86083a2855321a51690cf597efd7b Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 17:15:39 +0000 Subject: [PATCH 608/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4dce21b64..714696529 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update translations notification for Hebrew. PR [#5158](https://github.com/tiangolo/fastapi/pull/5158) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Dependabot commit message. PR [#5156](https://github.com/tiangolo/fastapi/pull/5156) by [@tiangolo](https://github.com/tiangolo). * ⬆ Bump actions/upload-artifact from 2 to 3. PR [#5148](https://github.com/tiangolo/fastapi/pull/5148) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump actions/cache from 2 to 3. PR [#5149](https://github.com/tiangolo/fastapi/pull/5149) by [@dependabot[bot]](https://github.com/apps/dependabot). From 59d154fa6f7b7345c4a8e2650954f1cc67230974 Mon Sep 17 00:00:00 2001 From: Itay Raveh <83612679+itay-raveh@users.noreply.github.com> Date: Thu, 14 Jul 2022 17:16:28 +0000 Subject: [PATCH 609/814] =?UTF-8?q?=F0=9F=8C=90=20Start=20of=20Hebrew=20tr?= =?UTF-8?q?anslation=20(#5050)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/az/mkdocs.yml | 3 + docs/de/mkdocs.yml | 3 + docs/en/mkdocs.yml | 3 + docs/es/mkdocs.yml | 3 + docs/fa/mkdocs.yml | 3 + docs/fr/mkdocs.yml | 3 + docs/he/docs/index.md | 464 +++++++++++++++++++++++++++++++++++ docs/he/mkdocs.yml | 140 +++++++++++ docs/he/overrides/.gitignore | 0 docs/id/mkdocs.yml | 3 + docs/it/mkdocs.yml | 3 + docs/ja/mkdocs.yml | 3 + docs/ko/mkdocs.yml | 3 + docs/nl/mkdocs.yml | 3 + docs/pl/mkdocs.yml | 3 + docs/pt/mkdocs.yml | 3 + docs/ru/mkdocs.yml | 3 + docs/sq/mkdocs.yml | 3 + docs/tr/mkdocs.yml | 3 + docs/uk/mkdocs.yml | 3 + docs/zh/mkdocs.yml | 3 + 21 files changed, 658 insertions(+) create mode 100644 docs/he/docs/index.md create mode 100644 docs/he/mkdocs.yml create mode 100644 docs/he/overrides/.gitignore diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index 7ebf94384..90ee0bb82 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -106,6 +107,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index c617e55af..6009dd2fe 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -107,6 +108,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 04639200d..7adfae0f9 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -213,6 +214,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index cd1c04ed3..511ea0255 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -116,6 +117,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/fa/mkdocs.yml b/docs/fa/mkdocs.yml index 79975288a..7d74e0407 100644 --- a/docs/fa/mkdocs.yml +++ b/docs/fa/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -106,6 +107,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 69a323cec..f790c0299 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -121,6 +122,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/he/docs/index.md b/docs/he/docs/index.md new file mode 100644 index 000000000..fa63d8cb7 --- /dev/null +++ b/docs/he/docs/index.md @@ -0,0 +1,464 @@ +

+ FastAPI +

+

+ תשתית FastAPI, ביצועים גבוהים, קלה ללמידה, מהירה לתכנות, מוכנה לסביבת ייצור +

+

+ + Test + + + Coverage + + + Package version + + + Supported Python versions + +

+ +--- + +**תיעוד**: https://fastapi.tiangolo.com + +**קוד**: https://github.com/tiangolo/fastapi + +--- + +FastAPI היא תשתית רשת מודרנית ומהירה (ביצועים גבוהים) לבניית ממשקי תכנות יישומים (API) עם פייתון 3.6+ בהתבסס על רמזי טיפוסים סטנדרטיים. + +תכונות המפתח הן: + +- **מהירה**: ביצועים גבוהים מאוד, בקנה אחד עם NodeJS ו - Go (תודות ל - Starlette ו - Pydantic). [אחת מתשתיות הפייתון המהירות ביותר](#performance). + +- **מהירה לתכנות**: הגבירו את מהירות פיתוח התכונות החדשות בכ - %200 עד %300. \* +- **פחות שגיאות**: מנעו כ - %40 משגיאות אנוש (מפתחים). \* +- **אינטואיטיבית**: תמיכת עורך מעולה. השלמה בכל מקום. פחות זמן ניפוי שגיאות. +- **קלה**: מתוכננת להיות קלה לשימוש וללמידה. פחות זמן קריאת תיעוד. +- **קצרה**: מזערו שכפול קוד. מספר תכונות מכל הכרזת פרמטר. פחות שגיאות. +- **חסונה**: קבלו קוד מוכן לסביבת ייצור. עם תיעוד אינטרקטיבי אוטומטי. +- **מבוססת סטנדרטים**: מבוססת על (ותואמת לחלוטין ל -) הסטדנרטים הפתוחים לממשקי תכנות יישומים: OpenAPI (ידועים לשעבר כ - Swagger) ו - JSON Schema. + +\* הערכה מבוססת על בדיקות של צוות פיתוח פנימי שבונה אפליקציות בסביבת ייצור. + +## נותני חסות + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + + + +נותני חסות אחרים + +## דעות + +"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" + +
Kabir Khan - Microsoft (ref)
+ +--- + +"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" + +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
+ +--- + +"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" + +
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
+ +--- + +"_I’m over the moon excited about **FastAPI**. It’s so fun!_" + +
Brian Okken - Python Bytes podcast host (ref)
+ +--- + +"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" + +
Timothy Crosley - Hug creator (ref)
+ +--- + +"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" + +"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" + +
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +## **Typer**, ה - FastAPI של ממשקי שורת פקודה (CLI). + + + +אם אתם בונים אפליקציית CLI לשימוש במסוף במקום ממשק רשת, העיפו מבט על **Typer**. + +**Typer** היא אחותה הקטנה של FastAPI. ומטרתה היא להיות ה - **FastAPI של ממשקי שורת פקודה**. ⌨️ 🚀 + +## תלויות + +פייתון 3.6+ + +FastAPI עומדת על כתפי ענקיות: + +- Starlette לחלקי הרשת. +- Pydantic לחלקי המידע. + +## התקנה + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+ +תצטרכו גם שרת ASGI כגון Uvicorn או Hypercorn. + +
+ +```console +$ pip install "uvicorn[standard]" + +---> 100% +``` + +
+ +## דוגמא + +### צרו אותה + +- צרו קובץ בשם `main.py` עם: + +```Python +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} +``` + +
+או השתמשו ב - async def... + +אם הקוד שלכם משתמש ב - `async` / `await`, השתמשו ב - `async def`: + +```Python hl_lines="9 14" +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} +``` + +**שימו לב**: + +אם אינכם יודעים, בדקו את פרק "ממהרים?" על `async` ו - `await` בתיעוד. + +
+ +### הריצו אותה + +התחילו את השרת עם: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+על הפקודה uvicorn main:app --reload... + +הפקודה `uvicorn main:app` מתייחסת ל: + +- `main`: הקובץ `main.py` (מודול פייתון). +- `app`: האובייקט שנוצר בתוך `main.py` עם השורה app = FastAPI(). +- --reload: גרמו לשרת להתאתחל לאחר שינויים בקוד. עשו זאת רק בסביבת פיתוח. + +
+ +### בדקו אותה + +פתחו את הדפדפן שלכם בכתובת http://127.0.0.1:8000/items/5?q=somequery. + +אתם תראו תגובת JSON: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +כבר יצרתם API ש: + +- מקבל בקשות HTTP בנתיבים `/` ו - /items/{item_id}. +- שני ה _נתיבים_ מקבלים _בקשות_ `GET` (ידועות גם כ*מתודות* HTTP). +- ה _נתיב_ /items/{item_id} כולל \*פרמטר נתיב\_ `item_id` שאמור להיות `int`. +- ה _נתיב_ /items/{item_id} \*פרמטר שאילתא\_ אופציונלי `q`. + +### תיעוד API אינטרקטיבי + +כעת פנו לכתובת http://127.0.0.1:8000/docs. + +אתם תראו את התיעוד האוטומטי (מסופק על ידי Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### תיעוד אלטרנטיבי + +כעת פנו לכתובת http://127.0.0.1:8000/redoc. + +אתם תראו תיעוד אלטרנטיבי (מסופק על ידי ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## שדרוג לדוגמא + +כעת ערכו את הקובץ `main.py` כך שיוכל לקבל גוף מבקשת `PUT`. + +הגדירו את הגוף בעזרת רמזי טיפוסים סטנדרטיים, הודות ל - `Pydantic`. + +```Python hl_lines="4 9-12 25-27" +from typing import Union + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Union[bool, None] = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} +``` + +השרת אמול להתאתחל אוטומטית (מאחר והוספתם --reload לפקודת `uvicorn` שלמעלה). + +### שדרוג התיעוד האינטרקטיבי + +כעת פנו לכתובת http://127.0.0.1:8000/docs. + +- התיעוד האוטומטי יתעדכן, כולל הגוף החדש: + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +- לחצו על הכפתור "Try it out", הוא יאפשר לכם למלא את הפרמטרים ולעבוד ישירות מול ה - API. + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) + +- אחר כך לחצו על הכפתור "Execute", האתר יתקשר עם ה - API שלכם, ישלח את הפרמטרים, ישיג את התוצאות ואז יראה אותן על המסך: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) + +### שדרוג התיעוד האלטרנטיבי + +כעת פנו לכתובת http://127.0.0.1:8000/redoc. + +- התיעוד האלטרנטיבי גם יראה את פרמטר השאילתא והגוף החדשים. + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### סיכום + +לסיכום, אתם מכריזים ** פעם אחת** על טיפוסי הפרמטרים, גוף וכו' כפרמטרים לפונקציה. + +אתם עושים את זה עם טיפוסי פייתון מודרניים. + +אתם לא צריכים ללמוד תחביר חדש, מתודות או מחלקות של ספרייה ספיציפית, וכו' + +רק **פייתון 3.6+** סטנדרטי. + +לדוגמא, ל - `int`: + +```Python +item_id: int +``` + +או למודל `Item` מורכב יותר: + +```Python +item: Item +``` + +...ועם הכרזת הטיפוס האחת הזו אתם מקבלים: + +- תמיכת עורך, כולל: + - השלמות. + - בדיקת טיפוסים. +- אימות מידע: + - שגיאות ברורות ואטומטיות כאשר מוכנס מידע לא חוקי . + - אימות אפילו לאובייקטי JSON מקוננים. +- המרה של מידע קלט: המרה של מידע שמגיע מהרשת למידע וטיפוסים של פייתון. קורא מ: + - JSON. + - פרמטרי נתיב. + - פרמטרי שאילתא. + - עוגיות. + - כותרות. + - טפסים. + - קבצים. +- המרה של מידע פלט: המרה של מידע וטיפוסים מפייתון למידע רשת (כ - JSON): + - המירו טיפוסי פייתון (`str`, `int`, `float`, `bool`, `list`, etc). + - עצמי `datetime`. + - עצמי `UUID`. + - מודלי בסיסי נתונים. + - ...ורבים אחרים. +- תיעוד API אוטומטי ואינטרקטיבית כולל שתי אלטרנטיבות לממשק המשתמש: + - Swagger UI. + - ReDoc. + +--- + +בחזרה לדוגמאת הקוד הקודמת, **FastAPI** ידאג: + +- לאמת שיש `item_id` בנתיב בבקשות `GET` ו - `PUT`. +- לאמת שה - `item_id` הוא מטיפוס `int` בבקשות `GET` ו - `PUT`. + - אם הוא לא, הלקוח יראה שגיאה ברורה ושימושית. +- לבדוק האם קיים פרמטר שאילתא בשם `q` (קרי `http://127.0.0.1:8000/items/foo?q=somequery`) לבקשות `GET`. + - מאחר והפרמטר `q` מוגדר עם = None, הוא אופציונלי. + - לולא ה - `None` הוא היה חובה (כמו הגוף במקרה של `PUT`). +- לבקשות `PUT` לנתיב /items/{item_id}, לקרוא את גוף הבקשה כ - JSON: + - לאמת שהוא כולל את מאפיין החובה `name` שאמור להיות מטיפוס `str`. + - לאמת שהוא כולל את מאפיין החובה `price` שחייב להיות מטיפוס `float`. + - לבדוק האם הוא כולל את מאפיין הרשות `is_offer` שאמור להיות מטיפוס `bool`, אם הוא נמצא. + - כל זה יעבוד גם לאובייקט JSON מקונן. +- להמיר מ - JSON ול- JSON אוטומטית. +- לתעד הכל באמצעות OpenAPI, תיעוד שבו יוכלו להשתמש: + - מערכות תיעוד אינטרקטיביות. + - מערכות ייצור קוד אוטומטיות, להרבה שפות. +- לספק ישירות שתי מערכות תיעוד רשתיות. + +--- + +רק גרדנו את קצה הקרחון, אבל כבר יש לכם רעיון של איך הכל עובד. + +נסו לשנות את השורה: + +```Python + return {"item_name": item.name, "item_id": item_id} +``` + +...מ: + +```Python + ... "item_name": item.name ... +``` + +...ל: + +```Python + ... "item_price": item.price ... +``` + +...וראו איך העורך שלכם משלים את המאפיינים ויודע את הטיפוסים שלהם: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +לדוגמא יותר שלמה שכוללת עוד תכונות, ראו את המדריך - למשתמש. + +**התראת ספוילרים**: המדריך - למשתמש כולל: + +- הכרזה על **פרמטרים** ממקורות אחרים ושונים כגון: **כותרות**, **עוגיות**, **טפסים** ו - **קבצים**. +- איך לקבוע **מגבלות אימות** בעזרת `maximum_length` או `regex`. +- דרך חזקה וקלה להשתמש ב**הזרקת תלויות**. +- אבטחה והתאמתות, כולל תמיכה ב - **OAuth2** עם **JWT** והתאמתות **HTTP Basic**. +- טכניקות מתקדמות (אבל קלות באותה מידה) להכרזת אובייקטי JSON מקוננים (תודות ל - Pydantic). +- אינטרקציה עם **GraphQL** דרך Strawberry וספריות אחרות. +- תכונות נוספות רבות (תודות ל - Starlette) כגון: + - **WebSockets** + - בדיקות קלות במיוחד מבוססות על `requests` ו - `pytest` + - **CORS** + - **Cookie Sessions** + - ...ועוד. + +## ביצועים + +בדיקות עצמאיות של TechEmpower הראו שאפליקציות **FastAPI** שרצות תחת Uvicorn הן מתשתיות הפייתון המהירות ביותר, רק מתחת ל - Starlette ו - Uvicorn עצמן (ש - FastAPI מבוססת עליהן). (\*) + +כדי להבין עוד על הנושא, ראו את הפרק Benchmarks. + +## תלויות אופציונליות + +בשימוש Pydantic: + +- ujson - "פרסור" JSON. +- email_validator - לאימות כתובות אימייל. + +בשימוש Starlette: + +- requests - דרוש אם ברצונכם להשתמש ב - `TestClient`. +- jinja2 - דרוש אם ברצונכם להשתמש בברירת המחדל של תצורת הטמפלייטים. +- python-multipart - דרוש אם ברצונכם לתמוך ב "פרסור" טפסים, באצמעות request.form(). +- itsdangerous - דרוש אם ברצונכם להשתמש ב - `SessionMiddleware`. +- pyyaml - דרוש אם ברצונכם להשתמש ב - `SchemaGenerator` של Starlette (כנראה שאתם לא צריכים את זה עם FastAPI). +- ujson - דרוש אם ברצונכם להשתמש ב - `UJSONResponse`. + +בשימוש FastAPI / Starlette: + +- uvicorn - לשרת שטוען ומגיש את האפליקציה שלכם. +- orjson - דרוש אם ברצונכם להשתמש ב - `ORJSONResponse`. + +תוכלו להתקין את כל אלו באמצעות pip install "fastapi[all]". + +## רשיון + +הפרויקט הזה הוא תחת התנאים של רשיון MIT. diff --git a/docs/he/mkdocs.yml b/docs/he/mkdocs.yml new file mode 100644 index 000000000..34a3b0e6a --- /dev/null +++ b/docs/he/mkdocs.yml @@ -0,0 +1,140 @@ +site_name: FastAPI +site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production +site_url: https://fastapi.tiangolo.com/he/ +theme: + name: material + custom_dir: overrides + palette: + - media: '(prefers-color-scheme: light)' + scheme: default + primary: teal + accent: amber + toggle: + icon: material/lightbulb + name: Switch to light mode + - media: '(prefers-color-scheme: dark)' + scheme: slate + primary: teal + accent: amber + toggle: + icon: material/lightbulb-outline + name: Switch to dark mode + features: + - search.suggest + - search.highlight + - content.tabs.link + icon: + repo: fontawesome/brands/github-alt + logo: https://fastapi.tiangolo.com/img/icon-white.svg + favicon: https://fastapi.tiangolo.com/img/favicon.png + language: he +repo_name: tiangolo/fastapi +repo_url: https://github.com/tiangolo/fastapi +edit_uri: '' +plugins: +- search +- markdownextradata: + data: data +nav: +- FastAPI: index.md +- Languages: + - en: / + - az: /az/ + - de: /de/ + - es: /es/ + - fa: /fa/ + - fr: /fr/ + - he: /he/ + - id: /id/ + - it: /it/ + - ja: /ja/ + - ko: /ko/ + - nl: /nl/ + - pl: /pl/ + - pt: /pt/ + - ru: /ru/ + - sq: /sq/ + - tr: /tr/ + - uk: /uk/ + - zh: /zh/ +markdown_extensions: +- toc: + permalink: true +- markdown.extensions.codehilite: + guess_lang: false +- mdx_include: + base_path: docs +- admonition +- codehilite +- extra +- pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format '' +- pymdownx.tabbed: + alternate_style: true +extra: + analytics: + provider: google + property: UA-133183413-1 + social: + - icon: fontawesome/brands/github-alt + link: https://github.com/tiangolo/fastapi + - icon: fontawesome/brands/discord + link: https://discord.gg/VQjSZaeJmf + - icon: fontawesome/brands/twitter + link: https://twitter.com/fastapi + - icon: fontawesome/brands/linkedin + link: https://www.linkedin.com/in/tiangolo + - icon: fontawesome/brands/dev + link: https://dev.to/tiangolo + - icon: fontawesome/brands/medium + link: https://medium.com/@tiangolo + - icon: fontawesome/solid/globe + link: https://tiangolo.com + alternate: + - link: / + name: en - English + - link: /az/ + name: az + - link: /de/ + name: de + - link: /es/ + name: es - español + - link: /fa/ + name: fa + - link: /fr/ + name: fr - français + - link: /he/ + name: he + - link: /id/ + name: id + - link: /it/ + name: it - italiano + - link: /ja/ + name: ja - 日本語 + - link: /ko/ + name: ko - 한국어 + - link: /nl/ + name: nl + - link: /pl/ + name: pl + - link: /pt/ + name: pt - português + - link: /ru/ + name: ru - русский язык + - link: /sq/ + name: sq - shqip + - link: /tr/ + name: tr - Türkçe + - link: /uk/ + name: uk - українська мова + - link: /zh/ + name: zh - 汉语 +extra_css: +- https://fastapi.tiangolo.com/css/termynal.css +- https://fastapi.tiangolo.com/css/custom.css +extra_javascript: +- https://fastapi.tiangolo.com/js/termynal.js +- https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/he/overrides/.gitignore b/docs/he/overrides/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml index 6c9f88c90..697ecd4cb 100644 --- a/docs/id/mkdocs.yml +++ b/docs/id/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -106,6 +107,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml index 5f0b7c73b..1f1d0016d 100644 --- a/docs/it/mkdocs.yml +++ b/docs/it/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -106,6 +107,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 66694ef36..d96074ef1 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -148,6 +149,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index ddadebe7b..4a576baf2 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -116,6 +117,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/nl/mkdocs.yml b/docs/nl/mkdocs.yml index 620a4b25f..8831571dd 100644 --- a/docs/nl/mkdocs.yml +++ b/docs/nl/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -106,6 +107,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml index c04f3c1c6..982b1a060 100644 --- a/docs/pl/mkdocs.yml +++ b/docs/pl/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -109,6 +110,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 51d448c95..fb95bfe29 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -131,6 +132,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 816a0d3a0..2eb8eb935 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -107,6 +108,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml index 4df6d5b1f..1d8d9d04e 100644 --- a/docs/sq/mkdocs.yml +++ b/docs/sq/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -106,6 +107,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml index 5371cb71f..bf66edd68 100644 --- a/docs/tr/mkdocs.yml +++ b/docs/tr/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -109,6 +110,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml index fd371765a..3b8475907 100644 --- a/docs/uk/mkdocs.yml +++ b/docs/uk/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -106,6 +107,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index c1c35c6ed..f9bfd6875 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -157,6 +158,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ From e35df688d55c93f92e31019a5652247082ae51b3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 14 Jul 2022 17:17:09 +0000 Subject: [PATCH 610/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 714696529..542637032 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Start of Hebrew translation. PR [#5050](https://github.com/tiangolo/fastapi/pull/5050) by [@itay-raveh](https://github.com/itay-raveh). * 🔧 Update translations notification for Hebrew. PR [#5158](https://github.com/tiangolo/fastapi/pull/5158) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Dependabot commit message. PR [#5156](https://github.com/tiangolo/fastapi/pull/5156) by [@tiangolo](https://github.com/tiangolo). * ⬆ Bump actions/upload-artifact from 2 to 3. PR [#5148](https://github.com/tiangolo/fastapi/pull/5148) by [@dependabot[bot]](https://github.com/apps/dependabot). From 2f21bef91b72dbd723fceb12a23ca5cf58540684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 14 Jul 2022 19:34:25 +0200 Subject: [PATCH 611/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 542637032..5dece6163 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,23 @@ ## Latest Changes +### Fixes - Breaking Changes + +* 🐛 Fix removing body from status codes that do not support it. PR [#5145](https://github.com/tiangolo/fastapi/pull/5145) by [@tiangolo](https://github.com/tiangolo). + * Setting `status_code` to `204`, `304`, or any code below `200` (1xx) will remove the body from the response. + * This fixes an error in Uvicorn that otherwise would be thrown: `RuntimeError: Response content longer than Content-Length`. + * This removes `fastapi.openapi.constants.STATUS_CODES_WITH_NO_BODY`, it is replaced by a function in utils. + +### Translations + * 🌐 Start of Hebrew translation. PR [#5050](https://github.com/tiangolo/fastapi/pull/5050) by [@itay-raveh](https://github.com/itay-raveh). +* 🔧 Add config for Swedish translations notification. PR [#5147](https://github.com/tiangolo/fastapi/pull/5147) by [@tiangolo](https://github.com/tiangolo). +* 🌐 Start of Swedish translation. PR [#5062](https://github.com/tiangolo/fastapi/pull/5062) by [@MrRawbin](https://github.com/MrRawbin). +* 🌐 Add Japanese translation for `docs/ja/docs/advanced/index.md`. PR [#5043](https://github.com/tiangolo/fastapi/pull/5043) by [@wakabame](https://github.com/wakabame). +* 🌐🇵🇱 Add Polish translation for `docs/pl/docs/tutorial/first-steps.md`. PR [#5024](https://github.com/tiangolo/fastapi/pull/5024) by [@Valaraucoo](https://github.com/Valaraucoo). + +### Internal + * 🔧 Update translations notification for Hebrew. PR [#5158](https://github.com/tiangolo/fastapi/pull/5158) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Dependabot commit message. PR [#5156](https://github.com/tiangolo/fastapi/pull/5156) by [@tiangolo](https://github.com/tiangolo). * ⬆ Bump actions/upload-artifact from 2 to 3. PR [#5148](https://github.com/tiangolo/fastapi/pull/5148) by [@dependabot[bot]](https://github.com/apps/dependabot). @@ -10,17 +26,12 @@ * 🔧 Update sponsors badge configs. PR [#5155](https://github.com/tiangolo/fastapi/pull/5155) by [@tiangolo](https://github.com/tiangolo). * 👥 Update FastAPI People. PR [#5154](https://github.com/tiangolo/fastapi/pull/5154) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Jina sponsor badges. PR [#5151](https://github.com/tiangolo/fastapi/pull/5151) by [@tiangolo](https://github.com/tiangolo). -* 🔧 Add config for Swedish translations notification. PR [#5147](https://github.com/tiangolo/fastapi/pull/5147) by [@tiangolo](https://github.com/tiangolo). -* 🌐 Start of Swedish translation. PR [#5062](https://github.com/tiangolo/fastapi/pull/5062) by [@MrRawbin](https://github.com/MrRawbin). -* 🌐 Add Japanese translation for `docs/ja/docs/advanced/index.md`. PR [#5043](https://github.com/tiangolo/fastapi/pull/5043) by [@wakabame](https://github.com/wakabame). -* 🌐🇵🇱 Add Polish translation for `docs/pl/docs/tutorial/first-steps.md`. PR [#5024](https://github.com/tiangolo/fastapi/pull/5024) by [@Valaraucoo](https://github.com/Valaraucoo). * ⬆ Bump actions/checkout from 2 to 3. PR [#5133](https://github.com/tiangolo/fastapi/pull/5133) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5030](https://github.com/tiangolo/fastapi/pull/5030) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * ⬆ Bump nwtgck/actions-netlify from 1.1.5 to 1.2.3. PR [#5132](https://github.com/tiangolo/fastapi/pull/5132) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump codecov/codecov-action from 2 to 3. PR [#5131](https://github.com/tiangolo/fastapi/pull/5131) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump dawidd6/action-download-artifact from 2.9.0 to 2.21.1. PR [#5130](https://github.com/tiangolo/fastapi/pull/5130) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump actions/setup-python from 2 to 4. PR [#5129](https://github.com/tiangolo/fastapi/pull/5129) by [@dependabot[bot]](https://github.com/apps/dependabot). -* 🐛 Fix removing body from status codes that do not support it. PR [#5145](https://github.com/tiangolo/fastapi/pull/5145) by [@tiangolo](https://github.com/tiangolo). * 👷 Add Dependabot. PR [#5128](https://github.com/tiangolo/fastapi/pull/5128) by [@tiangolo](https://github.com/tiangolo). * ♻️ Move from `Optional[X]` to `Union[X, None]` for internal utils. PR [#5124](https://github.com/tiangolo/fastapi/pull/5124) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, remove Dropbase, add Doist. PR [#5096](https://github.com/tiangolo/fastapi/pull/5096) by [@tiangolo](https://github.com/tiangolo). From 50fb34bf55c1711e3753363ab6427d77be25dbb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 14 Jul 2022 19:35:13 +0200 Subject: [PATCH 612/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.79?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5dece6163..55df22c06 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.79.0 + ### Fixes - Breaking Changes * 🐛 Fix removing body from status codes that do not support it. PR [#5145](https://github.com/tiangolo/fastapi/pull/5145) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 2465e2c27..e5cdbeb09 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.78.0" +__version__ = "0.79.0" from starlette import status as status From 3b5839260f916ac416585ef0452f101105884834 Mon Sep 17 00:00:00 2001 From: Mohsen Mahmoodi Date: Wed, 20 Jul 2022 16:55:23 +0430 Subject: [PATCH 613/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Persian=20translat?= =?UTF-8?q?ion=20for=20`docs/fa/docs/index.md`=20and=20tweak=20right-to-le?= =?UTF-8?q?ft=20CSS=20(#2395)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../notify-translations/app/translations.yml | 2 +- docs/en/docs/css/custom.css | 21 ++ docs/fa/docs/index.md | 338 +++++++++--------- docs/he/mkdocs.yml | 3 + docs/sv/mkdocs.yml | 3 + 5 files changed, 194 insertions(+), 173 deletions(-) diff --git a/.github/actions/notify-translations/app/translations.yml b/.github/actions/notify-translations/app/translations.yml index ac15978a9..d283ef9f7 100644 --- a/.github/actions/notify-translations/app/translations.yml +++ b/.github/actions/notify-translations/app/translations.yml @@ -8,7 +8,7 @@ uk: 1748 tr: 1892 fr: 1972 ko: 2017 -sq: 2041 +fa: 2041 pl: 3169 de: 3716 id: 3717 diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css index 42b752bcf..226ca2b11 100644 --- a/docs/en/docs/css/custom.css +++ b/docs/en/docs/css/custom.css @@ -4,10 +4,21 @@ display: block; } +.termy { + /* For right to left languages */ + direction: ltr; +} + .termy [data-termynal] { white-space: pre-wrap; } +a.external-link { + /* For right to left languages */ + direction: ltr; + display: inline-block; +} + a.external-link::after { /* \00A0 is a non-breaking space to make the mark be on the same line as the link @@ -118,3 +129,13 @@ a.announce-link:hover { .twitter { color: #00acee; } + +/* Right to left languages */ +code { + direction: ltr; + display: inline-block; +} + +.md-content__inner h1 { + direction: ltr !important; +} diff --git a/docs/fa/docs/index.md b/docs/fa/docs/index.md index fd52f994c..0f7cd569a 100644 --- a/docs/fa/docs/index.md +++ b/docs/fa/docs/index.md @@ -1,16 +1,12 @@ - -{!../../../docs/missing-translation.md!} - -

FastAPI

- FastAPI framework, high performance, easy to learn, fast to code, ready for production + فریم‌ورک FastAPI، کارایی بالا، یادگیری آسان، کدنویسی سریع، آماده برای استفاده در محیط پروداکشن

- - Test + + Test Coverage @@ -25,103 +21,99 @@ --- -**Documentation**: https://fastapi.tiangolo.com +**مستندات**: https://fastapi.tiangolo.com -**Source Code**: https://github.com/tiangolo/fastapi +**کد منبع**: https://github.com/tiangolo/fastapi --- +FastAPI یک وب فریم‌ورک مدرن و سریع (با کارایی بالا) برای ایجاد APIهای متنوع (وب، وب‌سوکت و غبره) با زبان پایتون نسخه +۳.۶ است. این فریم‌ورک با رعایت کامل راهنمای نوع داده (Type Hint) ایجاد شده است. -FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. +ویژگی‌های کلیدی این فریم‌ورک عبارتند از: -The key features are: +* **سرعت**: کارایی بسیار بالا و قابل مقایسه با **NodeJS** و **Go** (با تشکر از Starlette و Pydantic). [یکی از سریع‌ترین فریم‌ورک‌های پایتونی موجود](#performance). -* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). +* **کدنویسی سریع**: افزایش ۲۰۰ تا ۳۰۰ درصدی سرعت توسعه فابلیت‌های جدید. * +* **باگ کمتر**: کاهش ۴۰ درصدی خطاهای انسانی (برنامه‌نویسی). * +* **غریزی**: پشتیبانی فوق‌العاده در محیط‌های توسعه یکپارچه (IDE). تکمیل در همه بخش‌های کد. کاهش زمان رفع باگ. +* **آسان**: طراحی شده برای یادگیری و استفاده آسان. کاهش زمان مورد نیاز برای مراجعه به مستندات. +* **کوچک**: کاهش تکرار در کد. چندین قابلیت برای هر پارامتر (منظور پارامترهای ورودی تابع هندلر می‌باشد، به بخش خلاصه در همین صفحه مراجعه شود). باگ کمتر. +* **استوار**: ایجاد کدی آماده برای استفاده در محیط پروداکشن و تولید خودکار مستندات تعاملی +* **مبتنی بر استانداردها**: مبتنی بر (و منطبق با) استانداردهای متن باز مربوط به API: OpenAPI (سوگر سابق) و JSON Schema. -* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * -* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * -* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. -* **Easy**: Designed to be easy to use and learn. Less time reading docs. -* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. -* **Robust**: Get production-ready code. With automatic interactive documentation. -* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. +* تخمین‌ها بر اساس تست‌های انجام شده در یک تیم توسعه داخلی که مشغول ایجاد برنامه‌های کاربردی واقعی بودند صورت گرفته است. -* estimation based on tests on an internal development team, building production applications. - -## Sponsors +## اسپانسرهای طلایی {% if sponsors %} {% for sponsor in sponsors.gold -%} - -{% endfor -%} -{%- for sponsor in sponsors.silver -%} - + {% endfor %} {% endif %} -Other sponsors +دیگر اسپانسرها -## Opinions +## نظر دیگران در مورد FastAPI -"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" +

[...] I'm using FastAPI a ton these days. [...] I'm actually planning to use it for all of my team's ML services at Microsoft. Some of them are getting integrated into the core Windows product and some Office products."
Kabir Khan - Microsoft (ref)
--- -"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" +
"We adopted the FastAPI library to spawn a RESTserver that can be queried to obtain predictions. [for Ludwig]"
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
--- -"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" +
"Netflix is pleased to announce the open-source release of our crisis management orchestration framework: Dispatch! [built with FastAPI]"
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
--- -"_I’m over the moon excited about **FastAPI**. It’s so fun!_" +
"I’m over the moon excited about FastAPI. It’s so fun!"
Brian Okken - Python Bytes podcast host (ref)
--- -"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" +
"Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted Hug to be - it's really inspiring to see someone build that."
Timothy Crosley - Hug creator (ref)
--- -"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" +
"If you're looking to learn one modern framework for building REST APIs, check out FastAPI [...] It's fast, easy to use and easy to learn [...]"
-"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" +
"We've switched over to FastAPI for our APIs [...] I think you'll like it [...]"
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
--- -## **Typer**, the FastAPI of CLIs +## **Typer**, فریم‌ورکی معادل FastAPI برای کار با واسط خط فرمان -If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. +اگر در حال ساختن برنامه‌ای برای استفاده در CLI (به جای استفاده در وب) هستید، می‌توانید از **Typer**. استفاده کنید. -**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 +**Typer** دوقلوی کوچکتر FastAPI است و قرار است معادلی برای FastAPI در برنامه‌های CLI باشد.️ 🚀 -## Requirements +## نیازمندی‌ها -Python 3.6+ +پایتون +۳.۶ -FastAPI stands on the shoulders of giants: +FastAPI مبتنی بر ابزارهای قدرتمند زیر است: -* Starlette for the web parts. -* Pydantic for the data parts. +* فریم‌ورک Starlette برای بخش وب. +* کتابخانه Pydantic برای بخش داده‌. -## Installation +## نصب
@@ -133,7 +125,7 @@ $ pip install fastapi
-You will also need an ASGI server, for production such as Uvicorn or Hypercorn. +نصب یک سرور پروداکشن نظیر Uvicorn یا Hypercorn نیز جزء نیازمندی‌هاست.
@@ -145,14 +137,13 @@ $ pip install "uvicorn[standard]"
-## Example +## مثال -### Create it - -* Create a file `main.py` with: +### ایجاد کنید +* فایلی به نام `main.py` با محتوای زیر ایجاد کنید : ```Python -from typing import Union +from typing import Optional from fastapi import FastAPI @@ -170,12 +161,12 @@ def read_item(item_id: int, q: Union[str, None] = None): ```
-Or use async def... +همچنین می‌توانید از async def... نیز استفاده کنید -If your code uses `async` / `await`, use `async def`: +اگر در کدتان از `async` / `await` استفاده می‌کنید, از `async def` برای تعریف تابع خود استفاده کنید: ```Python hl_lines="9 14" -from typing import Union +from typing import Optional from fastapi import FastAPI @@ -188,19 +179,20 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): +async def read_item(item_id: int, q: Optional[str] = None): return {"item_id": item_id, "q": q} ``` -**Note**: +**توجه**: + +اگر با `async / await` آشنا نیستید، به بخش _"عجله‌ دارید?"_ در صفحه درباره `async` و `await` در مستندات مراجعه کنید. -If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs.
-### Run it +### اجرا کنید -Run the server with: +با استفاده از دستور زیر سرور را اجرا کنید:
@@ -217,57 +209,57 @@ INFO: Application startup complete.
-About the command uvicorn main:app --reload... +درباره دستور uvicorn main:app --reload... -The command `uvicorn main:app` refers to: +دستور `uvicorn main:app` شامل موارد زیر است: -* `main`: the file `main.py` (the Python "module"). -* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. -* `--reload`: make the server restart after code changes. Only do this for development. +* `main`: فایل `main.py` (ماژول پایتون ایجاد شده). +* `app`: شیء ایجاد شده در فایل `main.py` در خط `app = FastAPI()`. +* `--reload`: ریستارت کردن سرور با تغییر کد. تنها در هنگام توسعه از این گزینه استفاده شود..
-### Check it +### بررسی کنید -Open your browser at http://127.0.0.1:8000/items/5?q=somequery. +آدرس http://127.0.0.1:8000/items/5?q=somequery را در مرورگر خود باز کنید. -You will see the JSON response as: +پاسخ JSON زیر را مشاهده خواهید کرد: ```JSON {"item_id": 5, "q": "somequery"} ``` -You already created an API that: +تا اینجا شما APIای ساختید که: -* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. -* Both _paths_ take `GET` operations (also known as HTTP _methods_). -* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. -* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. +* درخواست‌های HTTP به _مسیرهای_ `/` و `/items/{item_id}` را دریافت می‌کند. +* هردو _مسیر_ عملیات (یا HTTP _متد_) `GET` را پشتیبانی می‌کنند. +* _مسیر_ `/items/{item_id}` شامل _پارامتر مسیر_ `item_id` از نوع `int` است. +* _مسیر_ `/items/{item_id}` شامل _پارامتر پرسمان_ اختیاری `q` از نوع `str` است. -### Interactive API docs +### مستندات API تعاملی -Now go to http://127.0.0.1:8000/docs. +حال به آدرس http://127.0.0.1:8000/docs بروید. -You will see the automatic interactive API documentation (provided by Swagger UI): +مستندات API تعاملی (ایجاد شده به کمک Swagger UI) را مشاهده خواهید کرد: ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -### Alternative API docs +### مستندات API جایگزین -And now, go to http://127.0.0.1:8000/redoc. +حال به آدرس http://127.0.0.1:8000/redoc بروید. -You will see the alternative automatic documentation (provided by ReDoc): +مستندات خودکار دیگری را مشاهده خواهید کرد که به کمک ReDoc ایجاد می‌شود: ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## Example upgrade +## تغییر مثال -Now modify the file `main.py` to receive a body from a `PUT` request. +حال فایل `main.py` را مطابق زیر ویرایش کنید تا بتوانید بدنه یک درخواست `PUT` را دریافت کنید. -Declare the body using standard Python types, thanks to Pydantic. +به کمک Pydantic بدنه درخواست را با انواع استاندارد پایتون تعریف کنید. ```Python hl_lines="4 9-12 25-27" -from typing import Union +from typing import Optional from fastapi import FastAPI from pydantic import BaseModel @@ -296,173 +288,175 @@ def update_item(item_id: int, item: Item): return {"item_name": item.name, "item_id": item_id} ``` -The server should reload automatically (because you added `--reload` to the `uvicorn` command above). +سرور به صورت خودکار ری‌استارت می‌شود (زیرا پیشتر از گزینه `--reload` در دستور `uvicorn` استفاده کردیم). -### Interactive API docs upgrade +### تغییر مستندات API تعاملی -Now go to http://127.0.0.1:8000/docs. +مجددا به آدرس http://127.0.0.1:8000/docs بروید. -* The interactive API documentation will be automatically updated, including the new body: +* مستندات API تعاملی به صورت خودکار به‌روز شده است و شامل بدنه تعریف شده در مرحله قبل است: ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) -* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: +* روی دکمه "Try it out" کلیک کنید, اکنون می‌توانید پارامترهای مورد نیاز هر API را مشخص کرده و به صورت مستقیم با آنها تعامل کنید: ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) -* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: +* سپس روی دکمه "Execute" کلیک کنید, خواهید دید که واسط کاریری با APIهای تعریف شده ارتباط برقرار کرده، پارامترهای مورد نیاز را به آن‌ها ارسال می‌کند، سپس نتایج را دریافت کرده و در صفحه نشان می‌دهد: ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) -### Alternative API docs upgrade +### تغییر مستندات API جایگزین -And now, go to http://127.0.0.1:8000/redoc. +حال به آدرس http://127.0.0.1:8000/redoc بروید. -* The alternative documentation will also reflect the new query parameter and body: +* خواهید دید که مستندات جایگزین نیز به‌روزرسانی شده و شامل پارامتر پرسمان و بدنه تعریف شده می‌باشد: ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) -### Recap +### خلاصه -In summary, you declare **once** the types of parameters, body, etc. as function parameters. +به طور خلاصه شما **یک بار** انواع پارامترها، بدنه و غیره را به عنوان پارامترهای ورودی تابع خود تعریف می‌کنید. -You do that with standard modern Python types. + این کار را با استفاده از انواع استاندارد و مدرن موجود در پایتون انجام می‌دهید. -You don't have to learn a new syntax, the methods or classes of a specific library, etc. +نیازی به یادگیری نحو جدید یا متدها و کلاس‌های یک کتابخانه بخصوص و غیره نیست. -Just standard **Python 3.6+**. +تنها **پایتون +۳.۶**. -For example, for an `int`: +به عنوان مثال برای یک پارامتر از نوع `int`: ```Python item_id: int ``` -or for a more complex `Item` model: +یا برای یک مدل پیچیده‌تر مثل `Item`: ```Python item: Item ``` -...and with that single declaration you get: +...و با همین اعلان تمامی قابلیت‌های زیر در دسترس قرار می‌گیرد: -* Editor support, including: - * Completion. - * Type checks. -* Validation of data: - * Automatic and clear errors when the data is invalid. - * Validation even for deeply nested JSON objects. -* Conversion of input data: coming from the network to Python data and types. Reading from: +* پشتیبانی ویرایشگر متنی شامل: + * تکمیل کد. + * بررسی انواع داده. +* اعتبارسنجی داده: + * خطاهای خودکار و مشخص در هنگام نامعتبر بودن داده + * اعتبارسنجی، حتی برای اشیاء JSON تو در تو. +* تبدیل داده ورودی: که از شبکه رسیده به انواع و داد‌ه‌ پایتونی. این داده‌ شامل: * JSON. - * Path parameters. - * Query parameters. - * Cookies. - * Headers. - * Forms. - * Files. -* Conversion of output data: converting from Python data and types to network data (as JSON): - * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). - * `datetime` objects. - * `UUID` objects. - * Database models. - * ...and many more. -* Automatic interactive API documentation, including 2 alternative user interfaces: + * پارامترهای مسیر. + * پارامترهای پرسمان. + * کوکی‌ها. + * سرآیند‌ها (هدرها). + * فرم‌ها. + * فایل‌ها. +* تبدیل داده خروجی: تبدیل از انواع و داده‌ پایتون به داده شبکه (مانند JSON): + * تبدیل انواع داده پایتونی (`str`, `int`, `float`, `bool`, `list` و غیره). + * اشیاء `datetime`. + * اشیاء `UUID`. + * qمدل‌های پایگاه‌داده. + * و موارد بیشمار دیگر. +* دو مدل مستند API تعاملی خودکار : * Swagger UI. * ReDoc. --- -Coming back to the previous code example, **FastAPI** will: +به مثال قبلی باز می‌گردیم، در این مثال **FastAPI** موارد زیر را انجام می‌دهد: -* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. -* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. - * If it is not, the client will see a useful, clear error. -* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. - * As the `q` parameter is declared with `= None`, it is optional. - * Without the `None` it would be required (as is the body in the case with `PUT`). -* For `PUT` requests to `/items/{item_id}`, Read the body as JSON: - * Check that it has a required attribute `name` that should be a `str`. - * Check that it has a required attribute `price` that has to be a `float`. - * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. - * All this would also work for deeply nested JSON objects. -* Convert from and to JSON automatically. -* Document everything with OpenAPI, that can be used by: - * Interactive documentation systems. - * Automatic client code generation systems, for many languages. -* Provide 2 interactive documentation web interfaces directly. +* اعتبارسنجی اینکه پارامتر `item_id` در مسیر درخواست‌های `GET` و `PUT` موجود است . +* اعتبارسنجی اینکه پارامتر `item_id` در درخواست‌های `GET` و `PUT` از نوع `int` است. + * اگر غیر از این موارد باشد، سرویس‌گیرنده خطای مفید و مشخصی دریافت خواهد کرد. +* بررسی وجود پارامتر پرسمان اختیاری `q` (مانند `http://127.0.0.1:8000/items/foo?q=somequery`) در درخواست‌های `GET`. + * از آنجا که پارامتر `q` با `= None` مقداردهی شده است, این پارامتر اختیاری است. + * اگر از مقدار اولیه `None` استفاده نکنیم، این پارامتر الزامی خواهد بود (همانند بدنه درخواست در درخواست `PUT`). +* برای درخواست‌های `PUT` به آدرس `/items/{item_id}`, بدنه درخواست باید از نوع JSON تعریف شده باشد: + * بررسی اینکه بدنه شامل فیلدی با نام `name` و از نوع `str` است. + * بررسی اینکه بدنه شامل فیلدی با نام `price` و از نوع `float` است. + * بررسی اینکه بدنه شامل فیلدی اختیاری با نام `is_offer` است, که در صورت وجود باید از نوع `bool` باشد. + * تمامی این موارد برای اشیاء JSON در هر عمقی قابل بررسی می‌باشد. +* تبدیل از/به JSON به صورت خودکار. +* مستندسازی همه چیز با استفاده از OpenAPI, که می‌توان از آن برای موارد زیر استفاده کرد: + * سیستم مستندات تعاملی. + * تولید خودکار کد سرویس‌گیرنده‌ در زبان‌های برنامه‌نویسی بیشمار. +* فراهم سازی ۲ مستند تعاملی مبتنی بر وب به صورت پیش‌فرض . --- -We just scratched the surface, but you already get the idea of how it all works. +موارد ذکر شده تنها پاره‌ای از ویژگی‌های بیشمار FastAPI است اما ایده‌ای کلی از طرز کار آن در اختیار قرار می‌دهد. -Try changing the line with: +خط زیر را به این صورت تغییر دهید: ```Python return {"item_name": item.name, "item_id": item_id} ``` -...from: +از: ```Python ... "item_name": item.name ... ``` -...to: +به: ```Python ... "item_price": item.price ... ``` -...and see how your editor will auto-complete the attributes and know their types: +در حین تایپ کردن توجه کنید که چگونه ویرایش‌گر، ویژگی‌های کلاس `Item` را تشخیص داده و به تکمیل خودکار آنها کمک می‌کند: ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) -For a more complete example including more features, see the Tutorial - User Guide. +برای مشاهده مثال‌های کامل‌تر که شامل قابلیت‌های بیشتری از FastAPI باشد به بخش آموزش - راهنمای کاربر مراجعه کنید. -**Spoiler alert**: the tutorial - user guide includes: +**هشدار اسپویل**: بخش آموزش - راهنمای کاربر شامل موارد زیر است: -* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. -* How to set **validation constraints** as `maximum_length` or `regex`. -* A very powerful and easy to use **Dependency Injection** system. -* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. -* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). -* **GraphQL** integration with Strawberry and other libraries. -* Many extra features (thanks to Starlette) as: - * **WebSockets** - * extremely easy tests based on `requests` and `pytest` +* اعلان **پارامترهای** موجود در بخش‌های دیگر درخواست، شامل: **سرآیند‌ (هدر)ها**, **کوکی‌ها**, **فیلد‌های فرم** و **فایل‌ها**. +* چگونگی تنظیم **محدودیت‌های اعتبارسنجی** به عنوان مثال `maximum_length` یا `regex`. +* سیستم **Dependency Injection** قوی و کاربردی. +* امنیت و تایید هویت, شامل پشتیبانی از **OAuth2** مبتنی بر **JWT tokens** و **HTTP Basic**. +* تکنیک پیشرفته برای تعریف **مدل‌های چند سطحی JSON** (بر اساس Pydantic). +* قابلیت‌های اضافی دیگر (بر اساس Starlette) شامل: + * **وب‌سوکت** + * **GraphQL** + * تست‌های خودکار آسان مبتنی بر `requests` و `pytest` * **CORS** * **Cookie Sessions** - * ...and more. + * و موارد بیشمار دیگر. -## Performance +## کارایی -Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) +معیار (بنچمارک‌)های مستقل TechEmpower حاکی از آن است که برنامه‌های **FastAPI** که تحت Uvicorn اجرا می‌شود، یکی از سریع‌ترین فریم‌ورک‌های مبتنی بر پایتون, است که کمی ضعیف‌تر از Starlette و Uvicorn عمل می‌کند (فریم‌ورک و سروری که FastAPI بر اساس آنها ایجاد شده است) (*) -To understand more about it, see the section Benchmarks. +برای درک بهتری از این موضوع به بخش بنچ‌مارک‌ها مراجعه کنید. -## Optional Dependencies +## نیازمندی‌های اختیاری -Used by Pydantic: +استفاده شده توسط Pydantic: -* ujson - for faster JSON "parsing". -* email_validator - for email validation. +* ujson - برای "تجزیه (parse)" سریع‌تر JSON . +* email_validator - برای اعتبارسنجی آدرس‌های ایمیل. -Used by Starlette: +استفاده شده توسط Starlette: -* requests - Required if you want to use the `TestClient`. -* jinja2 - Required if you want to use the default template configuration. -* python-multipart - Required if you want to support form "parsing", with `request.form()`. -* itsdangerous - Required for `SessionMiddleware` support. -* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). -* ujson - Required if you want to use `UJSONResponse`. +* requests - در صورتی که می‌خواهید از `TestClient` استفاده کنید. +* aiofiles - در صورتی که می‌خواهید از `FileResponse` و `StaticFiles` استفاده کنید. +* jinja2 - در صورتی که بخواهید از پیکربندی پیش‌فرض برای قالب‌ها استفاده کنید. +* python-multipart - در صورتی که بخواهید با استفاده از `request.form()` از قابلیت "تجزیه (parse)" فرم استفاده کنید. +* itsdangerous - در صورتی که بخواید از `SessionMiddleware` پشتیبانی کنید. +* pyyaml - برای پشتیبانی `SchemaGenerator` در Starlet (به احتمال زیاد برای کار کردن با FastAPI به آن نیازی پیدا نمی‌کنید.). +* graphene - در صورتی که از `GraphQLApp` پشتیبانی می‌کنید. +* ujson - در صورتی که بخواهید از `UJSONResponse` استفاده کنید. -Used by FastAPI / Starlette: +استفاده شده توسط FastAPI / Starlette: -* uvicorn - for the server that loads and serves your application. -* orjson - Required if you want to use `ORJSONResponse`. +* uvicorn - برای سرور اجرا کننده برنامه وب. +* orjson - در صورتی که بخواهید از `ORJSONResponse` استفاده کنید. -You can install all of these with `pip install "fastapi[all]"`. +می‌توان همه این موارد را با استفاده از دستور `pip install fastapi[all]`. به صورت یکجا نصب کرد. -## License +## لایسنس -This project is licensed under the terms of the MIT license. +این پروژه مشمول قوانین و مقررات لایسنس MIT است. diff --git a/docs/he/mkdocs.yml b/docs/he/mkdocs.yml index 34a3b0e6a..532cc5cab 100644 --- a/docs/he/mkdocs.yml +++ b/docs/he/mkdocs.yml @@ -54,6 +54,7 @@ nav: - pt: /pt/ - ru: /ru/ - sq: /sq/ + - sv: /sv/ - tr: /tr/ - uk: /uk/ - zh: /zh/ @@ -126,6 +127,8 @@ extra: name: ru - русский язык - link: /sq/ name: sq - shqip + - link: /sv/ + name: sv - svenska - link: /tr/ name: tr - Türkçe - link: /uk/ diff --git a/docs/sv/mkdocs.yml b/docs/sv/mkdocs.yml index fa0296d5c..4606c9349 100644 --- a/docs/sv/mkdocs.yml +++ b/docs/sv/mkdocs.yml @@ -44,6 +44,7 @@ nav: - es: /es/ - fa: /fa/ - fr: /fr/ + - he: /he/ - id: /id/ - it: /it/ - ja: /ja/ @@ -106,6 +107,8 @@ extra: name: fa - link: /fr/ name: fr - français + - link: /he/ + name: he - link: /id/ name: id - link: /it/ From c07aced06d5f9216ea9af44f83f65221b626210f Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 20 Jul 2022 12:26:04 +0000 Subject: [PATCH 614/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 55df22c06..6d90cd916 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Persian translation for `docs/fa/docs/index.md` and tweak right-to-left CSS. PR [#2395](https://github.com/tiangolo/fastapi/pull/2395) by [@mohsen-mahmoodi](https://github.com/mohsen-mahmoodi). ## 0.79.0 From 9031d1daeed911f3f2ff4dbaca0c0a0013694eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 20 Jul 2022 15:20:12 +0200 Subject: [PATCH 615/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20sponsors,=20Str?= =?UTF-8?q?iveworks=20badge=20(#5179)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/data/sponsors.yml | 4 ++-- docs/en/docs/img/sponsors/striveworks2.png | Bin 0 -> 34780 bytes 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 docs/en/docs/img/sponsors/striveworks2.png diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index efd0f00f8..7aa50b111 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -37,6 +37,6 @@ bronze: - url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source title: Biosecurity risk assessments made easy. img: https://fastapi.tiangolo.com/img/sponsors/exoflare.png - - url: https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings + - url: https://bit.ly/3ccLCmM title: https://striveworks.us/careers - img: https://fastapi.tiangolo.com/img/sponsors/striveworks.png + img: https://fastapi.tiangolo.com/img/sponsors/striveworks2.png diff --git a/docs/en/docs/img/sponsors/striveworks2.png b/docs/en/docs/img/sponsors/striveworks2.png new file mode 100644 index 0000000000000000000000000000000000000000..bed9cb0a773a49e8021902202b8ab21a3bd672b7 GIT binary patch literal 34780 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

n~I<2aQ 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 Date: Wed, 20 Jul 2022 13:21:07 +0000 Subject: [PATCH 616/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6d90cd916..3bf9c27a0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update sponsors, Striveworks badge. PR [#5179](https://github.com/tiangolo/fastapi/pull/5179) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Persian translation for `docs/fa/docs/index.md` and tweak right-to-left CSS. PR [#2395](https://github.com/tiangolo/fastapi/pull/2395) by [@mohsen-mahmoodi](https://github.com/mohsen-mahmoodi). ## 0.79.0 From a1cdf8cd44e088d1cf2c82cbbb0e3308e726a2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 16 Aug 2022 13:07:22 +0200 Subject: [PATCH 617/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20Jina=20sponsors?= =?UTF-8?q?hip=20(#5272)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++- docs/en/data/sponsors.yml | 9 ++++++--- docs/en/docs/img/sponsors/docarray-top-banner.svg | 1 + docs/en/docs/img/sponsors/docarray.svg | 1 + docs/en/docs/img/sponsors/jina-top-banner.svg | 1 + docs/en/docs/img/sponsors/jina2.svg | 1 + docs/en/overrides/main.html | 10 ++++++++-- 7 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 docs/en/docs/img/sponsors/docarray-top-banner.svg create mode 100644 docs/en/docs/img/sponsors/docarray.svg create mode 100644 docs/en/docs/img/sponsors/jina-top-banner.svg create mode 100644 docs/en/docs/img/sponsors/jina2.svg diff --git a/README.md b/README.md index bcea9fe73..a5e8cae22 100644 --- a/README.md +++ b/README.md @@ -47,10 +47,11 @@ The key features are: - + + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 7aa50b111..7fbb933e0 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -1,7 +1,7 @@ gold: - - url: https://bit.ly/3PjOZqc - title: "DiscoArt: Create compelling Disco Diffusion artworks in just one line" - img: https://fastapi.tiangolo.com/img/sponsors/jina-ai.png + - url: https://bit.ly/3dmXC5S + title: The data structure for unstructured multimodal data + img: https://fastapi.tiangolo.com/img/sponsors/docarray.svg - url: https://cryptapi.io/ title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway." img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg @@ -11,6 +11,9 @@ gold: - url: https://doist.com/careers/9B437B1615-wa-senior-backend-engineer-python title: Help us migrate doist to FastAPI img: https://fastapi.tiangolo.com/img/sponsors/doist.svg + - url: https://bit.ly/3JJ7y5C + title: Build cross-modal and multimodal applications on the cloud + img: https://fastapi.tiangolo.com/img/sponsors/jina2.svg silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas diff --git a/docs/en/docs/img/sponsors/docarray-top-banner.svg b/docs/en/docs/img/sponsors/docarray-top-banner.svg new file mode 100644 index 000000000..c48a3312b --- /dev/null +++ b/docs/en/docs/img/sponsors/docarray-top-banner.svg @@ -0,0 +1 @@ + diff --git a/docs/en/docs/img/sponsors/docarray.svg b/docs/en/docs/img/sponsors/docarray.svg new file mode 100644 index 000000000..f18df247e --- /dev/null +++ b/docs/en/docs/img/sponsors/docarray.svg @@ -0,0 +1 @@ + diff --git a/docs/en/docs/img/sponsors/jina-top-banner.svg b/docs/en/docs/img/sponsors/jina-top-banner.svg new file mode 100644 index 000000000..8b62cd619 --- /dev/null +++ b/docs/en/docs/img/sponsors/jina-top-banner.svg @@ -0,0 +1 @@ + diff --git a/docs/en/docs/img/sponsors/jina2.svg b/docs/en/docs/img/sponsors/jina2.svg new file mode 100644 index 000000000..6a48677ba --- /dev/null +++ b/docs/en/docs/img/sponsors/jina2.svg @@ -0,0 +1 @@ + diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 5c7029b85..0d5bb037c 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -29,9 +29,9 @@

@@ -52,6 +52,12 @@
+ {% endblock %} From f1feb1427b70df971a28f2c0c6cf1016b66e4561 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 16 Aug 2022 11:08:10 +0000 Subject: [PATCH 618/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3bf9c27a0..5f2f0e38c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update Jina sponsorship. PR [#5272](https://github.com/tiangolo/fastapi/pull/5272) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, Striveworks badge. PR [#5179](https://github.com/tiangolo/fastapi/pull/5179) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Persian translation for `docs/fa/docs/index.md` and tweak right-to-left CSS. PR [#2395](https://github.com/tiangolo/fastapi/pull/2395) by [@mohsen-mahmoodi](https://github.com/mohsen-mahmoodi). From 0ba0c4662da865bffa4b55872030907981c8d01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 17 Aug 2022 12:48:05 +0200 Subject: [PATCH 619/814] =?UTF-8?q?=E2=9C=A8=20Add=20illustrations=20for?= =?UTF-8?q?=20Concurrent=20burgers=20and=20Parallel=20burgers=20(#5277)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/az/mkdocs.yml | 2 + docs/de/mkdocs.yml | 2 + docs/en/docs/async.md | 94 +++++++++++------- docs/en/docs/css/custom.css | 5 + .../concurrent-burgers-01.png | Bin 0 -> 203390 bytes .../concurrent-burgers-02.png | Bin 0 -> 166992 bytes .../concurrent-burgers-03.png | Bin 0 -> 172943 bytes .../concurrent-burgers-04.png | Bin 0 -> 163423 bytes .../concurrent-burgers-05.png | Bin 0 -> 159869 bytes .../concurrent-burgers-06.png | Bin 0 -> 164838 bytes .../concurrent-burgers-07.png | Bin 0 -> 169968 bytes .../parallel-burgers/parallel-burgers-01.png | Bin 0 -> 225993 bytes .../parallel-burgers/parallel-burgers-02.png | Bin 0 -> 203644 bytes .../parallel-burgers/parallel-burgers-03.png | Bin 0 -> 168628 bytes .../parallel-burgers/parallel-burgers-04.png | Bin 0 -> 219429 bytes .../parallel-burgers/parallel-burgers-05.png | Bin 0 -> 185116 bytes .../parallel-burgers/parallel-burgers-06.png | Bin 0 -> 157113 bytes docs/en/mkdocs.yml | 2 + docs/es/mkdocs.yml | 2 + docs/fa/mkdocs.yml | 2 + docs/fr/mkdocs.yml | 2 + docs/he/mkdocs.yml | 2 + docs/id/mkdocs.yml | 2 + docs/it/mkdocs.yml | 2 + docs/ja/mkdocs.yml | 2 + docs/ko/mkdocs.yml | 2 + docs/nl/mkdocs.yml | 2 + docs/pl/mkdocs.yml | 2 + docs/pt/mkdocs.yml | 2 + docs/ru/mkdocs.yml | 2 + docs/sq/mkdocs.yml | 2 + docs/sv/mkdocs.yml | 2 + docs/tr/mkdocs.yml | 2 + docs/uk/mkdocs.yml | 2 + docs/zh/mkdocs.yml | 2 + 35 files changed, 104 insertions(+), 35 deletions(-) create mode 100644 docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-01.png create mode 100644 docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-02.png create mode 100644 docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-03.png create mode 100644 docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-04.png create mode 100644 docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-05.png create mode 100644 docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-06.png create mode 100644 docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-07.png create mode 100644 docs/en/docs/img/async/parallel-burgers/parallel-burgers-01.png create mode 100644 docs/en/docs/img/async/parallel-burgers/parallel-burgers-02.png create mode 100644 docs/en/docs/img/async/parallel-burgers/parallel-burgers-03.png create mode 100644 docs/en/docs/img/async/parallel-burgers/parallel-burgers-04.png create mode 100644 docs/en/docs/img/async/parallel-burgers/parallel-burgers-05.png create mode 100644 docs/en/docs/img/async/parallel-burgers/parallel-burgers-06.png diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml index 90ee0bb82..d549f37a3 100644 --- a/docs/az/mkdocs.yml +++ b/docs/az/mkdocs.yml @@ -75,6 +75,8 @@ markdown_extensions: format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed: alternate_style: true +- attr_list +- md_in_html extra: analytics: provider: google diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml index 6009dd2fe..8c3c42b5f 100644 --- a/docs/de/mkdocs.yml +++ b/docs/de/mkdocs.yml @@ -76,6 +76,8 @@ markdown_extensions: format: !!python/name:pymdownx.superfences.fence_code_format '' - pymdownx.tabbed: alternate_style: true +- attr_list +- md_in_html extra: analytics: provider: google diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index 71f2e7502..43473c822 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -102,87 +102,111 @@ To see the difference, imagine the following story about burgers: ### Concurrent Burgers - +You go with your crush to get fast food, you stand in line while the cashier takes the orders from the people in front of you. 😍 -You go with your crush 😍 to get fast food 🍔, you stand in line while the cashier 💁 takes the orders from the people in front of you. + -Then it's your turn, you place your order of 2 very fancy burgers 🍔 for your crush 😍 and you. +Then it's your turn, you place your order of 2 very fancy burgers for your crush and you. 🍔🍔 -You pay 💸. + -The cashier 💁 says something to the cook in the kitchen 👨‍🍳 so they know they have to prepare your burgers 🍔 (even though they are currently preparing the ones for the previous clients). +The cashier says something to the cook in the kitchen so they know they have to prepare your burgers (even though they are currently preparing the ones for the previous clients). -The cashier 💁 gives you the number of your turn. + -While you are waiting, you go with your crush 😍 and pick a table, you sit and talk with your crush 😍 for a long time (as your burgers are very fancy and take some time to prepare ✨🍔✨). +You pay. 💸 -As you are sitting at the table with your crush 😍, while you wait for the burgers 🍔, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨. +The cashier gives you the number of your turn. -While waiting and talking to your crush 😍, from time to time, you check the number displayed on the counter to see if it's your turn already. + -Then at some point, it finally is your turn. You go to the counter, get your burgers 🍔 and come back to the table. +While you are waiting, you go with your crush and pick a table, you sit and talk with your crush for a long time (as your burgers are very fancy and take some time to prepare). -You and your crush 😍 eat the burgers 🍔 and have a nice time ✨. +As you are sitting at the table with your crush, while you wait for the burgers, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨. + + + +While waiting and talking to your crush, from time to time, you check the number displayed on the counter to see if it's your turn already. + +Then at some point, it finally is your turn. You go to the counter, get your burgers and come back to the table. + + + +You and your crush eat the burgers and have a nice time. ✨ + + --- Imagine you are the computer / program 🤖 in that story. -While you are at the line, you are just idle 😴, waiting for your turn, not doing anything very "productive". But the line is fast because the cashier 💁 is only taking the orders (not preparing them), so that's fine. +While you are at the line, you are just idle 😴, waiting for your turn, not doing anything very "productive". But the line is fast because the cashier is only taking the orders (not preparing them), so that's fine. -Then, when it's your turn, you do actual "productive" work 🤓, you process the menu, decide what you want, get your crush's 😍 choice, pay 💸, check that you give the correct bill or card, check that you are charged correctly, check that the order has the correct items, etc. +Then, when it's your turn, you do actual "productive" work, you process the menu, decide what you want, get your crush's choice, pay, check that you give the correct bill or card, check that you are charged correctly, check that the order has the correct items, etc. -But then, even though you still don't have your burgers 🍔, your work with the cashier 💁 is "on pause" ⏸, because you have to wait 🕙 for your burgers to be ready. +But then, even though you still don't have your burgers, your work with the cashier is "on pause" ⏸, because you have to wait 🕙 for your burgers to be ready. -But as you go away from the counter and sit at the table with a number for your turn, you can switch 🔀 your attention to your crush 😍, and "work" ⏯ 🤓 on that. Then you are again doing something very "productive" 🤓, as is flirting with your crush 😍. +But as you go away from the counter and sit at the table with a number for your turn, you can switch 🔀 your attention to your crush, and "work" ⏯ 🤓 on that. Then you are again doing something very "productive" as is flirting with your crush 😍. -Then the cashier 💁 says "I'm finished with doing the burgers" 🍔 by putting your number on the counter's display, but you don't jump like crazy immediately when the displayed number changes to your turn number. You know no one will steal your burgers 🍔 because you have the number of your turn, and they have theirs. +Then the cashier 💁 says "I'm finished with doing the burgers" by putting your number on the counter's display, but you don't jump like crazy immediately when the displayed number changes to your turn number. You know no one will steal your burgers because you have the number of your turn, and they have theirs. -So you wait for your crush 😍 to finish the story (finish the current work ⏯ / task being processed 🤓), smile gently and say that you are going for the burgers ⏸. +So you wait for your crush to finish the story (finish the current work ⏯ / task being processed 🤓), smile gently and say that you are going for the burgers ⏸. -Then you go to the counter 🔀, to the initial task that is now finished ⏯, pick the burgers 🍔, say thanks and take them to the table. That finishes that step / task of interaction with the counter ⏹. That in turn, creates a new task, of "eating burgers" 🔀 ⏯, but the previous one of "getting burgers" is finished ⏹. +Then you go to the counter 🔀, to the initial task that is now finished ⏯, pick the burgers, say thanks and take them to the table. That finishes that step / task of interaction with the counter ⏹. That in turn, creates a new task, of "eating burgers" 🔀 ⏯, but the previous one of "getting burgers" is finished ⏹. ### Parallel Burgers Now let's imagine these aren't "Concurrent Burgers", but "Parallel Burgers". -You go with your crush 😍 to get parallel fast food 🍔. +You go with your crush to get parallel fast food. -You stand in line while several (let's say 8) cashiers that at the same time are cooks 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳 take the orders from the people in front of you. +You stand in line while several (let's say 8) cashiers that at the same time are cooks take the orders from the people in front of you. -Everyone before you is waiting 🕙 for their burgers 🍔 to be ready before leaving the counter because each of the 8 cashiers goes and prepares the burger right away before getting the next order. +Everyone before you is waiting for their burgers to be ready before leaving the counter because each of the 8 cashiers goes and prepares the burger right away before getting the next order. -Then it's finally your turn, you place your order of 2 very fancy burgers 🍔 for your crush 😍 and you. + + +Then it's finally your turn, you place your order of 2 very fancy burgers for your crush and you. You pay 💸. -The cashier goes to the kitchen 👨‍🍳. + -You wait, standing in front of the counter 🕙, so that no one else takes your burgers 🍔 before you do, as there are no numbers for turns. +The cashier goes to the kitchen. -As you and your crush 😍 are busy not letting anyone get in front of you and take your burgers whenever they arrive 🕙, you cannot pay attention to your crush 😞. +You wait, standing in front of the counter 🕙, so that no one else takes your burgers before you do, as there are no numbers for turns. -This is "synchronous" work, you are "synchronized" with the cashier/cook 👨‍🍳. You have to wait 🕙 and be there at the exact moment that the cashier/cook 👨‍🍳 finishes the burgers 🍔 and gives them to you, or otherwise, someone else might take them. + -Then your cashier/cook 👨‍🍳 finally comes back with your burgers 🍔, after a long time waiting 🕙 there in front of the counter. +As you and your crush are busy not letting anyone get in front of you and take your burgers whenever they arrive, you cannot pay attention to your crush. 😞 -You take your burgers 🍔 and go to the table with your crush 😍. +This is "synchronous" work, you are "synchronized" with the cashier/cook 👨‍🍳. You have to wait 🕙 and be there at the exact moment that the cashier/cook 👨‍🍳 finishes the burgers and gives them to you, or otherwise, someone else might take them. -You just eat them, and you are done 🍔 ⏹. + -There was not much talk or flirting as most of the time was spent waiting 🕙 in front of the counter 😞. +Then your cashier/cook 👨‍🍳 finally comes back with your burgers, after a long time waiting 🕙 there in front of the counter. + + + +You take your burgers and go to the table with your crush. + +You just eat them, and you are done. ⏹ + + + +There was not much talk or flirting as most of the time was spent waiting 🕙 in front of the counter. 😞 --- -In this scenario of the parallel burgers, you are a computer / program 🤖 with two processors (you and your crush 😍), both waiting 🕙 and dedicating their attention ⏯ to be "waiting on the counter" 🕙 for a long time. +In this scenario of the parallel burgers, you are a computer / program 🤖 with two processors (you and your crush), both waiting 🕙 and dedicating their attention ⏯ to be "waiting on the counter" 🕙 for a long time. -The fast food store has 8 processors (cashiers/cooks) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳. While the concurrent burgers store might have had only 2 (one cashier and one cook) 💁 👨‍🍳. +The fast food store has 8 processors (cashiers/cooks). While the concurrent burgers store might have had only 2 (one cashier and one cook). -But still, the final experience is not the best 😞. +But still, the final experience is not the best. 😞 --- -This would be the parallel equivalent story for burgers 🍔. +This would be the parallel equivalent story for burgers. 🍔 For a more "real life" example of this, imagine a bank. @@ -238,7 +262,7 @@ You could have turns as in the burgers example, first the living room, then the It would take the same amount of time to finish with or without turns (concurrency) and you would have done the same amount of work. -But in this case, if you could bring the 8 ex-cashier/cooks/now-cleaners 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳, and each one of them (plus you) could take a zone of the house to clean it, you could do all the work in **parallel**, with the extra help, and finish much sooner. +But in this case, if you could bring the 8 ex-cashier/cooks/now-cleaners, and each one of them (plus you) could take a zone of the house to clean it, you could do all the work in **parallel**, with the extra help, and finish much sooner. In this scenario, each one of the cleaners (including you) would be a processor, doing their part of the job. diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css index 226ca2b11..066b51725 100644 --- a/docs/en/docs/css/custom.css +++ b/docs/en/docs/css/custom.css @@ -139,3 +139,8 @@ code { .md-content__inner h1 { direction: ltr !important; } + +.illustration { + margin-top: 2em; + margin-bottom: 2em; +} diff --git a/docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-01.png b/docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-01.png new file mode 100644 index 0000000000000000000000000000000000000000..e0e77d3fcec50e22c6efa0548ced74eaf6427dd8 GIT binary patch literal 203390 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

V+hXZK10wT3Qy55jO^XMgW^Vw`Ed)>yU9{&pf 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-02.png b/docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-02.png new file mode 100644 index 0000000000000000000000000000000000000000..27f6e127179cbceb02da41761f7489f10ed086a2 GIT binary patch literal 166992 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 z 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%0DR}mUF@EC3cQ9MZZv6%Yf{n;z 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 UHDXZBiVbUz!t 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

Nu=l< ztHw<=v<_$c*y&GE? zRbq>s&AbV9dJ(WQOG!u64CE90ezv>TX}=7ZI3^Gy*?J98z5WmxFyNJ#=87**t-JmC zot>AI2bwkC=}1y1J$`+iXG>Gt>sP9biY!18Vd36a zf$au*D7>HK+;m-!SCXLM-jvTPUOY9a4=6t91derJ-6j9$(;11q2Yo&xHNMhto^gr$XPm5`Eb8TZ#TJSlJPcKks&-+2OzRoV( zpZ@KsMs!3cx6lDm@6z(xH3^TK&E>pq7-&){uXxC(8=V!|S3-gC9jpRSC+={*PA*E6 z5U$_NB@T=}82OxQBy++S^A~U_*DZF31SiUBuKtdn7~=IC=`7ar&PvJ;{QB$&Vj-%r zpd*v8f5S(N#ud8-K5A{?Xo=tBZJpgq!v&okDaLCR$z^CQ-5NeUnpH#1_NNlgn{7)G z6mRy+0WDN`m$E>NHs*;C`Og1l&rwseINk;DyA8v>xwXM-w$ETtS|pd(4?|Z|pM&Q;gHfDIWq8vKY16;CxeJC0)>HH_2sk)`Z=D3J`sft}G*+j2d)COXqW zy15p7b+PVL5JtWecsy@- z6yqj!xIj3tSL-qph7~6|f2#rr2(SKjBC?U$ux`z!Tzh-{dlU0?xsAGTfO3=I(?~aN zZLMs^PyvAekP4&DBS;d(?ijRy|MHCkJw$c1yn6Dt(&0}Zro#(f)*VePxS8|n!)6k^ zD#zo}1(E@D^RWgfC9Sau*Xxg-OxN|1-F7sG8f+c|Zq}GOO@m2jF?!4Eq>!S$u#N_K zT?pe+NBE3p0U;y{L}@^-I;10i(NOOaI9UFu>q*+%9p2qGW?3X$e)A8iwe#IGcw@WZ z05^YJ6+Xed;Oq<;^Zr4BFS~8*IV4N8TPvWG(xr@M5%#e@Mo;g0OvKjXarm3W*kx!@ zFSQ^9&on{5a^#Jvb3@>#ekrrjSw6%x(7)0OvbcUz#-o<*1IoXS#6#m7y61_?7JLCa zM_M_!m+6FzR0?Iv--L=m?z@r_PW8IR&ohj%M7UA(B8?i7hC;ZIZ9Knt{OGnqqH7T? zI7>P)N(i=bWSvz$5RDW$lW+aJf~`>5r*q^exo@B)mHeQ~PQdi{-11T!U31t6N_z0C zz8h2uwad+xvChWYX2#N9T5eCzqh);Aja5lWJ)1Z58_ zvG9EXi=1S%Uu(j3up;zni zE$nJ=d7&87%wIlu3Rgc#YM+^9gDFDBBkNXoXCAVCADU6d^_75{oQNZRKDAZlxCNOQ zMloHy$U#_IC6F_>T5i!`J7b*hLc52aekK8LH3m}8@YmXf(KVPZO>QaHI&e*({h@>w zoW}$$P)bmoOWd6)T{g)tlE>oDnpeVZvJFC;wY8)F=W}cVR=b)%Hq4Gf#+GVO*k%=@S;v~ z*xKSkw>DZN8yVrU*?B z4}QXwGbDRAE?_lhP6NTjkbd|TRzzEzR7Q!lJJ)TNIi$~^<}OuD#=LVo&F93G2XwB}{`7%EZ&Xmj95 z3|8$$lwzA&L<~pP--yOJV3)n|nRQ|gZ*A&>B!I&BC&8RumpAv1k^BB64#nGLS~M*WYmTv7 zD^c1jOwm`5B8KKp4NOEL9z<_}d4J%JMH6>WG-AF9 zTlOD{WeuEPTN(3Z0o3?-){`B_xs29nsg5TF^`3qaLcn)OBHRNAj-~>QAOkv` zbep@5EC%!l!!cxv|1R$q3jJ|CE$mxPl5#qO=b4_Y+h~X1e(uXsq(KKlJ<43W|Dxd0 zY={16Mrqx-KOGBCG^4e4ThD7M=KkI&EvW}T{ragv`}bLV)C-dgpsQ(ASS&1 z02m{u>-rC(mTXF>la2J_*hV^lS&%Qz{0;dkELoR$EWlZiM6Vqs(rlf8z;V0Z&7TjN zX)+6BDbt1|FIAf)U=v!}_FaKKAv(=Qf6oB0#yq=ic0i&t@F}vX^Pru46%x`c+e&MM z5xrMI(^RPr+mrEI+{4PiRuf+_tjy{D7K05h(W69cwg<393SP9;TSx1p+Cg^Va`)cWxsiqv|7$l*~B`YoacNLW`O5*mD!bFeX{=? z#O)}otKgNE$KsM)r%AM2&+;E|FXgidKMIQZK3tyS$lDsIjN4dX8{cgLzw)y`vl|w# zRbfOFB85EHdQqyXh}}dC;jZog`oJIc>fVIi>@OhgJ3~4`{l``I!f%Hk7e8x0b4!|@ zC3uQL>?p>=Qi@Iyg~KJ122=+c!)BmqC21ih1y*45B@D+bO;~F%S2+w8NH-;FtJBuC zYsuGVx0|GaQKG$g0zyGZugNU+>ygQOp=AhrBWZP(^omJ20NZ0k*E*2!1t!3TVQr5N zFn=CI2q5p_5DDgdbMJB7=8ZoN?clTU#d-6D3*4i9x=~PFr@%s4W=;hrr-6Ju6R;~M z5@U4rVK;3NHwqh)?c~3fr7255?X=Jgv0DsADd6VGQSj2-@KfWHS^wcZA$hFdpPiF_ z+r()D--aL0_B2;L7B@{D?2UW{)OlYRAd0JhH>E#i&5WO32pp@VPHn6Yepd4~4qhOs zE$@MuQ3bu=7Y?>;b8Hw6^*TrW)R~5~1op-gW+zhMRn49g%>-Qt9IIqYJoWE;$J{>+ z->3&%&INO7k6QS-T;v~Jy8i+r{cM%EN#lfgZKDUd@mij5k>X?@6PVf5VE6`aZP;2; zCs(H4yOA}eVAqAe;cs2mUyc{mUdRa;a;pGiKHYne@dK2hyCDRp$Af}iaV!)d+X6^hnbP+Z2N++@uPP(p2gd^ThhvKo|SUXA;06?>npk5&F}hr z!!94Hbcwi|;($;s6l4ci07(6wora5ZC*H^+f~FlluUY9Tz4zye41tB~6T zloc=14=-28xDRQ%USG^WPzf1P(z72sl<6k=d5ybrZK zW@UOXkhuhkUrJXI@k{|ONez=4AAyqrB01CkV4|oyvre(PlnI(xVEMPlt9|rOlsqYm z-MaXyb*0?jS0X_qK1OQN-nl4BTB_ItlMXe5gL(vkXF++L78)nMKl9~4CkXCGM}>#~ zz1TlxP(7w(KF3waL=#KLEXP{-Z)$CN{w=z{7@kpIUK~ulsD3HB-})MTd^dqRK%jxu z54<2(G{3eoARVYElcMV{>bonYhf{NfQej&E@gQhr{0JAZldND$@uydYV|=^xFr z$>I|70sUsn7Or(8UjkreONOiL1%s>M@reSz2D=IXL_NaBpEVMzHG zOhH1riDpAs){lqCadQ*h&RH8SsttRSqtap?$CUn_6 zwlXes+2D4-LQbq;sAFnrt)Twr#Rite*vg~<0C0Pabk>klLXo>gyc=IhUnq*;>!h-c zZZq6PC1>v<$MWG58F+E;+ya^(1nGDcDJkZ|MDQNXbHiYr1FW$!lpgeVEy$PwBS!mz zkz%IXZ{PX|3DPBQ3K^E4Rg{aS;;qBG@D`_EH3?Gdhy3XMx(>AM+yPv58g4@h72 zIbncrWNPe0RF-wYz_;^`*XOyzq`7hS~}sM0Bpad-|9_ zKZ`857pG?3ijC!~33_lbB2UK9+43)xP&k_Mp(Ty^()wYVj!g@+&QHqy@&RrnFv;a$ z3%cUI9>OaD{$wS8fZ26ONo6LcyLUvPvxgU~#ye-|Y2?OQS=zZoZP>2useLjmkH5w2tulLD<2nOf|$l zB+!ki=wNLKDWlKitWw{!Qeifc(jO#Lk4}KqwuqoAC+ppr3CtAL^?d#q&GD;OAVCVW&3DGc`{q)%t0Psa)9HkP)kh@3ltNSa(jCjZ8kIWVzd zaQBC{U`-*uEt=pkf zbd_N5Zr=?%%G0c*2oGI(zC}LBh2L06|HHM<9pn}9Au)NMY%i}|y@na;^{)$i;Xwm6 zg*n4}N}?kYd3Hk)gCBzaPtVXi(PtNZfuM8I1!5XVd}JbaoEsYfWgl{T>na;h^P?MB z4vo6rixC*Nqu94Fw(YkM)P~*%-nYF+xMR;33sE*uXGw{Be+bmotx1^H7;yn0G3V5G z!{1l_(W$#Rz*{gQ$9T)VDsrZ;%~U<&Q}p6u2d@$M5B8HhE%9eeD*Ei|ChFE9#8K#~ ztGMNLBYDK;$7reZKncUsD8#B78}T&ng!iY;^jEk~D1?)ySD`oip1RqYiHO%F8CoJ} z*KUkLejWkg(8bnreDKf0;#zKn)qi`K(~3!S?>IW-=e&N|`Lmk&uxSw{NX%Fi&nL8B#^Z; zZ#v=yxZgpG?9$!*K7&WP#Qmj?$k6uq6lXu~K@iOD!91>xQ;E+G{Y_l>(BT1ALg?i; zjIqxm@s{^OVDR%kg8pCV$8HurjkysS(MRNv;Cp(Lmwj$S52-KKckz>CQ}Bvay`w%j z&NN`+4bDQqTsbp?oGgsBeoiGKAHBUo;W#wy1FmWU087`Zs{J-L;Lyf5|{2 zy^pZnd90Yw(uz~ts`Chhn^xz}$`Xq8;M!fnx`ReEpX;LZg=vz^|LCI+4YFj#Upu?2pF&*+BAp0l7aO=;?m2es?RU72vm6+DSZUvi}!(`L}JDC^D{IZCjdc9_cp51BN z>^a9@l&VfB!tMri_}ZV=d=j1}j6I|C{uSFS4`p4vGmY?*xndeH1afAv9O07_kIlsc zGUC$cX@pmhh2)?oHYzNDNJ#cf@Viv-U8N+n3_XB5d(p(GHl_lVtkpg3uZVSNm7Vw9 z5#9_Y{7LWgi{B)xGFjGzKC^ne*AAf^JXosv9?gSx7rXGE(f9O0B?G&uO>l&5ohl4O{HkCZJoX&d;pJ^^{OZ9-m}SNcKU}$ztW}SS z#xGWQTV^au5sjY|>C@$PUyoWF2=n}$sGV!r%y@?DG;p)DuxGT1dNZx%jkM8@>1;q7 zF_4!vc;!7f?GZ#7dI@k8{t|Hof;@_=-_-g8(P5y}R3!$?B5R1Y*4dX6=Ph5^?p7zr z{~TrDTZhJbahf=Zut^$vZ6wI)?p>sQzYOq%uUX%<6lP*2{oqk|WMjnAH&Sb?Z`o9- zWL4}AvS+nXVkSK$GHkxmOcsCzfSLkXVYfti@tpPjPwMV^#ZLgc2m^=D?%0-1%S*Ea z!n6^ZA13*DRJ%E8EHIdG0uI!&$)@IP#ON&09`}5iayXVWG2`;6t>)TAmzt_NH!zxS z6gZVCLwM<*|Dd@fy2C}wF%cPkBM8Hi!zUUs;H!Nj7$}Tr${8aEIrPw%e(-ge-RCUf zONeX0L{o5oeKlDcj1I54KWGj}MU{W-ld>f4{@e_BzszF0>QYjBA#GrQq`=nHDrUI- zq*W>g;HHUbL2I{$4O2H|BdcEspvH-VzisS1VadFpd-lb*u=& zNDe^`xb~Q zihbLJO>5e5Gg_KedFk$ibW6q)JD$`uCQGZeaoG-y>>>$|7`&dvuPs9yRyXo$Sp{f6 zdHhPh;V?r4U%MkUh`sUn_EejgGKH!>K9|>IWVfT#$^kdFn>t-UW}Fi|*SX#Vvk`_t z`Bhn&Za$5X_k4SzOOhMdOttKbRO(ovyk8Ch*=S_{eZk8hBVTg@moPmBuUwN*f=}SHDs)*kGOdV z$~pyw@%7B1hqyhuB-G`xs}TV1J|DeY67Z6S8-bYT_%{A3m<~TufkrUH)RP{a1-2gN zPl=Hcwv;!5uF`F8PLW8jP0E5B#~car1hrVFpk6V3cvH!}_B;wj8d|iff9+v3U{e)7 zTFVm((k#PN_oPpWqI_ZatIy24`?>^uHdojZ$nh7eq3sQryk+a;j|k^Y=<)Ls z^=OsVE7$`ZMb&4X{pna-=$$zR$o|-QyqH0s%{T9XjfO#&e|zVT{w!R4|G9?GORqc$ zey>ve<5jVkcigWL0s$)AZVPLezmXQ6HY*$dqL>8pn49cjpb|N528RV~zr%mt4HNlp zIw4_EL12B2ZMwmkDF`%v#uJ=6vQsS(a^n9_I+W?Hry9+B`V{$O3PAm{o6x*+siLxE zaG|W=uqnr#w-`AK^92?+pI=>KzUeA%?Avgg96tf5` zZo4Y_V_{IAC=;)1GqbnC2eZQN$nYGId^4zCVRu>ZMH)^BVnq*v=r>rdnC6xeQK>-@ z@#$%MIiq035piV>ysIAL_k_r=$@+`vSKVS^Y6d}EeR+h4o;n!mafhFRr|H+A=;#Z1 ztKd~3?u{M)3!_*_2X-DRwXLvtI?9{OqqS0-J>;nH^ohg{7Yn;$B7{!wN7mKK{i zGz%oC8R;U_(AKEGJ3FS|6N}8>RWKvLNHS3y5#oqZ@aej;u;Rz!5ZqQfkXKictWZ24^;lH_{)PM9>_$k{>oCMTU3B_ZMZPDP>M2WjMP`CTHDb zxoE2924%L7$*TW5d1HU+5YSYIfVtdT0i))94}A&L!_B{2a=9A}^#?K(ke=KtlT<#= zxj)|aR=1>n4wt)cdwG0e%{M%w>0tfJC+!+sQIU2^%X=3)3KWgAwlVFn@9dqUv!N&k z4kz%UkCfXV>?-tcPQ=04-=O}WMCI!6f7;*$?zzJ~ufXw`w;Kyk#x8t! zq{?yey*xycOY-=mIpKZB?~K4guyh5U7yk@CHl*IyqUy*L@X=oO0^s%DtH1hPN`qd$ zm0ffc)P6v~#42m8W{f#(r~Stlh_&#oiRJ0BnWa$R((>D22&;D5+WXo*EA^rvLZS0F zr$=CExeAU5?g{D&7o4%s;_^}>gZnHy>3fd=2QkNY^du=5j^fKARd^x}h$gedx6gUX zFUr1c6^%#(2U(ecK8>;c7h%)}R+z;N8Xuzg(H>Jxovu&ovaJ)vb0n+Qtmyg9g=-A1 zF$*)_7b5ro`;}7N_}D*&pmab*-r`Ph7PqtW*g5pM&e&FCSEd^M+Plf9jRi3pC@nqI ztT@wLgR3LiSD+0h!P+?3X5UG<_ek?LZKVnomP!AYLj z*1+(jR;ls2#NnIbSCtGEano;$mbGdaXGIsI|@ZiD;F|mrXV<75_lQ;ECX1m`^@im`ZWL27D+k1NmFOBp_?o6!#jpf(m4gwxHe`eDU z%pmEhrBh-v;Dr{ERGmBhQMx$cVY9|oi?}Lhji_G#b3F6_=F8+1Fztjb%{ot{vdmN$ z90UgM_8j*)xErJyhncok_~vNb9)dZ)rjqLpQDb!z(DOQ>8gZjp0{Ht%fR(Wt%ty9H zEv6h#@QbTm&ssn>L#=660PV#kpFBAjnf~qO?3ZqUe`;7aM5DIsW_US9d;oTZLI;H8 zn5Bf%>vag8C7@t8G%ke~38FGrIMOprFE1BI-6;sqsDV$sszTmuIE;xo9L4Y zDw-5PHWMbqn3a+$UcU3aN9U4^RzNaOQlg+O`qEUDyhzSCMJ#7T`oYtenY)x6Y}%<3 zi+O14sc+fU{rSfjY@W|t3S61O^S1qQf}SK4Oj+t7t%hAE zr(K7NL=gfnT!)2v0xvmM#Z2{9x#nO`KpPZ+TjU(iF|b#xpRxn+vcqH4j69J51nu zCD7^j{T#Z=F-#-j_TB5nQldEInknOlN#!P$2+Th)DkN8X86M90BEqM$+|X^^li)?%kScd- znWvn(NWO_d%SiK8TRnT@54xS483(c1IqsL@%IbN{#{Q=*#mbP3Pl?uqAuT!0_BGe% zb__gofgph-(o^axq=urR4Muk`dDR8q6@ZiG4WE7RMG>?-MZ-!3e9{1GYuiFWvEY1y ztXK9IR{6iDRxpmnYTp*?N~#fI^fVZWGg8c{hRqUdej!1~%yfW5t3(>^5*j#{E1JK- z=LbHjto8|Ro-9;jgTRFy1KgfCY%4IW-vVAp!aIjg^HODMyChP2fX6q4%fWb z&IIkMoy%&6rDP=OM6$?=CRF&!u`Ubyd7_Wu2@v^DnR=iDOUS1#$zScepDwoif44Yp z0NL_hm$93eME&NmgJc#ZqdmE|73^s(1{H@V9vNi1Khc>e0i%27vFB^iAGLf<78k<=At! z;{umQg_6z^W0epNi=xK$pA@-4zXdCE>Kg14Ucd6rq6 z7(I{af-n$eSttC8m`_eO96Z6yKWOM{Q_B_NkUw*8D+&ugAofd30ci@L;qd8BOf z_&O6URIT3HX^tku0-N|O^K%4i)$YB$p)F8t&a$#)SlVNGN9$vE4}nm~Z$mCu$;v`+ z5R(nGk^_EO)?UUKfSdMv{}Ng)M0oIdp3WP+|Ff*GVF!PTe+B2v&a`pvx?Xj_hUUL? zooX-!-OIPM&n?4~0mtHNat$pml{>wLm|7Mbx!R0IT@wk%kVCfYrfmE5>&(Agl%HYuYI;GaS*-ZPiJpQOHz^jn& zuzW()-{pp>CxM}oDDvF@n|x+fEb={U?V3Q)b&t-jt&>UndO7HH<)}x^f*n-h{>+Kb zs8Gy@1r{Sek-#@XgXG#BN(`x5CuyMg>MmOk*=1(D{UN~Vqsfk* zta3?SC&}4mol-H|ty@7V-xl&pjWMYiST<@t)syTHco({rhZ$v9fBG%Bd{g0YqVmTD(mZ1-Pzn+r+Jv@}~t4ZQ4e zCe>k?N;(lqPIEpAAnQ(*YUO-7m3-Yxga+HC|K%9k%2Ev)ie4Tc)ukm92;QLH-h5tH zyLjC%Mfs_|`vf0tZSC~KNrkeL6IJAJbG1e@uS#1dMd^tmZw@RTj;!vL-UM>uCH+zL zE6=U5Xy?o8x$c3&?`E%YgOr5N-4y=_F8_Ws-R9<{2V2zXjjNMcp<+vE8W5Ft$83>D zH?7oSrj9Kk@e4?-1RP8i|8=FzJwRq0k^659c$kk(pr{PvjbzA4R-^wzm0T7C3c`yi z0yG&|4wlHEvs=oFgLb`{La{OblwtuslEqsCP8kMJl-$A%lv2#&hG@#s`pe9jd?VDq zu}_KINOrZ81br|2u&vR&y1F64X|cF?CyMKI3r0SQ^{ryqw~>%E_+u*@enXoA(YXO1 z4bzzKv2a2Xq#no>=^2&W0G@B()=eoBs0E{#OHTDg(Odpo?;mn2eh7DU$^CNJ<{TKX zd?k=b1p~>34AWs!Hf(k1TOYCT;C;GQ-w8$Kaz@5Hb;&kUbhL)xG9JoOiyQ=%XD*g9Aztc!RGJ2;zQ z+~~s0%3wfO<;v?jGuU-iPwK1xdg;-oh$P=ZQ1z)uX$_e6_%Ox6L)G4OblY|IDT_h5 zzua-+`wl@-ynuH&uEFfsKMTt2A_%ls_(Ej!BOzczodEf|v6ohW_pF?_sjN%JM_IOA zUly2say=?Xye8__i98KN1m712x<6eyx%?9jzZFNHx^3$BIjBq^I_JFuF z#He;9LrY`OaTdlOxpusKNwd##x`Gl&h7PA){zC&WyfKbhWLkfSiPMX7Lf|)s-#J*g zexmSm-E6{lHW6_ngfxQ+ewN=pmPPYM>a~i%hH^aqx~UUYa+a+Xbz7(A*?V9U_CWcB zWdXoa*wYX0+Py!^x4j-sJIlsIh5$85q%A0>EleWp+h)sQ@iD=U^Avz#L|3(Vi^kx7 zC5&A2S-Ifg&jJ|w;xDC-jGJXLHRLJ@(W>w#h+D<-c@v6OaS2FMJS;$6JGY#lH+#0BY!piFY{5Nl1yVo_QptHq6#j7snokHjt%1vd{aZ#fHDQSmb)T&}|p zBU$8YwUZOcsa~pz?M8PkF-A;D0G|5wwiJ9mE)?{-cRI_8b5ayf5bZY_%(#KAT{2N0 zs2|VGQNJ!%4VBp}ufwi>O6VZRaZ>CoZZ7`$0Xb6HQ*ESrmuPSxzTR5@qS~V z3j1~Xub-I?HjF__!Y%iY^u{kR`}E>6WoZ>iQ(QXjY5_HcBX?7O3Z08vtC4(qY{rx! zCl!z$gSMHM7KgB$Xy_ALW z{u+y!1DHj*PGo~f-c9DbzDNOvbW?Z%Dq_P%HCdyH>%JE+Acd^Mp%mN(^*F0pLRytB zWl$K|%R34$F6-U?QPbr{l9yI>BSTOj$ry}=lIu`-M+m(VO=7cDpS9N3(@z$RwWQwroJhp=!FO?W%oRwF481Q$Z%N?Uw<2jwU_i)H+zO*`e;p zL6KaDO}koQ!ASr;#L$;4A2a&3XY_09!o1)R*?i?p*7nJQ+spk|NODm2e?Zb{pw!Ph zf2XZ`HL9nG3@E2DuGFzGd->gdq1xX4rak80%`aXTqUN*#-;_+t-HLXaH>Y8mLjUi>3h}EQCxA=E#TEq)z4;&ml}a%i4Llof zE!XQ+3*v3>-08!HEz~ewcnFd{^bn!hv1VA_{=mPKOV~-pQGo!uyY8n$FB`s$GfLA_ zgMGfn`{c(XZ|!5&PDfbl8=7X4?lz5uhLX2+jr+^5|*bA-oQ?WJrygd+6<9jrW?TwCW5mG@9iBJ?0bSX1nR zf{!~`vqr4i{G3hiTgao>@2&{QwHs8$(KWWDW2M1(qr)d!m=&ZKkwf*kB2?GN=oD{W zCL1}M@qg)1? zzuVmyTRnQ(eU(sBC+ac9M`b4%P>$z>FFumHW2PQ$wdLpO*t7F*n`I6#iHTzZGq_C>m}97*nT!~ zrrV(D;pdXt70o_Ue8^HC!BNn2_rTBO~zwc{Wx8{>y67=x#P|n|-R0 zS_M<3&Hl!y{qKJ=vpp_YT)v6+;~NDPDQ3=$o6nseN9nRTq7#-J=vztRk-dF*PcO?P ziPOghingdbG11G}h|38?>B+IDp>2s}_xJibtFHI=BFjv^!`iXi^3W)&r+uFw*-sf& z!MwD2wgu*N?QSlc5?IB=$>Bq1+&mNGP^h9nwTgZlUdFqw$(7&ACwBh4MhWzIwRt}8 z7a1H`Zlqx5<#whNgXhyd+M6p=qFReV4M=9)3QToz;#cUAgiWX^DUQURWTxc+(rDbL zF)5Oig-rD&Cko=1(Fn70|051D>(+dR^Gj|hL^0{rn6_1krr&U#)3keE?q9n?8K{0K z3DF^O?K&X<5`W2&L!Jb{gVMpChpvXAH*uTRX8x2 zhje$DS{CSCZF=N%LHGSdrnZBGGh>zs&^j z-Y&WH;&XQd?*}rrGdst6NVA9VDF@zMIQZQy8-GKGQUvB%Fx-v~;lba5;nvPqtAJl? zYvtA0mi#Ndy~(^zITI}{ite124*lzRd$nj6M_HdD7>lP~4Gn3W+y(4dbnhJ`NEGD! zez~ujCg#1}J-Ht5-7MHrC4mo)+8b=$&u%bmBW{ay*f1sZ_&i887=q1~E!nz2D+~o5 z*5X@N?wL1FMz}(LX`3=mc{*}*o)x3b;g|;Etvi#k`|GK*8CRixBqe%m!3%8u3*8yr zsvwwD)YaytywN}_AD9Sei`7qNhHsmQ{dJw&jy<8LJbEaF@^k&ZljE77Oz^}MA|6Ye zfT}B9-761tz%ywQt@v@%*rR*sMIl|)Uo@f>TFPRQ@C=1Jz5a@CbVY(h1q-%b<0(;A z!?&Ngh#gEBMUP;6C8pBATwiwhP4qGqbcb``I&Aobk}rP_5F#6lIzyaQ^Lis~hb=`* zu@#_Xf@v;f=LWj+8C`31iH)8z7-$9K}rE!s$ zZ#qA&z-_jOJ=pB1jHM`01F5aC$EV2V{U7)#r&oXO0nz{;Qm4#g>3MRL?5|4CGap(z zt*t0jF1zuYRcoExJoW?E(`f7Ul)Tkw5A%2 zj1D6Dedz>0x?_s^u6&^3s`_hVCCpA|#p3~m`hN!gDiG2;sO))-BI$0V%O{S?gDb&y z^~ppxx8z-urIeH8uU%bXC63L-&`Yb?7#aVu?pF+C-0kF)amYG*gJz5~an@2+#+1PL zA~|g%3jnCPN`HZogh_wzmv0$$-=85n3Oq)PL{L-%hn^Onc6yeY!6}FWD6EBydeu25 zgNp!6fn3DABL(p>8MFZh9CcQJWqaQoLK0bKc+lOgWxEKg)*89KQqa2V>#hVNabpzL zgSx3}Q?QXz#>{hJEuA%Z&NfMKE7Uai=*1;lwY*PUy<@eJQT}fom)xO6kNMG$w=RNY z#~7BG*(4=4cg#eQERxt#)nw}m^Z0+A2qQ7bG2hSk32?e;vMazeSWVp6-AAzLe!0Op zu>hc}nyT#If|JEd9buaHegCpcBCX=K!2tIbysdAbK14ZsN7rjdqz;#SVFFef+G{?{mLPjlweEk5E@nW5Rve)=janU;rV z(iJ+#3K+}D7{+nYy3qZ;Qr>`j=;>~X z9*#%P<2Nh>Sct&26IZJkrKz^12ga#}AXMqm$@FC3;T9N5!OusWn@q zIDYu!>O>v3uxQHXq$Fs?f0lH3y~5s>7tIaxl6qPcpW z$*mFP<9Cbu8#7oj+B6>mahQHuLsTHBSG)Ai4({S9|7t@pOwaoDV%DixS5IPi%rw-X zmhQaksquF8B71%2@A+od@vGh#ilZs$aq&7WtE5zp7Gh1f1+mv&yIgC-*P~CW8=bf@ z%lNdlWoKx4__2v~CMpQ;HT*i6r3V130EkQ&14wAdJm#JsX4j7u7ANvnrSTYp_Tk-D zrUE}covgP({tOIoD{}=-=@7o;$P;lCyxc8B=E|sn?_Sp%2zCWWw=%Fz5@RVb7^fh> zZ4k?JvISh;Z@LksJ;yXfQ!eij6ighLCG5)Up=D-MR%3{MAuJcc>1xBj9CY1+(v&U=)wfr(}0&dWMZRY zI>@K#%BO#n|7A1EVQT+=AZ|cn*-zZzXi2z{OO70Z1&^D+2L&53Cu$1n^qO5{1Bvco z{Qe!W-rcJJ=hZiH&E|B#Y!+*Mrs*Q7vH2y_YUA}s&zF2rSd2!#^VdfTeTUNbpGq~F zC@LNQBk7!j>w3Q~9@}o5GfW~bRLnE^x|g(^&n0JxP_I3i=i03m7s4R0XP)Y-UHV#H7IqwE|!FFNfm z((oDIb2`Dtc1tH8m}m*2%Fr+cZQ5;a*p$@oEo!=QjzR`BN)ffq++90GX6{>g?X zpuwW?D;+1^D#p;51I$9|d;%4~-073g=wF&v(03aw4F>|BPb|hW(x3QGaOObD1Y)N_ zw3Tv~Q9n$8^5^>YZ;?Kdz4IHy<3j20RCpZH(wv-z?eR9aB}S)Z8K;}lju9*XbiqZ2 zZFJgoc1}Ox@)pX<>D819Y|HaPkJ$SX>ByR|-9p@W@q??Had(C}i}H`+@9_)7-CLMa zesC7-$CR6=e9p~3&Me* z!|6W%3sBX)nw;^&iS1asG=9`}mJ2G6KyLf6O|&rJKe(X$cLncwylRTaibEJ$u5qc$ z;}0Ls(MY)H8uG_rmx_H@>KmbK$Yc?ULl`GDw4f*Bc@$H$(0<83z8w^L9IV8i z{k&7hPRr!-9{`U{`N|w!w!V`F) zUFHbeWr~qNtFDSr?6~dBMM|(Upu&T(pRzAH(p6QpiXkg^svWTb|M)TVpY3vp)%F-L zDZlSmwmJf_jJ*;!O64cR?ymSIGkV5sKf$4L6t*w4m@EW5kpF%?1FsQ;(n?cF9eTBH_&2&79Wn_0D>iBTSfKmT;9W}6IZH0k zAdm39XSVUOJE%nj9vKQM`t)8kSS+{gTgkMJcz^BW$n;C9Qth_vk9oQa5NNN6wTs2DH%} zR#%9!dYo}8yJy5>GlGpS*Toqjny|p6hwIjEMi-TPGy1OMi4k2Kya49OtX z3&;Jv=PR)WWLgsRSh$Sc{(eaHB3gTqshoakk~7 z+TFA+&akhoNXk!=09O||@UBLVY~|Ajo)dQl)jU#xCE!wjzGwE>eH3rKEv44gQYO}i z$ASR$T<|M+oR43>w`)&kvNdt97Y~OieKBOa-1}7?hNwfoq{CMonTfL$stAv+G|>GO z0tO^frGH4}9&d67ZMY56Tk_1aWO(dPj%St?TAHU?tYv`2_IF{*9#hvoOe(-as z?=FXGzn|xbV=208hAkn9^UR(o`~r`qhDQ#ZfZ5E6w2u%>)vdBfsn+l7qAbqh_0I8I zk5kgz4B0+YJcf+M5C>OZ7#)=}DIIEZT48rb!l7Na^N z8TRO`FSU-DfUD$Yg{}YDM9cQ4d)4Z>hK8NiWTYFSRh3Qg-d}MAqVl}%C27r40x>SM z0ja;+Ftc|l8Iu+aIGE|}U$Cae3w?JPET(8FzVb1e01iN7io^`~;ZWcpXm!w}F3}@+ zy4ygD3fo163w1lD%xw2s{8{IAtqCQPBq*?VIJw`whuWX+QuH8R)##TDc&AhFKod{6 zcza1l`PW`&t|TiNq=iYVmOI=zo{JL9Tvi`0nIZ$RY}OfSS`@ac4s&BU^uAQo6{mVu zcOP?^hR`#vxT;`3T2pMQTXDJ<3AzcI$TsF*3QF+%YQEg+B*5X2Sdy+@>%Tg$ttZWz z$%ObB(CTqnUQ%6H`>}1p6*u;ZnzyTm2`EurPm)iKm$Av+)t?_@bmKdaLO!q=+WSM> zwpSNWaIa!r_p=H$0Y-Oe5@;PddW%_AaUJ^VSoVg$b-gp`9&KnBY9CEe9P~aCBzmvE?fvJ-BT%fj#`YJqvDm26Y6qj z5$H&dfNu6WSy6w&vgeV!hI><`TN-RI-joEB@|jzQxBGhD%JW36NXd+F{(@?&wf>i) zfv$}EJQS}cl6WL!!$O|L>82kO5yqFmi7?~X%JK>sV`-*P%62`!1>P(oCLR2BD=XX5 z=KAczFiw7Z5~k8jB^o&vG*LX5FfugJ@6_YW;NDxj>gvi^(3MlcLl$IT>65d%5y=WFte1`ktd+nU8VQkJxy#=*n;0ovia* zFQTuV@_IWsl>I0;{egV994Cmb1_;$HYd;V@9|hR333yw8Vr zF6}l>(~DZ^0vp{ti=g}a9)fCbo z6uh~MpIo(leWg$yX3d{%6cAT_rK(ZG4(T)dmS2Wo5e1*Q8Mb6WCO{whd(o`Hc|lrU zk&1^S0{F{`i5F>%7L%q;#_9vcvzSMXP^Ol{Kw)9uZA=W)H&Lp`<@JT6>|aL z&&D&|AT?9VUAp1rVdzJ*GBsRdi8BD&)e6`4JGq7NGC2}&A*v~?7z?eSVPKm2yOtcf z(bi%nlLck3r8+s2%Z<)4!5pG?9*12wBC2dO6-?OkTJyllfsT@6x7)lQ!y2$+rqaHD z_`+@BNN&!{N+{ANCP^^YSy>lZPJ{y{rLtGg8*1e}LUoOzTxK33>Y284f}1qZ zuY1sT7RVY?!L9a$TU`MR-#RbgeL4`JzTKeBoAwH(GCP}Fs7R71{m0FG0zl{Fd&hq* zRouM9IZ$D7KJPL=?!AyzfAZ6eNWf6po8-|r-UZ7Mclm(d zxs)V4*eG-~LE92guqGQlQ&@B{6D;PTa$xoS%7VxK5<^1?g%2N?Kjf$~1#S{!G?Wu4NRi-v7LkB>BPA--`#OcZ&I#caWLJGj z5i-J*F~~ud*-p%0fz}6C@*f$?y7gS??2{U7oSE23+JlF6#?2Y^Yt?CtR17$5j}!#% z;qoB9)v%I^A5;q=R6?BD;x z?D{x_28eC)4V!W_wzInkj(>d#*5ei@5ZbBH*!bFP6>wT>NOG+GWJ}}X-jCID*8I?0 znHMwNd~bvqd%a#M=*JuX@gdus?8e%nej^Vb9)xbR7;}F9@fR%N*mj)#e;mk-2HxCWevP4wx96nD>s>s4sSRlAX&G`@Chxjai~(!$N}>R;KE z3tTxO>Xk?pHCY4!`zI*Re`2l&t5vE$zx(By^h_~ef&mGZllown7xT&%W~h9}cT_!P zvolaiDB#kaTfKgWH%n-I&hckkCL&%vC1C^KiK|*0kugI`#e>&SS2kH^R)9R`#54pg zazOp$?e#qd+rkU3418yZQxi+VG-yTOOi{d)3KW9soEcOd=@18nc^r<)w_MNq$&O0r z6nK4lmQ|cX96OGoM?slVB!IQ)DGib>272gWfQboewzd_0wc5+A{G^?lbyJf+TcVp~ zZ|3{LvUDMPqYNpynw|jIY10$n!2;#aB46$$YxZP6@4gur!im96FS_0qZ(oY5Voy>b zcl%7!R7ItkxCsEvUf=ti11vLS{dPz1;P>9#%fEA))0mf<`bqjv5UE`MRgU0$u5%gw zh4f%NzbRu0$G_?!`mizAB ztW9bV)zx=nGmlhNe)F!S#v6sWwnK2gmH#b0C{}49Uwdo_pDtnQ(9tilD9uY(OJqwL zJ}_BPS;8?!ra=m-o!}aEKvMAWqjs|_=#-nR7-vK*#8gd+n3eOCO*PhnHLTKWG={HC zoicvQN%GSN3u57S!aF<~s_A-q?kwfo!Q>hQ_R~!xtdbL>Ol*6&_tpyZ-v??urvWCV zBSQluE~bR)Pg8k?5}qO>qX0fZ4={XQGD@M>8=|ez54na|!M2z=a3eU@YP)SBcec-u z(6iCWy1Q(Wi|AT-(s)yXUO#LF&OUwmd?OPmW}lnzoga(<_+gqI#rgs_%KT+)f%*9= zpN2qTtq)uB7c024a%24vy5=3sfbWZkj}wa8-6fR}S32xg$7zGwXD*%2de?L3Q6#o_zN;7f z3FPAEPY{|9iO^_l_>+=L1F=UqY~zxgjsimFc0E$`BkjVmdst2`W8=XOu3*eZK%emFyE|Ai(OOHjsE%t^(K#wx687NK%tAU zC&RDw#~&vF=iCg}kMu@%wEQk|Fcu&s#g=;Jv{*OWC);8B1nUnQi@}a>U!-DJ2x}qC zxbrHu1w-7*JOY;%OXr$Rj2-kr_NETPrdQMUvzV8w%i7o}TX2;gxV&mp*d zFXvSWGHpc{M$EtV|5tzqlQM1bE`C?yt%-3jcE^i(R1dX35Ul{F#en}Wc*c^h2D*PL zyrHLal2UBB&Gnd|`*75K_-x;Y*zy-u0Dupdo8MBg!qbnQRvarT3Retff!6Ro`3``f zdR-4{0*nEl?{8c>2#tx)S5LM(AcCX2y&xR}Uag6fQw6;qQe%B1*77251^~uY=j0@q znTlHnARCCK^G~xMA-nLV_*Tid9m8 z!VZmk75c`7!gOCsSJx!vj-=My-y_4l!cch$imzIHwAIX4)M6Gw27m+O7}^&kvX!4k zMM!9s3&_7XUgvgWTEGeW)16w+3SBV1zs5`Q; zK~0E{dVyS33Atxlm1+vPNUt6_NtbAYa%m&$Lr8DzhBA}W;Vv9I#D1D85Pd=o92&vt zF^8AJ@X+XoR%@Fs?PO3?9!F|d;=!^ZR{l%G8C7z8sGujtDntGM01FpBE|WVDf)AIA zr(B(UzujNCeVuZVU$6@{(iX7g%-4~Odi5-ec8FGOe052~flxxIvW^_%OJZM`2- z0-rZSmM?z@QvS_>5_#)RxxmXJ2LNbi|B)vsb={G(^HpaS z77Zngr{#jZ_w(R7Yb>+uBCfre98@53}R061G8U?Fy(?h^MiE zMwiD%t+u>!Y3RnTwD3_|6}u)UDb_7yn>9|nRB%bsts`z&O$eFRpZ8oOtAzzTNukdy zuM%QPsV?YPapex71tOz;|t19z&&D%r<)kP0XW>i&JQi@gB-J?K!C7TjiL=x4Fu5hoUZ}8Jn zCpASP0&|z0oP(WVZv>AHA1k^gX=N_5)!@y2zeTiN_e!`n67iHu^+wya3dJ6BTu@0% z>aJ>!7@8u20{HxBvT zsV4^0)x8a6A<5vmgbb4*vqXbNTJ5pFK=<~kD*3#=LR<=1Aa;X#uD-ATg%fi$dHZ7E zeXM@@ek`vX7x3WV^E_xtoZnocPpl}Wrp=Kw447bw^L$;m!y`X%PktOncWl~gwEJJq z_CK}Ta=}LN@?@XwiI#*9FM=u9{EDZ7^wYH^nnCeh$EFboxJEY-Z5?e6RXDxB3)AO$(Vw0paL< zU~`&VX5}gYlW8gs_GfZa{d!cfZh@;&=eH))#L=!{Z_ww*Zsq%H9PG*QJt_#XCl6^W zZh4$F3fa7_NQ%mTPk&+qoLhZ+<#79iC_SUIK-j&3P{echyBdTrsYKTAOpI}aU0?kI zL?Z^M{a>0?Z4}D)EQhhf-yw`LjNCa3!!Y%^0R>%_9DG*HIx@Mn$LWiM*WkBP{Ei=2 z|HM?Fs*_Y?znPm65Nq?fz?et&6(M?qv!r7z=^5%p^Sk@}Xt!5K5BR*D>Uvvec4;eU zZZ#!En_mqmN&kAJ`!Y=O)Mzill&Oi;09?(*FSJ-@l=2aNJ4*Zw)xiOmWzo9aw9Hd~ z#jXre%Rq|Y?w#T^3O zZn{Stcg|k)mW`WDJP^-QF#bsjQkZb!{z1_9AU+)b#_66!lr=&Tgw9vW6D;UWUf!t2 zOwQWBr*2W6{v!#ae4-s#1}-nVcA2DZ&P}4j$dzB%p$9&;X0%$Iko6O^sT*P13!6xw zPDojH&M2Xpd@KzD6O*lu2y#1P>6cTlW3KFvMk7l4JHerD1qAhwN36|TB^Br9l;bhhjH%y zg;lZFO(qy#7>?lr`B?^syy-tn!6hwSYmB2BsQqC|ukZ8-ShyuBdVi>KTHM}3e~Bm8 z5PVe`yUJ(bD{l?PM>+$j(^@=SynG$N-)a#ig~`*<1TAd4vz@dCGZrh9&7u-@85*|_~E?k4r^s~2SihU*xjiB%M{uX z?SSd5)z!W9dUuAqPQ|*3{fIrs&1>b+b+Jd4xxW)Ha2<4@@(Xr0KY108A52D|Qp{TNb^-a!c_OMng30q#aLhXMxq04V{u zEcnP^pvLusSjhB^mMv1y%7+SWI@WO-+|9{QLB3o8&+F(wp($4T;3{@X@9Md$*J=}1 z;M%)la$jSofyuxWl9?ifj36JX;V~JGFFMOF`jJgr*d*)@PC*DR5pEovGYC-l8iwIu+htA}p0m`Oar z#Ap6c=^&C4`u%Z1SK=K%Ocsz^V}ytS!14KMZ9!kNX3A|WS8ZCIUmGDjlq=}r-ip}& zocoBWX>R_M5^o;f)kZg@!?OGVJV>)D55QvXQYDdin`1d+U%?86HIJ%7CIln1>-W!J zx|+H%W*j^5z4gf?zC6&6KDjA_+iJs2$dZq!*ixgfbdnGEcs z<`V>`qAmfqx6{x)Kw5midgF3hYJdP;U4`>_wwOyr4Fs*MY)K#33xG$BO#-jno1dQ@ z)}oRy#M|0qg|%6dacs;PxtWtIf}POeei?|uQ!K;*hwQnpv?sBHJA5v5C!#9AzRZIs%&`+)d z?Y{w%#J!N!%|Z(G>I4+9Nb=XV5qP$D4+ma%S*ueSc{&E=aw z^{>zT2tU1fp_bYf7U{{Ajoev-Znz~m>qxYXy67RztDz6%D%!`BnRMn=(g9PCnMK!K zpz0_6aXNbc6+;h0E3@)CnL#+sqK!cKskzf5K|riS8+dj;enV8VbuPar%mAX>hhExTm3 z{ZU}4Lgh=Zp-~Ainmb1VojpvneGWrwQ8^y=bgWKk2K2_&Xx(*1&hY^H9pN))K3HcPt$& zL18?EekWL97L^fASy)O~C;~oJnuKUYDSdanYr`F#8p=K1kG~$b&+eTpG{t|9<`wj< zC928HQxAg_u@SxqB7PC1aYhmRSqtN*wRQ?`fvc>!^j+4JkLN{9^GvLtg}60!3DNRq z4YY84gW?OWXB!Go$49_%aAWtd<RABA2QiyXMhm;bG2q1bTw_U$4)&-fOk*veizmS2SFZ>4&kMYoa8As~s2=e5R0NJK z9wFqDj+naYPhY?e?mUQ*QhYl6np3}BNTMFmr|54Q`0HkT@`F5{&9`#LN?Nf`NDShW z*cKUA2{NL-7;1mQ+=uE3)(uEpIo@?7XeS>Ot+yM?!&5W6lcKeCk@GAf}je09iuG(C2 z``7;vLSG<^1@9*GvuZA*y?P7!+%!{f@;z!Zt&ZlbX67*Ev-lS<+$h4|rcTvW`vCT5`ePXvoGr%18H3`L{R z=N4tD3^cdFy)MoDh-!+)inKULNK6T_;6z6Vxo+!nb#DWHLcNRl5|bFj<*qF&u!|ed z)`^j--vzWFZ*?fsbt^su9U>15`WU}yf009y(7Hmz==61Lp>@U);De4F{-aP)&dPWV zb^GQ_n~-R`3*uq~G%(!j^f-Zu%8}EuvI|nQMIUGj$*Dw9&#S}Tb@-B1(=}%I=K=Qi zpGE7IqlpDHu-2LRC0-Rz6d28Xd5UhMMtp48iA3>cNz!0Rbf3h?VPtWeOsGvBA}+Ap z0z0TkGbr=6!K*K-0ZcM1FL01PQzz-UU}-@#yJ*t5u}B|%K<0N8sa+>7`?s0R_oFyr z$2Jq!V0_e#j(DM7&y*Aek}x!W0JQi|xm;M=%_ekNxY!8T_ucZe;~}a6Tbi<`Bj^Ck zY}c=YGzb*yQ-3XaX{MzufR$s?oOeZf9&TdSKLZF4>MwBjn3yb6ffw$Kp`^tyk}5+k z`1yveyrkvdXuF2ZNdN#+pGT2>Tc8FwAk9iwfyo(Al>u!i&&eaYwvJ$PXJiU^iYefi z*~&_2&csuBZE-MZuwOOLR`Y1Y`Nwq6>3M;PTaV3m`eN zE*Z~3o5gkq@q~>UjR?G)R)dp?7EogND>6H{4OYkN@2Z>JUamcV0%(G(mhKA?oOoH%IDrW29FIbE=7(l zDR5KX5T#*-2qSw+3*CN;6l^@V!<Q+}FymkI6P#PNeVW|Ub04R#Cb8uSCVz}H; z8^6jGh#`YgPz;;_IddUenzPVzc^xCWnsV3x4|;UQwa$O{KiU^mTroHR0;JvZaZLu{ z#83zf)^lHL>9qw$N5z8Y8n2A}LbQqt`W`Byy#CU2#pyzf62Ji|Z~9r-Uq;2|)JeL$ zx9xY8m-;iRLf%0cNe|tvZp|HKyc%o;P{KeRmBtGh<(xz_lOZuiMJB}?@Jq>?Nt@?H z&*P1%WupZ?cSMo}jlAlN6e_YpW==tV&?Fi7E=Y^LeJuFijeH*ae5#8xO`8(A06;)D zW+=C|0=o$f4~hq+noKB7fsYydLzjd@+fyfZiVyeeYr zj}(WQh57iCzc8+p5-wqti_?0+m%q3{ktxMincM-6?F6;L+uR>Ip3hiFf+y7 z#jp$93tWBSwW{)buM|W#Qj_*^S0I(SO z?i(zTWf}r|E`iU3G{1``q%-4Rsg`{yVqRsZ^^~Re*IitzAD8w?Tp>tR_*wOqXPv&+ z@9^!y+bpmRiB#@4#RQJ^$UwLTwgM*iNzp@UBzV6$L3~#jt_z%712>&p%0mjg@8-`4 z-jxWcEgGJv*@KFxGFHRF`9_xU-XXN#7^fH<5;&E5{t~9i!IS&Qdf#YH9g9GTXCWCB z5Y_7ouVJ7vE%^l~?US^@Eljis+}fv)8FadD69|ADP_^(~Ysw_}oc*QIk@Fcsg{#jR zCfv`qARC?uo;@z9Nlf=9nSnG-J;Xk9$7aqvq#%5*OaBl4w5eUW{Ny`znj_PNinI`C z6)n{mx>x?gvzYI})7y_rLNCM}pmFKBopvj7cW4|z-+3_f4a0q0`A>a1x8|Rn=$}k? zsw3b;qRPpaUF+wL*aGiL+?EB9i@7_=8@nqC;@M&|Pyq%)4=DUY83oTGYBzHAg}~+P6y@&Ei5m;fcDfqs-&*m)%NrgGqn3M%M}`r?4a>(war>kW@bPd z?mBem!Nx3*&_+Og1-v%rXR5+j%WMAOwWJs+67|_GZY_YvN3K;zB7UdV-JLqi=N{(o z6@q%J{EH`s8VLbds@({CW~7(Xmd^fDQ7fQBFczz;93S%w;Fa*xj4rAX%~c(Al=k?~ zt(1G^)O-Q;>E=F2&=$6ZpK-LSz_lcHpQvHoJgx zhTNg8BEe_bBb{iV!U}3Lq0T4k@qGF z=ba>HTAV*M@z&cKvyWRC`q&`bpyjbrq3poN!}cv6O?1chQWW)UP=>CF%XRORguy*2 z)7DrUbbnq3OtZ$0P-fdty^$tHgV(q=S|ThBc|vBG^*I+cxWYD(NV+sy-Zh)WH7P3B z%;L8W6V&f1L*tYA-R-~}&|(++VqF|NL^Q6##|^2pcXK#YGV@lkt4)pI{uq8KZ?Na+ zKV99&EC%*8ERB8`Ln=CE(03}bROg@p+pqRL-cDCF7eW_EVpTUZNCQGvs4Jy;xwCA4 zz4{}7Tk3TAg3=K{Pv)2h+U_;EsblhYjatfSa)++Xa8eEZx9xRDMQWoY4n<|Clk^E9 zpEOBT@ECFgA;Nd=yKSCGz&LfF{GU(+Uwn|ao`hbJa*XsV6pbb<7XRAB*~7@Lrhj8K z8b8Z~C=n`^GF2Xelw)YTnrqVZs=ov7(`6G4$nk35e!KWLg|Cb46O>WK77X~rXRwHY zB@qw}rw>G%1#;g&_N+gtlgWAFRr?-jAMIU3vt2F0z1$MW3#w z)Am`a!d{NPKM;<4wuktU@vW%yKP6y)O)X*h(OvKAU=Z6BIzA*=hP3$vUk$lwQNOT| zuYONYBxeK17x6Fdk|LT>h>Di3%bhe+GOz6Rw9EVoD%0mf?f2G7VV^wJ`huzL#n6O& z`p|*-XLYq0z!n4Fdl-PsOxwX#H@|)STm6BGT8+K`-B&wdN(QFW%Pgt}2lu=@q#M`F znXC$x==mqo4p%b3hcq{zwT=aK3&Tw#DSa}_g@^9Xg0{tw$V32?NGd?2gcE7x8{PHB zRm}Qv(9UM3=J5=V!m(mMM@nt}SFz0+r%MMMIh*wgg&^47;TQ1vXx4xCv_v*fcjufL z+j$gUwav)p{P>QK*ibyWxtei91kGaQ+~Y6(rHBgo;~5Ix0?(Qzu(+BS7%YUXMqWxK z!v{_Jy80l5EyXG|-QYH7!NUa=ge!@O$X%ky)woYiBThlz20qB^dA@)uLMFwDE zz#8EB42PYZfUOjubo3TSnBP7)vO=t-XuN#Qya))=Gu>_+caihYdk#-3tFxhGP#t9d zh_;!f3OCoXM_TOkKhIXMT!7`aI5X2lq_Qo92;l1SOj$W#0MphAv1L;c%{RH1H>mE$|0=Y|yiPq%t!lSz|U0&hdW3VnErio^#MdJUilg5N8 z`L&n=(_R~4hA0)DmTZqIHU!K=_(Z$P>MRZ&ApF($`Ban zk{>-8v-cb2JF!!y6Cy$iDH6OFBEI!k5{O|v;0_#YNcqjj@!v(Pb=&(o#4@2$Y&n}1kwr1avL6XInpo;c=^rt>o&Avxmmt1%wANUdCzzuIYSY7(=VKIQ4B^H8$ ztt3x=OpwOO==?hqMCa@R@DZ6Uai@w(*T-a9jpx+(jej0e;ew*vD}UT(l|wd78dnt@rhax$%Dtw3qFxazOz&z}ueB^C4awFuGl-e>1}rdO2bRD%!&82}LcgjwlLUW<0aP+@H9{FBjz?37&o57xKpJbVgIoJMU|2za(pgz(zugZY zE^J>|v7zVMIE!7i-Ya?1p9ov2PME=-FXva0*R_K!o{$~QWaF3Z!>r9JIrY@9g#-(% zsQAsmM7R|T2DF?7!LW@LD!(~h_sV&Agll|GG1XF9c;#w1gIC3&oGs85#`;*+_n0(r zX6W;M-38y`G)4)c?bo|9Q}3bw2yBA+&?|$Sz=~HxjsHX0%FN8PvbTrHYkY$(7`c-S zS)$;Bg3-ZxR9yZu-}(?BsGjf@^2>hKZ#(1q8EQ zt=UYFPKGXj$l&lOBnXto@ka~gY$QH@PAx5!Isl2R`76i`4uIKGR+x}MwL$RmF}pX^ zmPB1S)E>sr-+JCv@ZXPBMbgolLAFQW-mS{&Wc#|xZi z)S)@LF^A0x%y|o$+gzeh>ZE_Qo(;!90Q#CTa3Pt|IDC}+kdZVRxp*Ul_9_f8urDW^ zJrBhMW#wmkT1fQl@j**1gKqzX0HBh#-(-pEtYt7=>av|rf<)j1+_Ap=nBPq6l;r!T(t=*HEq~Nr z6`47aUA<3tGpu$Q&0e@Rw*i4YlCL`vS(dWXawgNK^TroZXygN;b$~ym>vw*qF@FjR zs)7C>09Wsz8+Fqi13oV6G?z`Pf6Tv*m=59RJag)C9FJ%O5Zjnih6#i!$>8k%Mgqz! zJRH8TRfr1se6Yyzr869-<7epfF7(lscMDvsdqm<%d>YaLUQ(8FgbuVplv7FU_e>5R z1;-^l&v!>Nh(0u6H_jm$(^p!~Hs?zkcM~{g)xZ8I#};KLS*tx`(=}im2w?eO;9y|V z-$m5;p49G+B;$bSG&Zul{lLDlT^W$1LIg1HLwF-LgktJNEO~hQSiG}tA#Ro@a%FS8(ppU-lYri?|y99-gF=0Nn)pOk|{kRm)x(}WFNF&pRw zE6T!OB2uCXNZFIR!ssI9py0qOmWlpA($Gj~QNi9jI#_g3(+08(r!gwV8(BE50!G>t zrtyPTp^i+{fK#hS;;JYN@iQ{Cc^=*MvGxuH|GRtIL)=oA_2JbGKXY1H8Mb=VZ-dOs24eq>Dt`kd6J*Km}>`>XJSYx zy#76v~h4u$?^VkTY&xw3Pc@&cqtx|cyb0a_qH zZ_0N#AAfq(dRF1-?~h5`7^?&ospJ^K{>{%~d@V_9Ep0qw4Jn1Q#N-=Q&3G9eOorq% z`23&Ejxy^_#yIzMq`I~CVup0X^~tub&5>d*nxPK_7&X)<{SZzr(ZHI~IXDmD(lH`J zp$TPZ+T+wzgcauC7?-}2R9+}Zl9eUJX6_*>$eSR22-2T}F$d0DzFpEDuJjd8M36vb z=Qb_pL`k+Yq{(!>Z+LM~OqA@|)qkTKwZ_Q( zjf|LJxshW&u*nKFH_q}rTHwwdnQpm0qE@^;UPiFa+{6>h+5lJye86xVwbzYa96CaL zQtF4Mz;(mk}MCRpmviVF8hJ#|<|x)rf6JT4X}oT4Ood7l6>{->4A& zb@YV+RrjdH2({eItD3<S zKEl1efRHofv{Ysu$56TN<*N#)t~V$k*S5G}Q?kxy@rM~-$*7Bj`?txdq~urVmxc$D zyiEc|j301T;(vZl5pGlSQ$yS9V3dDhF`&>UTSd6+iR>*9uCzRCHeUw90GDxw`}yH< zvvVf|+ipK1k+t9@1SPNwV`IRT#buxB;+zfpek~7}JE2{lanjP8*U-r%v$Q2}g&bl5 z3;I}+)xtx~I=|?85ENF>U>#8aocYOH9_{^G`~f=lH!;_a!NnFY9{r{1F&DdY0lk@_ z427(kzW7>rv$vNI2c2m^tE6PT6G8wPtxt)y=!g8O3g!(7<@-7DlJ?}S^50G}SNLYM zo3Lg?4WcOPe>Y$$sg^hATc>FeMB>V5qIv1;RnjorCno0avY->)QPG`>|j zXb%JSK%b%K5H#R++0(84L_fPSkT=lg1Y&`J(=#kAk_uw$SXfpW>##a^5J1@>zv{dJ zW|ScGeU6fKxk8;xt8H1l@ydC0GJMx%!uGB3Lq%_`|o&P zFAZNr69ppe<`}rVy7y6!9ZvNM1}z>ZT&UYXN8di`E@H@uE3DP!werGVNz0JDer77C z2Usa};5xy;6)GmenF_Xd8a9P^(7-!Z&-Kj||MjxE7M0K8Ek=L&GYguECk#uzic!%G z>(#>so?bNXq_v-pwb?{x0h(r&)5m}wyL>;~liwd;_HojT2vD%`#|M|XTj9x$f4JVhGq;Lw;KTtyw5{9bm8V!7r10facTv`gV3a6M zD%LvSL}+Q}4hy9&-;Lh#TF-ZfEcN(tVTtrncs4i1G`nQBfA0Jj;eav>EIWE$2!eSR z$TbbeMNyNkh4TZwN?h?EU~^!Z|EF715jV_LD!WZRC-eIzLGb zk)D{zYSl-97~%1YH1(ZVzhCYzT*xC#TAD{;Br zE%u`d$-S2`e0L7n$zrQdTe9=FDqxddCx3hHU>df4k*8DR=CAjuoh}6B+cpJ$gbJW> zdhUIvuL+!fo$IU+x&xYH6B&SW$eG2&;5gl>F#msNPwa{fQHMr#lf=R z>IhSmK{wG(dil;L=jdrtfH#g0=UW)wbhW%ey}VpK~e%{;J!m zv)c-K1u=J@_hQ4-7rDE-rsgh-BWy%e3_sb2T%VEkdN^}cJEG!>Pf=H#3t(pF~1~Rn7TX&l0bDiLh9#%YOdBNYgj41O>9nyxBA z9nPq#mh6(V`CpF2MTeP^I-!%qsSn>lOd`$>m(KtR;A?GC#sm{4xUu}!ccjaKZX~k> zqW`#x{6Ct$F}kkr>pDqe+cq0Dw$a$OZ99!^Hc4aKw$U`Ulg75*)Bo>z&p7wX9pjFh z+_U#ubIm!|UTiE^PEaPgJ|e7c97nJ1|bqs1oKxU|CG&1@mj)G zvvrht`k*lA+Yl>kps(2dxyDq%ytF%vRByhS6x+ke@&jo&XOB9BiBAEGsmkoPW)rd^ zEgTFkj5_50cZFfKgZze&LQQ97O~X-cSZQqvJ<{J8&APNN=$>V@z&dp3s5>n5{njfql9k%iJ0ev~=k^wKf>a`CA+p zK*N#J|EVJ~&eh=UMtOd_1yVt=hwtZbt80 z;581E0(fn@fkyFz#Q&}%CJ8K%e1mV1lj)gLcQh++FIWv8ufgY?cZX)u<5~{wZ((m! zru5`e#C&YAtnvf{{dDF`rbdVHsy|L#SblF45mRt=cB(3>X0GO&uQ(~4PZH)zX>MG^ zj@ZB~GCB7II!r=Hpru*t9dC8ZEL3YH69&l^tO)Kj8tOcyHDq{=|L}wQ1j%8y4>K3y z2?Ei)?ve-j%gAM`=J%{if@L#qcpMI?Q;h5^orI(8?;y)qlbtaHXI(*Kw`%@ygw!{Z zWoXrnY2gZks;a{Keuh!w4q@S7Eu2U!*h{U*_(0-J148!4&{)hvp%`qfVyA;otIVGV z5(OTr7N46{kCph0CAD@6D}M!#bj9tj8i>uZ(g510cGT7u6pDwwWltON&!@IMNp53G zM`bu>QwlP-iU4E=N+m{a%*SG*`D)O1*t4=Q^Rzy;5mz<4I}D6vJqSi0C{tNx3=3sB z*bt<*>}2P|JKv4`0NY(ASRy^iRf-X1zY)4dzb*_m>=n$y^4j*!m=Jr6>wkMH0d)l| zzu&E(5{q?FG119j8?-;O|E}lmUvMD4gJx__Z_E(*{xYC)>H+z>2$fpuW07na zm0K#Zwq055CAkWcIGq`DAPMB4it}I}h2V5aR3;90id^^{?%2vyrbg!@l59VNMeN*s z(y@ZegOjg`GT%)D#ulBb30lPmQm(Qi8@jfxbG}Rov`k`d;$s`j*~!yU7h%o%5rPj0I*mB6N>H|&&6TYX z?sOjMEtL8kCg zGr_&j)5S`tVb52vm4}aS>5e z<=@;K1$J+n*Wxd-{o}v?E_}qlC_5ky%d(T%sZ*1dD{m*}tk{h26-`G7ZY)>aM!-E2ZP!%3zf5VQ!<`Y}&wIlb#celr0phDPY2%(}t1jbjo znE37ym`!u}(nCB)EbqzeA5k({dm(yq!AJ)Gg<9geil&trCN$5d`JG{F>-OU46_k$l zV#dDE1+PyidPR*xkywu^H7<>R#qC9=Mr^|B*TdpX!%pVUTNeOqR#(VVwyLY?7iiGl zO{AS6EF}$<`QKb-3aBq>by(n>zKQHNRmIwi?Ohn#A;7VW%qYgs4?K>Pl6BT{kFN?U zDYB~7gnBLxp2sm$!2e|Ym7|!7N zbvhT(S==R)jkcUU$jKLno+jvIF}>>p1R88{mJ6NVg&~4U7U$|iymFB^!R;6ZTWN3Q z_7>_ojYE`o1TEQfJIiSrJFQ)RHN@qASFDN)(4xqcMKK&BXS)7Zj*Pj5YBY3;jrYEv zThGJRSfVy3#c1zReFhj4Pe2CV^??j@o#dB;i@*lPM=vp=L0iR1J4^s&)vdDPB`F)p3;bDizG5$4@8z|zJiianU5$rB-D}7?ZcF`qJukDlqBG;I zecBYDt7@p+#y;Uo1O|5e&<(Y!U9L;dXnBsTrII8xaq<}UhW@mJ?s3gyODm*q0+D(d z7yzF(xhOs1E5s1I{x@iqok6h1_DhStHf6-Bw{+}W^jkfep@)@<`X?bXPUHFc3B9|z z>ayDDFqRS|pO{gpqjyl}^G9>Ksu2)EUR%tOXrG{_3>c5xk5DUZe;w9|CA{C!YTXad zZS_WWF>$HGeYnqC_-A+5&L%0gkVGuU5z6j->FMQnp3i&Wz?3SHGaocwsyi+DB+(#R zVX14_9MH}>ZM{hEe6RN<_;>vzL(v6UMrv$+_T0Y4=zN$~dr1A}4*m&Jbpf&$M#1cC z^OD!>_%@H}%sy-{M594Rk1;94w}zffOpQhg7S3c04OMut1uf0)e8DVvx+$db)f+?zqpcT} z)uRHdK%XECN|OQR0s|NEEeUAE?|~`a1Jd&qYj2HSA{zK%i#`tr72{=~L_ z6Lh(=DbIVb#V7VeNeShO+udIRpk%?Sl2+J)hQ zqnLy8rRKVh**TQ7CgVg=*d%ZER_i-(&;2#n3tcVgikk1g$s?H>@;)=%e&c`4a7oj_ z>8oR|bo?sMR5WmJ=(T9{yh#zgW0v&D~y*13kPCWY;egth$^1A*MB0)pKtUdA8+jE8` z!yS?giPcEsDuD-1TKfqOOni5!T0^VzP;QF4l-AZ@^7@2D`CqNTEddMs z(tu1PXTtS@kdj~S^P~$S5hq*1#FNAMT_9$9mDRj=`Azgp&3KaQ`aD^+@#Zot_4dwx zrk@48*p~Y>4#>z0r*s1sBMg)g%+C>uxw&a}Bg8P^!mDs5nufDz-=9y4Ft8^fqba}S z3k{kulj0x@Qmi_Vk0fNK$vDZO9uFuP};)VFeXJSLpc3TA!aE zLPz@%FPua*8ta8*Z(mJCF+Iu*0h7(a6^tf9d0#>P;b5?NC7RP|fWOq$P|$#CKx7sy zX$T+YEw6C6!Epa}bjq@*%E|Nku_o0tu%7T`i#ZGCYi00?KKIa1tMwOL;HAON< z-?i~hwxuBhGRi)=)$4+o2Q)1#Ud7LBCKgMJM|*8`-~w5zFNEAazLhqHZ~X};$8Zxz>6WR0kDQ(^MwxnEx=SHT5Q-FlCsdlD*u zuAOt{^0Q)>h?^p&V))t)qm|~}47It6&WyBf)r1NS9)EE4Zee%*=l8NLdGa*L&`9p( zZi2bm-mSY?Ya+gxU6&2yHS_wy$UX&&s|oD{yZWQG_DT02Yt4j&U=~n)Wc8%1mp|eU z)pQVzFd&dgfj?ZJB5+{fa}y;tf8dA8PEr&wA!v6t75MuzaVnijio2D{ur4lC z9BfQ!cAbf|QtB2aY~9GATOrj`MTr zhW5-fhBvY(Xu(Rrf*}brSzx6i&c6I8iN7#n*)vTcR$*fDN)Mr#gmgA0y?DX*iSP0r z!LT*9m8Pzqc%R(H=;pGL10Fx3dnaAeTP;7BPIN)XwS0V^kA3VUxht`2ek@|zP*`FuTCZ{swJ6Jo+ej@D8Q-9ou_{CWTCwNtp+)x(0R8_s{E(LJ&4Efs93AgPaJh_xu#Ht3@XBSi?@<#(4=>ky zBhJ%YM_0?nabnfliUpadC-^>ACptQ}Ye>u5f7Y+lXNjG5V945bf;P>qb9wpFjy_#j z{C&+ZDk80}p$ER!4!;tErmwiGDG1(NqqbT zaTjsSk8e=dmWVQ#Wcfm(Ff>1cScLSExyY643Lv?(aN0J&$ma5jWhYo(gZUys%VE87 zyL3J;5Hq`ks&ibg##6$;G!<8L_IArsRDJ3i61dfo{Fa=cKiK!Sr=p5U36#GkU(97y-gVW1M{|l;Yo|LgUFKZR z7)aVo;6=WLS&$mc?;?z0w0O(=P(&C|K}D5jo45}=Py>S8IGWR5*$XD};RKKIZ>aJ) zk!Lp~*c9k3M13ZLPVjw>^|=oCe7Md++?)9h*V?LvwjoKF_Ti!xe%k-XcA&j5nxgY= z5_deZ*ZG=%;d%U4Z|IDm$|gr!v3B($+^PeLu1e8bGsC_pt7~ON3x`R+eLEviQdd_u zBP{sJt-S%tudO_NQ^hu!n>b}Zoi*vGT+fV0LFi-dtie8Jz~u0-V!n6#Tv|~PrJ+w< zc=h<&eRxaZjm<-w;#e?;&BqcF)F~Q0EK(r)@ESgcvHhZrS?6RcHsVMg0S0Hbe_f+L z+4pB8=iyno-t$AA>Ke$2K)o{*x`CiF-{I)>Ex|u-4E`bX!I+f+O)q`=8Qj`T(fco z7*<8{7e+mk{vb_Ur^VzDBQek&)m_q-IzvD`Zj|+2a5Grsa)f)Hcbsk?q|`Q0S`F)c z!;|WG6TSKHa-8WC2%sjW7&Od653^MQ)r6bL`#7Lb5qJXKVlwdFkTvu zAa&s&{n{CfRATE%c}44Kb;oj}B^qPb9jblLJNv@I!qfXlZN^a-a1!yehbhgLUD?h& z7g^g?*hqtwghz)E@WhX@oe?Q0DCU=zBq~Kz4R4#dn=vgXCMjXUHe|fC@b^XvnO&7A z8;XyZ%9%pu(eczK9zT9BUxEk2em>3&b$*V;BJN2lBB%2(Cym%;%X=ApvN#T~;KTC_ z^%a#w7f+$}9v~F z9u>q6_H`QGxWPaMQ>CeQmsCR;3}HIGXz#unq{X*6OiJ@%U>Ys2k6>Tj9_xB@(d+FO zDE3(d7%)9eSoW*QBY%>DKC+%>nJQQ`PA}*0d(*2oCtDf)G0{1xic+qku*YYF;yDNlMV8FK?SW% zVQ2UOwLTMKJEy+Djb8)lg{*PKJ5}~%u}JcQW@45VUqSvWbME>d*~jTTNcFvLqkE{sbK1=32l=}<+)cJudD<@#uB-fn!t*)pwg5ZDw*pL=Bx4=@m zhB67Nuh(CNei3uu69Ki|Un^?ZNxr^1VAtq|%G^*4{&U_$c%iK|E+T;Iz5E3F%`@oj zBKT)#S6i%te~5%)Z@dZBK{l7kmIq>rdym+AR1{AIT_)evs8Q>SMtbsEiz}q*lM_#8 z7oyJW7Y$=CQqLAW$zeu0k#9)TAsZ|#QHnF0g2xOqO0Re3)F0Gja(tjw2!a zo1EN#yPY`#UM1Dlu|?n0ZWgue>ugq7PEJmsAq&>e+(cAWv*pZ}jl~NRCcbvSOC@S_ zdNBV|FgcV#hfql=H3}{dqOWM>6I#z9UTFH7`jrvTFVxVm%uPJ}P|-$;oOc}uGML%2 z3_W3%D_>fR`mQcU#MWQ0oI3f>J5a%~vvLQMdIWN2+akVbnfpei$*ZMY-xpiCsWU+s2lJ~i+c(Rk?x`sR8B0t>_uCWqR) zhbHbn-$UKgF!nClfpLC|R-4*tlOa^mCJ#^Wuq*^7lxyJ)*eGJ41?2UH?q5DVoyoql ztL)wlV&+$3evyzJ%dcCN6{)}irb;l87f@U2Pri6dAb$&PIUd;FzvhEV0n@^KN~5yq z+osBDigv{+UwxzBSo6_<205ku$y?tErXOAJKWil1hz--^6_2lGvv(uO>4yqKB|pUM zjIJc?QPa^z9E=k85veQij+AqLpe0(FZ#t&02g75v-JhZL&`B2w%VXWN?Qd@D;twg* z%gqv%ApdFB)4KHinmu&On~j>*b;dsg_sp$JO;tl1Y_DNwux`~j#1ddt(oR>aA(41a z)+a}!h;Dq(ki5TV73kYTfUZ5gE$@AzrzC3UP|WZD0EGsLtVDHyu>9&itFj(iG8WcH zijs>XF&^%5W~oM=#Q9e-r|#;!T3kAMAf4MKw+G$4&u?Bbo6b#?Iw7TspIwbdbDOiV z80)`yjxX(F4<4W(xnuw6H#K2zOW26lO&z&>?p7?5(O;CNHy-DAN7ns(h-cTj135l1 zF<^Iha(eoFU*j+9>&v&K>rOza>|xe#z@(s|A!%qxBJh4Jzfxxmb=i4~Skrj}+u?Rj ziVW?tUyw~>4O06Fh^o|Pa`@}S5@t)r1Io}&!_OAj;_~O+c z-+S_d8tvse$MQ@a=Li(it4%*7iY1ys2K#LS;LHN%DyE_@>vhFcHPzPp???7Y2>OKq zUTVFo^+$O#^*K*afT;)M3dcM2)`gX5RKk9PIT}Y9$n0XnK$q_!wK%UMfj1_9kokAZ zBlA5tt8+AOyzR3xErBk@KP;!Yc0wAe(W@sh1dVd|!{K3A7fZ9Qi38Go8|tW)_C?17 zstJBbAAq!jGHhm51yaEJ?Rs?1bIJwEgnw(n1t1P?#urPEQi)+TMh=F2bf@;BN_|h1 zS^WI0a$AZ%xv7%;wOvk`VyfeQ2EP!#6T(*6nv+FFoy&OlSnPH0tugW+-pN{Cut7yO&S*D8FvhQ2%a?_8VdNRRMYKm``Eof z%iz~_QN_F#{LcJx>iWpJ0+25Mp7X(#=(p{`gtv?KHbAI~=_59Z7sY2s1N>7cToD8_ zd;@1Yf%fCArxU2$XWz~+Ijtix4Vnea*e&`p7oepaSHroZn4LPc^_jyR`eZb;VW+2^ z1yv1oLz2ww!{=K?T5L_lEb(&D*~Af0W6G|heGXfeOAwcI*7jb_t+4$kJ;Zw)&^l_K zYZeiI=gg|Bmf8iD^vrsl*iuf(_Z>*YECdn5E|NhC^ZS~7ZtjCHk@H~tea>8; zmkl>G(ci!Tiq$Y~6|9K|F8N3Z3`l+c%|$A=T_#Ywsipb~6qIY-YpRH%oTmTfJI!Gz zQhB>YFo`1)5xz`T9tjD#?+$Q0Pp(sHz=n(pO!W-Ubq*nU-h!cPaUqA9IlKE zO_C;h#D?gt?N6r#Lj6dbxi%L=ZVeT{76j{=^E68h0D)LIX6M|YKEK|@9-vbR{{-bu zC(PVVg<&gm<8j1V&J{Bo z4MP8!o8t-kxR}i1h*Q_|4AK9%Nki#+s;a75_kG*|ss!hwpYDn2>C1b5g@uI<2Px`K zAJ0d(E9SY^^UCtq3+nn}RnQJ?I*rZEH|H%|;t1GM z3B$wU?Dm_Jt4-FL?JhJx5X{dPw#EuSqyt%<0@&>RE-^8BZO!3@G=d=nIP;_&uPX`r zCN${LZ{Iwj!A*cfN@$PVFcy$sYN!eq=(~3#LkXj*%A5r+naJKRr`QTKPc1LI0rHuD?fdWplL{{JwNFkppw9s2jO? z|1e^alF3RQi|NT8SSg7)R}LAG@WUfY@#?2CUzTzB!#P#t>z`;cM+?QC9FhUH*c$xS z!r42TE#izD0LyzPhGVO^ng}jMe!Ds+nJ$nJo0tHK%wfv8x7nT2#la^#=e_mI&2fT? zTBM8hA?lGNGlo2uEh@-gKg3hxCE&rBSR>S&>20%uhWqpD{)PAt+SSLda_r)L$0^IB z+q*gWFqm5H)6R9({Q@SQoq%&^^%J}eW`A$d22f=);Fq>y5y=>za|Igm?I*tNN2df_+08-9c?C7jV9)t^JQUm~% zDCKh|v$>qp`MlZphGWQRXkaRu{7s|CBx3gu()17I{a?@+JFkQ_#5d2~Zh>M(Sx0A* z?{R$qfKJ}JxdS`foww5i7T@Y^R_aT^0=6zM>puN~lBuw`_@TWjIT<}x;KSqJ%dY*H z5*H8eUn-qQV?1h@;WvJLI9E|s4cX9XDJakE+wDSPJnC3Dczb<-09-g-TjsTNk&$y4 zc}-IiQkrlbQCX$cu8KOVGR{$PncP^mast53uOA*?i3~rE4NqEMY4k0UV8ugqVX=fk znJI((oC^{~Ocmu}VYs{$n_L!z375h|v(F+~0o``kw?n~z84np8ILI_z1{EPDC-#qj z2f#LrV4#|_)mxb2s5Sf$Laoz|As@_O$|6_VWk~mCv0MuipuVk9UsNVColGYVn58yk zw|qT9vM74ylkH%_6%)rOc9=Sla9jydmXx}91Q^Ds!M#RN5GSNGvYB$2&AUHhDh@TNQxxWXW(+#(D3-qwc8*i1gn4(+Too zv`!42&Vo7yl)?3W&Wi!VZwRSBl1dVN7Hv-SHF1vxkCFN+Dmd+&!{sBR$X-_XK9DP# z)rr1=_8!Ck{)1}_o+s2FkIi*G(B)Ud4y&k!EQ%sxWFyp6H7v3+u9fY&xtxOME2^rZ z=iHQs`WtN2wEGWOBB3@hp~; z&00s=}gG} zXW%z>UC<-hb+_TA5v!^vnVRYM4^okC|&hF(%4 zNnr-)_K3fI5aFc~0*$sw&|h48qB74r#QCAdA$FcGi6PgeO!eJ#OLPD*tTqlOG!zMOqJzR+iZ3J ztf+2}-1_`@Tz42i(4e1fu!_vT`dbiJ@AG_TG%G~OP!GR=&1z022uVsQ(E(<+n4w2aV1fqUgC&ldPvk=8TbhYCi(#( zLpRJ$H7etW@B8xKV*muGnkFX2cZk^X$qT z0wEPmfYJ3nV3W#}RrOALeHkN29f@5~3MB`^6u!#Ynz>ke;}*v_df0^!mJM>Xk!rQ7 zqX@>SNPKX%q9HND9_CWD8Pbypib1~ z1lOCM6TVzklYcp& zd{U#I`OB~BY01fhDe8J$c{iV%wOUo{UZ+*-u1mU#AyIB7nx^N&R@0xyr*HQ}QIdEK)FO%MpZ@z`M&7oGeSBpHWsOL=aVILLeS*h<_Z*yBPW zkq8K_crWe@7$CvKM#$cuWUgHP$??MXhm=|sMsPSAC=8VI)t8#8*J%r3O%U)95hXHF zwA3E&B;!_Vp)T70-!mdn2?Frl+0tPEkA> z8wImBOqe9~tL``imQHWJSQNL+Lypgl6p&&Y!UM()nBo)v+-4gqqCf8-`H$9(AnJ~p zx<`wX!C`&f2kKZeU>ovz;Q&s(w%0!UHk+L_n`Ir=((~?HMMW89hM#iiVnvafp&&t`qvKRfD5y7E|uW9xnuI{nQDXrgBChf&}}e zlpQDW32vKIAA7>wB`BbYTf{X-gob%}zpO3m*zW5{7T;{yqm)|VCc2jB`zcM%dIk|2 zuxF8quZ*ls$>6yG5nBoNH%+Po*CTL1F%SpT*vQWtm*}mI3(nibg z3pmT~N9@U+U(fJ0$Q#Isvm2$Idj7`C_fjVN#V>~q)MmCerdTE=SPLAD!g;=ne@jy+ z>MLuTS{)@@ivFk4ITtz%HiOVVH~+|NAGHA#g6&AUYGN|7y@1Q4S&RJ4EgSLSzt3%cf45mxg9H# z!yBl~xmQdSG`kMw>!$yuRcM4`+W55d&nYht&tE3#cEK=Qg~+V-Z|Nx}P*o)(Jnhc; zA_gE4EWNcsB&=vkE=z}lkEx)rJYwhP7zqj8ZcA$hdB#;?W#_ar6UjgVHYPTIg|!RT zHYtVp@|dvGpvqEuElrutWfQxX1$@9?ZCq*aId^z>J1C}28jS}^o|O?@As3Nx@Q^mI z^w_Vi71x@d4~h7*Jk+hSz*&;lmAm@hTS)c#yz1A<$0K#?>$p(OTKq2YQ87{75f+jd zb}ukGN+~D;XAV}Q;}>ik2QXZk_aAEe%IOUzz8AREd5Xt38|*678;^exv#ZyVrI5sW z#uY&&e|`l6{cL*T)<_KXx}-z~a)c4PQ|_3=3_UCG1!H+-b@Dw+4UkLu^I3|TRz<9f zvXW7{ayjx>!fpGR03RQ0T>V^dPd=!!-6fjkOQfw1A%M$0nnQ9=X%*DgLYIj8t@w@X zom~(?jovX&fQX1cj$hXkoy)L^w&2;8mlpsB6idWsid6rWKvm1;?!%h>5wLlN5B~gs zRaGsksMsU=e1bv}cw>r*Nx+FV900Y` ze)kn5m+zMmQc0B8ClxhLKs|p0Ko*zIl8aJW^t9%y5uP5P_~v;!Z))JWFHCsyA?eoD z6ep%;ef-PIGG`p;U=_=9QB5F(3UB_#L&<|0euF7=wk4Y zUxJ8Tph3<9d-ACz6VXxDE6P`|B~ne%#e`CuX1yZwfABG)!;(aj*3*+su=E+!?#WZ5 z|6@XVH(mK&MaVUJ+A@nVFY_P*q{~9g>9?F(PI=)KVZ&kJ5=X~t!{7ilK)ZZff&^Re z*sUi)l+%(PUDf&=N*6eK@9i-n1+aHw`Z;}&`*|+N03R``wD_$18?{lnra|DEVLYvY z8k>uL+jL*!Q)N1*syb1NWjt6O5+w6n{5;=ft*S#;hWYU=e*X%lC097ismk}BI_itoNn|%k)rwRR!{(s5! zw5p{)6#@)Yj&le6YuB9;J?4bp%$o!m8(T`pWp~y;w*~-ofHEDQH5~!mq+3sKygg)dtpp6)M|L~9nAe3Z^yYXV%HZFp1Je#0i z&x3%9e&pzO=ickugZJs(@6FF&CE=HMlaT$>J4=eHoH(L9;XHo{9bz+XxrQmdnVo~^ zpp$oYgk@60a&rOy+gpWA=+7o5=H{}Ecoq^UadQjfi*{e$$b2Q;(_MkM>g|vvcE`Sz zz2}u831(9xNFyTIX~c?Pwcr} z9+_3ZQ&Z&c5qnLv6>5OLE+4mFo9MUzCT-`5*`#gn55StcsMFT%vuhcAcL#|+PhS$P zHPVqH;iJY7H{hey2;KwZpL>)T1_VVo3+3g~&Shv^zh};Rh#kEANcNKQ%{MF7zY?yt z#~!)a6wfX-)C4pvMzsvZ@l~0VC?Z3^N4S9({Myq{{X!DtTE*9GM@;@TU3?Czf_o;y zw{=6v?aXTa|8vWB_z7UWC-55rhjSl@V!1$j`py(DwalOHoDG|w@!&r^G zo9|Bjr)!*LY^pdLDCmk;4R>m zAUF8V{A=7ia+4xV(3z0tRBLY(63ej*m*0mE%%< z`WWEMygk~;6bEy_PM;%+5{SSBl!rEffLmo=UjmLkW>YF-!kj>6K9qoX`C-j9f3yXa zs1!Jf=z;aATgpOOA8p++-P4}EwM^I`>C1lMQM`WDqjOad5J6&6>c_OD5s#bRe{F0Q zY$WbmYQ%#;a_738U)IC@5A>_HTB1huP$AdL9wP^1oORdY{$#r4<5j z1du8`feiD{nld^)eK9v5R1J`ZOIs;UuN&X{@z3xwd7r+_#*~svow!qO9lHRYOABkB zJN$w*ZFB%B0-2>_LrzHv)zZ?^#LVnp0=wE7z+p9mN28Q6SZ%a4F*P01(boqLunqld zdaSFcs0nn*SJizxxp^KzkI&6QZZnW4@TsRDCF|M3&Vn(Qhwz>m`H^4x?VFd!&9m#< z_8V5)2T~N!3sbDmkLFv{HZ%f=XpvsNsPL#|0{n=^E!|hOOa866D{~o&sWxWdA|?TN z4p3zp>NBx36J@K*0UfhgY)^5as7j6;FQu!?z5m|U(3kJ!1IYzdBtD)$Hhe940#gyV zB8+suGIK}`f>)a6p*$%BR}FC&pxvE%Y(eni3GO>U+%-3;QV{@D}utm!Eu5BJz3W{p6Kc7+UxV z9i$O6pn4A>4Axl)GIeK`&lj-hoz5Bk*PhbuI0yqmXdiE{mMpg38I?bZW1bzjLDH)Pe@8jpExQBx|?VoY{W%rw09Qn zG56@lYJw6=DfLJYa{rVI>LZqw71>kptF6Mhoh+ z(8Rgt$~boWm(k%vspmj2Z9`+e@Z`M2koUtF?~EH0QGB0%il_`Eqy1#v zy@S?2mto7TLYpr;1?K15jGF050?@ZS5!~(R5n0)iZOmkFA_%}Fw3|w1Nac7O#mSDa zVu$SJ%k5ND*g4p)PVIZPADXt5cAOrx<8GVp&N;;0+-_-+f4u(z1HNIPzD72muDm=Z z+SVCy%0B-;sw1Hvg$m?sb#8Dmzdd}UN{y}r(Ds0k-fhg1@dTj2Nr2WE01&_kmcCEl zlD_{GKx1N~oKaCw7&e8b87?j?>|De9k!u(m8%qeDU3&n{gLi3V$|W~|G1C#)wZoIY z@nXaQ>VrrzbZh?Xphv#)4ERYylG8zB#!Mo$hPU+0h!ApT!t$vb8yoN55eWJRt&9~^ zEo@Gnmo<#mXRRk%0szL8u1i%ES?YRFBbjKLgs!M5Tbjwr?)d++LZ=GH4!t!Qd-)o6gxM@vO+_9>z+kx zoQx1#VZZbzQt!8Kot-~G>Ckk;v(zL3d$Um_&nd^!)#Ue6sIH%ZyAR;T-LkV*h-mh_ zYZC+Dn5t?_g)VBrjmaG^??0zyCQSU?2ubrwX`|>So(3X^eAJbt^2cPFr{sV;bs<*l zL|YAd^{TF;UICsGVfE~H(BDQJp zPm7~bF2?`CcOuZ%)|TyaGd7vY78M;GU3>Gqx~f%PUJl5!(SIM^|EX+<`~yn5x-sh%E+_9Gqw0>c8M z)5mBN_1=?96Y;}m&T)_@ADR*2tH(CnlLsq2Y3T*l^O(c=^;HLv#U3<67v6dk9H{)8 zJwu7!6)BefJEnbSOVtPs`fR*u3Xq1UaxY(K&Dj5NQ>NX~$zM3~A=LQAoSpFcgDVo- zS^auI!pM})PWDj`uCe|5h5mOrsC0KlQQ6?iQ8O{kwD2xcEbM2cY6?Jvh@Nj;G6HR6 zw^$`clCgRa$gniLpC{rE=o~=p*<Mv(_1US=jV}FKE{pJ8A-jDn6Yd4mx72~Dk zdA&6JjYS`lk-5AS12o4Z-lV?Q%l?PS2U5tSL7*WqHlJ(56`EaB*YavM#;qTng2!m1BrNoC5RXqHUv`l*nt`d zuan!AQ^#>Qf;LRa4HF7W)^LLA=qlaJ7sCvqNSreQ*1YN;CRQ$J&FqYw&9EQu5$pup zf{n+KVA0b*@UVLA)AJwjFFV3k9O+!S{|5!=8@$=tRVw_vdStgG$e zvId#?<_nx%(2AEx774O_g94oC)_Kebbe9xTo25sVKX8UB{-2^bib4T$#$a1)p?-J$ z543FhZ8UFPny=KG((83{nx%Tz@&d$GrCt{x9^s}k>QCqJdH2_M0S~IY{O|kF`>zh` zPrw@n)%jIS(c|T~#1l})dCFniNu^M+^gKuaZ#4)pA0I)|7<$5xn|BaUq`ICla14Jl zKdqT17NkZ$!LH#zKSzVYQ$#oRL+r~#RmS&NY6MN&E)o0t%!-VRyfA%PENx?$rh<3h z1{pk>YtJ1UHJuT_yt;ms2ftRaeIa&rrCwVF3kH=(Du`+*P5AbqA`73MiNvm)`vW9b zVDLuuVErylUejR{?rlpTt=3uIc+&VLs>r+T=+{BrYrI%sA<;DX`?xac#Bzs^di6rb z)dh4ezJX-K2+$fBz$3Ym+5VpTd>Q-yn0gDKF1POe`wIdBB8`M}mvl-?cSv`4Bc0OS z-6bX6NVhadcc}={-MpLQ^ZU;`bDTMIlyS~|?|bjPu613XRmCoNlYYw|@w)NkMtv|i zMpwloD0sdTfwlcDlfU4l-FS}@s*YfsNs`*yQV;lB1J+dqrZge>L~nzQ#X~lYN)|<{ zYce3Qs3GRNnC#o}W8Uev@WhDF;83KPej_fSLU!KZM}HdU$1XlV&;t5yb$Q-iY? zy$w5|WfNxtCtt-p+UNW+nI41$hsqT+)$WZ&^+?YLT|h)Ry6SKpWFd{%e>;))v#7W? z@_eb(?$ep?llJJ_30(;(M*Jw$zHq8AbMw%bQ{qRdHKO8i!113j)>6y0dsPm-i zfzW|4g|KaAz;pQ~9C#5Wb`mYji=MHj;&9TpBe7wJRTQNX>)a^mV9&j?yn$ z+P6r*U}Blk9?s-LIi1$meY!$7C3&y=Xf6Nh#I5HcUi(+q!MV)#h-VOwBQ1u-Cgna5 z*v(2^ib5HSetiQ!teHz6rq6Dfc3&Q-EB+Kj61MccOK~?H^|%{uL2;UjL@-$efJof# zTN>IPx?Q4k)Vdg}(uekOTa=X>Y7CqrFL4!#eb!*a_}%$H5tZR{52V-77oz zdg$`@gS!dR697vk&MwCPUf05)(S|4fgx0xLXDuOyMj=I^;_9Q$$sz zz2vzKpM9PNzm|qWyLv#Kdpg9IVf8v0XsfZ|h!wnQs4(P`r2PCHDQXuvKzKg|@~M)t zvWSon6u5ZP#sE)B2n2#82`dP46=`W{GqV=cn3|fJz%;j)0s-f8^Vv9$MxCkbOk_RK z^@r)IegZGg%MD;yFrF<_p$_jEqRJTs^=&~o2XtP^ub=+JNZ+70B#t2vLsbZ{ae}sf z7{X@G*HFQ5ybv9BRwcQ=4y&tlFv|K(%Hj!sC_jdIk5ctz+-%#$m^`jP+jbl{%~_X_ zqK2aRm6TD!UHeb|@qdRksT)U%xa24VKSD{C%O{RbvIrMs!DL1*^BvBJC@2q^ME|oY z!tn{^SWYg=2jH)onQL`_Sgr7CbVC6#5Xb#Yua)dSCZ|CEiu5=PPW65&qbCbpI$62A zc;nB$N$H|wh!5gtg$D9;K4wqSPp=5VGWonPk&Plt(F7f|UZGg)_R_UBP2+`H8yxcl zu;wfgE$d1GZ!cF~{^ijJA1W!kFrJ@IvOEhc8Xwk`T7^Wd{xm7z|e6xnX z{CjFr`^LA|2oO(~4oMGJo8$S$=lC;zZtTHa0fO%F3ufC~L67KHHf%I_vN`pAv5aGM(bxBdpLy z^LF$$5c`cn9M(D4y#gk7$S5d+tSVcA=jK#9Zuh=czg1CDxjC=<68K^2MfRFhTEWzX zCt}ct@3p*tr2GRUJz)jwCv+5NO5nmZq@Yo_7)i;gF~2K{T{(A`<1x96oVUUVP$(J2 zKts$qHwH(Cw+qyKdyFP3H}i_w$l7(s7M1HG1q5SiCOUSM;d0AhITCx%p}BnDlV6c_ zC4Q@i+b{Vn-zcc~y4kxO5oGJe-tqI_IC4s-q@e$;2ujzc#=1b2hA7NLw|SlAH+)|^ zhODsA6VOmaC4Xsn$S$Hngf@EElc;>6yDb!qZZ<|LjG>cgy|7vvTs z_i+cq>~E)qxv#m!fdNbwIWg5>UKy=F@y4R&8wPWz?r(GB+k_QYYjFm>Dnwc(n0^V4 z!OZLw1e3_~S?^?5I^Egr_7^|1a&hIr7mWGw71%-h0g?V^b#TnXM-~6qcj6ExlnFs5 zm#?1P6ayUtDjc;jxw=CCD#j*gz+W@v71V`Bnryab=i z{_~U^U_(LbN8LTXxj3byriS)z=C-u3@+>SY;23P}TzI&HKCBxE-!0aep~w~2_1-h! z9jG9weoeZ*b_+%!8V3%%+qM{xPq;tJd5YxbXX4~cX+8WFk(fBH@6;2BFf%*r@LYyC z{gwd@Tqz9=jXow0Pi_gel5h4(pd4-KsA!u=C0wCSvsVH?4O@Y#zL& z$WXH$e2r+Cv5UQ1&Rkro{w7Li)*!c8Jj_-PYtY zTLUc~W^VS>hf;6*ZE^>uTiw%}*!^19 zmcK$Ev7eScl@Z-g-wUaH`I)>U!Eg1(-{Dw5JilLLd~9b^yMZ;I$ZP%gwc(JiuBX{6 zHJw^tZ-c$Jd~8hv$5?1EdzyI6)~k}HLj0f0zQ=`rE*r2nl7fm4<}O*E#dE^c^IzCI*@VpLy7+~9JTbDID zIvOhDtEHvYN8P2S=bZ!$XjwpYo1U2wVZvEX!>gC^q{i&o{q$pHMF#9RPY*}F7S`7L z>T6)S;|bi~`Kp+2qo#EZcLz;QU;_!^^O=_AJed+Fdj2oZVi7pWj_*9PCD*gMRe`G$ ze@@PUi!|JDbOKx~72t4T$Z1u}E#0b%^J|wC=IvN(Y6_HEuEt^MZ#IhWZ;G~`fJb6B8fxu7kyJBzZh{?>EU zw4~;>ufugB?36V*=)E=XwNd9icIG^PZ_M0nvjAvr{CZDd*4d1RNX**K&n#!r4F#qhjS-8l*F1)G?tje!uR9S ztbdCLpVfj_7DI$|w6mi@Rgm?Hd8zITUZzG`|2F=qunQd0OD6Yw%M%L=>YU`=oyM4w z1ZjQ?;veO@i48KeQ6CAFkF6PS&pSR*{Xv4MdATkyrwvMR|D!-|yNY!o%&~^9*vP$rL@TIZh@Wdf$N7Msjj;G{~_I zC&=?l+Sr^c+O&h+$hIkCC&xEC=l&1^N!5@Yfl$q11?>0q~8A zQ*AInud^$kDndqr5%M#jv7hC=p2oF*M52~}O~{+5o9cCuRw>o4iQrRP`3mc)bJ_He zdVW|g;u7?-tSA!`-)V5uV)v$M5j3#jb1jxf58+t?VXtMg_2@#PuL zJUOXQvXjKpxL3+a@#}m6EAQF1mtX=!Kut-yTaU~9wv*GkG_Q6E*LhK4^8_x=2tlrc zxUCtwq5gB(7!SfX(tdd1c!DW>hDJ%TxN~MnMe!32iWg?sk)~EoF9e=$F$kC1qKioG z+oeYv5@J_7={@c<9X20P%cPc14+1q;G`~cY=MGC5w+83?=c6CrlrGg^yGp+m@`Z>_ ziKUg@JzlS{R_ImXyRx{nJm^B9y)fj~FxEGbTamB@_TQjqW?L5< zn&JSoZJ)-rsJT21#M$0e@P8l)(w7iZVSk|@s_5Veedk|^vnVGo$a?wJ@^gfl#WXaW zlqqy3>uWIGSc?v1<I&tHrH-!`#+n zkiO2VU#{(P-JO;All-5=r9ulfh}1Tgb-rB8yY?O+C}|xTqVEdVwws6g3ucaqSZQH? z7Ev)UYEjK%q2b&!=N0~-JwqGZx5A|)-uJP!otxfvypCsK?nl@9+`Hnok?#X}U6^LX zR*s1ArM~kE*V|MiOBDuN(Vfl71lW%W=X7$UGh01C-1u2dnu=5+gxfMEoZAS?j+)<4 zl%3q3lzz-X`H`ndlW%fg$lN|}u2D#ob*4e+E9YKIaoL6=%J`k&KS@ers~QUe9xRp> zt=rGES+6r4+@#sKhu`7(lS@l@zh<*=8!z>Tj9CmgG9=~XO#4F7WODekZq9a`_G<>w zv9Xs0t-+1LK*$IbB#VoS0q#~0hUb5#fV!L9a=7H#3B-%k_UjjU9Ua+VuOW;X6n1uI zAH;V;qM^yE>%(T$T``ba!1|Xi$Ki3Yu3B~j2S#rh4g~nu@j1C8R+B22>$+d0LF+T& zpu&*Iz;I=PMa~?ADn$HS=Je6N(ibnukd-Kv0}UNB8X3zz*!M^7{4!R^YGALeVc#*i z9G`{p;C5~KkCm-{^F*MM!24gSGf{6}!noh{9z5&)iE52voP)1usv9x)vg|iyQqu); z_q|`bu#VEsjKW!I8R(?FSxDlv@DIp8x5Y0hseiXTe3&Efy`wItL8}T zp>REpB)9n4_MfV|PM{6u$8AfnS$!nd?uJ4W6r=y@eoe+w#mD#CIPlSsAVvIEUcTr&*^F#}94>%`$CcCZ^uC8= zQI#ziMcQy}-)qgwS8M-l9K%l~E(g}%&t3ifhs2t!d?9jADcWpP0h`&ZF9%7s*fF*` zF}|T+Q^^Y?#%GlAcfDDk{z|PB8sL1~?uCJvW#EtcX7V_;am6))~EJ@4Z|FD06R|zdBToB?bP@f6hSQ4^2iD_HjxlWC3E_FYF z>%yZQ^lB79<|0MUXUO;IPVdK$AE`i}ewHXfw>N?bv;6DVzwpGcLi+m)HK}9X840|Y zkvPnxqZfRbh(WOT?Cfz5{b6BYAgZ{1;%5Io>w9e^NNG@a+W9h;m4RDBpn*ORNUm0# zP^{+4HzOE3HsYlj4EAP9)#=|Pzteid9y$*4Wo80*8dXQdzrNu4*<0vZ`$G%nNxy^m6Zf4%j_*v`Iyzoj)kr9AHP3p#e+9j5@rDZ9I1&ZYY-&5^Z28|`9<4o>D`6`Skh#`n6i+=eP@p}Ju@kKg(YzCrWZX?CM zd(l2P#@NtgkuT-T)05-JX}(lzQqu7 zP{ITAl}2Z2x{hatp#by1Q3?$Y_it(X6G}u=vszCJifr$9IERxP69Wj=GC*CKBF__!>T^@hZ>K}k7S_GK~ zDi@#xIah9J^nBV=^cgv`4@@=>pepD`2!w3qOUlB_%7AVrB`xiK(vR&9dc53wB?Zk} z;dET!^-9Xk*^YyJySP0t*aO4BvKbr|h6PSk*| z)~o!fc1!)-vla5>S8%71c@m8ENxKdO!fxY_1H^YC1D|=K$ zuCR*lj7i*8(t|m!&Q!L({D;xW^!F)HjCVMFwfn~TqP*XHg;o4x{xU3xZ&hlujXu1y zqI;FAevKp7=z)Mfh`G6W*MZBnODm69 zmng04P15%E zc0&Rc;*k!$af#%ee5}w%Xts4V zPt+S&v%7K&SW|ke{w(DyuU<1W8^4Jh#@Ch>oXKLg@~uVZA>y$?=lzCrITHd~T2?-J zdEnxrea?vZcr#s{whOw8ph6)Sa4~JIA-h|CYlI%p&EBbi!P)xE8JCT^xHo!m_0rUh zY>G*Hav61a7%9wfRQlfR0Y%Zoi;b51wHwv5$}^G1>M(|>DuF-%4SktHME{6rx6`Fvg|DfNIt zW}({P1^D6$>gyAOgM*`G+<3~$w$5(UJG{8H8m%{h){Tq-0j~gu)pRs>-Og7+UY?4K zETF86R`As$9v~a{J@{PLnp36P^GZvNpb_2%N%5Ow1Aoi)BSdD4w za=#p}zn1_ZMu6VIjHX;CBtpCA34mH#_}J&mQDLfPb>gVt@ME!LF)UR;=*Yoavqm2ZlY$%6H{N82mI2$D+dc zSPahG+9z}J9M-oq%+b#qMT_Cf?qH5Fct-*47$ms39s|i|w)pjK|HrVpgLPGu|23hb zdOtvbV=}vQ^^RSI-J4OGfZxk4hGOSU1Z+hA2Qe`*^~uAlI}1xoL!do-UCgS{Yu1OJ zo;m_Urh0O7Lqig1a@7>%N_yo|e3Wsqt3@ zPCzLs!x;5xG3$~9MQ`wUc8+k$~->lS92@Ft` zm^4E!=LDG~$g_Eq`Vxw_Ry8F5#*cAz(&e8_H+-KR6RvwL#H!nNS)ez^4O52S9lCFZ*Ov@S-&(CuTk%THWyV~0O~W) zq56zjHeFhQ;oRuza1|2^tHxnltkHH=N=s`w)+8dJn>fe!k^A`<B9l7U?gL?w@yG0v(g^K-9{zKrC* z3mURG*rB`rzP`M9%;iJv1ec%?<7MFL*7n%_lIc9B!TWT7#(RI(gh_XTw8)fhHL6eL(Po zg@Or0-ueBw(pjP15)bOfGmtW1wOOk7u2ORc=WH)b@}Fg_YIS;02l$tlmqR5zxPGyM zg`k?Ix;3LqLr_Jbj1p@M*Rf%so^KP+UoDEOSGU?arZ^{h64n^bu|SSR^kcCMWZ4Ia zdK8Y!nya=xWF=wZvP_kFrVQk?N{x9o_0S zaQ~~lkOGBuAs~L>b>Cm9JD7st?+4QCpvAWXxKISAO7}pTuWUVhFUNDhX4`te0o<}# z)$UhiWv4%+8G#|b1q71655Kps?A_hnm584~YkLX(8JVmd*j-~|V<$-kr>?CcCy1NA&C5IyJ;YI+6W3hYYoS|D`TJDR<`veH z7ui1RA4U=lK)Sn#g@1$siP5C}S`urS;`fu}d3^<}A6N}sc-B;tom6m%To)-g`9hv!S80fZ(Ij!bZ+vijp3(KX` z%`ratB@uIej%wr#IUKdP?O{fWbY>TP~Z zB@i~T6ufH^Ft<4)8QD~!nz}uw2*DcSuSWFiMF=QOaiSp+bCy(y_OSk5>%UI)BkJkj ztMJ%}je)~=VYQ%%qqy)VRsav~Ib;Bm)IDFTI)?pWUtL;(kZ!-B!Ddg;v)2j}6EpDL zD>(2$oeVxFvf0?#53anSBxGe@1A+#K2PCdpb2tG>3iP<{LqIDGgNP_*$oK zOIh{IIKD-Wn#)d}TR6be*^PnPFp!nsQIuwUN2}k?3Jb~F zXxrkAS6x1)#$lTV6JFG_2`bZd&Hbg#x*Yc}OkJ-N(dX1pIKc1`rkJE%t$D^ge;%NX zY}$DQEHW(M#+Wh!YyR1Kp5?f&Po%QtH{LT2?U~*(p2f4+?#aoJ60x^u$^Ufkw6wI8 zU#W!&W830}=i6rNF-pw;=7a-dK8GhPCyP1y%iFT%zh4^Y*OdZ(3~orqlRxX<06UW# z`RD-%S)aUA%gPAR2q9tx%$Bfz)PP=&8q}8QmVG^u_B{CGsm&J`U^@)eUX(KiZFz9{ z(9@@)@(6Qd!V9{X5#s=7pu%b-d)`M>ERoOWHDUF$ZsryH){^M3P*BYdH!0S37JFyh z^J-hHHpY?Ccr&S7A9eBOYTSv-_f-_oL_QbxD5DP=E5z*+$Kt;PY@wZ_YGSQOw*Ar< zl76!X86+H;@VR7t1ZTQE zNa^NLBZ54-qM<*ecx-qlIU?o*USCwlnDs`z#tpsq2L4*}!^^&lyuc-67G{rg^MPoB z)^-0Um&k$f2W}-8KXWjKg3xY47jIoHQY?+uOn5OF*TB}GGy(iDN0)>)Z+t! zR})p4!Fnt)ox&71sjQ1f{^e-K0p)2?u~FF3iWzVmeEa5KF%~6Ec(1i3`%_N7*P2K> z) z;{z!~lvPZC34_4To)o(h5Js7s0`i5d|`Hu92K8>#5&x6klJQd}3lslTj4lRGg%Pco>a- z$0Te$3gPuxM@i$Scojf0a6&~_-9(tJj)>w53+Q-*!H7+IR@@8fYd5L+N*5b1OFnl4QyV~If457LJ$QN%#5(2uof@F zXrmZoNCD<*B=Z#9Nu2kYu3oI2S~B3Fhd^SAul`05hXDl4)zdgWG`tv%%SFftk*5X< zAw*Z_=RdE)ZX75gfhs@4DPp?Su4|Wy@uW}_`DGjO;*Ut2SMA8)J|s!3$LLRFw9lR%Hk z;pySZRp#ZNXli(Ehdp)EXj!6jpSu8-DxZdkI=hF|rp~np0kMJl_I2MMg_4EEC_b&; zU%sl7j+`1WLf3opeiBzr)a}P6sMbWf|9LOjcJ-tGemB^N=DWN|WYU-O5PfInl`{n1 z8}|Lmw{55jtB5i5!HkU-U&eJf)l}uT#lMp3kqHhTy9G~-^~LKiG5*>H-XT~gR!PD` zob&53mqHPq_=*rjA}ky7g5?-_m6HoL9T7}oM(z)Q^P%3DkCgMYp?1~GR}&@2g9;Ow z7LslB|)QK^#5o_8}ds`OeC>`O6762 z?SmIe8R`F9)j2LnmDL9-x3|u!?Z7LRY7`xYL!+j`{t0;o(0ZR)T;<@VUQ|S>&4B$? zwPLI6Yb9{3xmat(7ZS4W5XOW&Qw9?OslrQ6H9YF8+}q`&j;F)@GV@>GUUqEmTrn6( zJM8NkgA!a)(qK4|hMXK<{YAOUycZYC00b{;Ak{RCL5&C+l>p*ci@)MBa^iJ-+W-7) z$tnBnP1L5Klk8k9Y@lKoJ|E1Yb$eF9d^o<4Yd-q8pg{NlrtF>&Fk+aSN2!yCLJ##4 zM5d-leu(x~c(_@e&xj=$482(_#2i3b^jMyMm)a9E8!9cAh2b&-nH>3~XrpYDXtfUJ zCe6%zgR3bP7S3S3R8Djei9nma5`j#X2^e}2lW1TpxG0%$9er*^UlSewm{w|`rng=M-3 zdKv;&Q<*-bOLN0+L5KHQ&ot!3{gmWnbR;+)LN!c^A|~)}Eg-~p4KyypdAy2+x;LReh5{DI0EHz=e9=FR*FfW6dFs1;G@h zsP4R-jZuJsqKuZ_*?l>_btCT6w^DG%)Sn)hSGIB9?b^DzCcmji)EiG~6R0o0Xyyw) zm)ygb(^EH+Tl+=)W821Wmd5pC^*#}ZjW6sLYk4Fue@JF&X(~a$NO1arm}5~9%V{7! zdhK>F{n>gnEghO-J2Ctwsh~vgg^71Yn?h<)1N;)T!y|$$5D0{8AtKw%>md_F*P%_?-qV8S*Q@y;Sf?E9iwO_4E_85`NU7E!kr(KHk@f!lS2 zm=A*`5)is*+lOw~lWshaZQGx1+HcId-`V9$6fOY2+9!p@G?;c$?~L|Uvps!kYt%nm z&7ApzBR*ST${q0ElsP8}*G<15$Jx&i$}(rY;>F#B|4?tarF8yLFen-4qnjbT2At$Q zzl{99;}I7#q#jajEsERVyvgYZ968;v*!D{n#RpdhAY_dS>TV5PtJ2Q+A! zckh02cHX=Ork@eUPJ9prNp{B;WzJ91uYS&bfgbGVXSebGzO@|xjj^MX6QGTGzR$)$ z3@Rxt-3&nC-{{BIdo~LztEyfOt=JBSVpj6ntoU6XBvrYb>=dghDNWBAHQ2T;uBS2^ zA-i?@mOogCtIYOxz(PXbzgJXIX@}Mi#o>IP6mrBLpr_3oK$WdGlF#S@Mgq>=B?eud zeNgFrB7hb0+w6^RK8vBUKTO+3g>eHpqa|q-`2F(yEh0OG>&XWAfpO`UGHQcIbAM|6 z#<$GNQRFBwMBkTJ?MgnQN>Sf?C8#h_YBogr@{nk-YGo>-dP57U)h6hx*({iSEvq(C zBa>5ugzyc74nD}}1hmSF1r8X$j4w!$3L%3L_Ln__3gtMFhqYYF?_>(zFl7o&^+>19 z`?nQ2nZJT$G|h^wFabc@@$&kk%XjG~BN9n;V2oo2vEYrO4BKZ-+W^YY$cPO1Vp#!s zvbnjrn&mPu5C*_dxPIQTIqxYK$z|bPg3P%vrl_$7CAfh{=-vARDrMUmp(%|k8SCPJ z9z%|hC4F5T&UFAwOj~PEXM1&UkuJ+8`ovoOH$T_~ox!0YwJfIA+I%y)ulOGSR6OP22 zQ0y;#9jjL}2`ai$i}(381jc|IxK()IM0q6gJxZWJR7~cY**eNB4=|OL>vKD13mQJ2 zi}Oo_w6rw0vMQ*khyvRHa3q6x6NmcpeZvjL<0mPXz^4p9{>ZuRm+hVu$s1kqxAkaXXo<@g&!%JpPxSi)S5WGhdnie zt*+<9HoN5vsuy~V1@O538cuqy=LwdP;R1lY`P_;RIU_EEA#>QGF8JcFvz&bFlcz0~ zyjOL_ppWl=lo2E%{!E}c256qHXB}ceg!weK^ijXU3RXcD1R`;=``&eO2j}Q9XMqUi z>1jsB&0dCKx|WwW;;mpr0BC(}ixr=M$+wQHzzF^H_PpMuG-iyoZqpv zH?hb-a1u}L{S>{r;ZYz^IN4Y+{nlMrd!*_OZn=eMMVF+IpOl{^!A5mksJl%c8QG;RL#*g{0;1$etvIqMSY~$I)uo`gu#roeEC_V>?R}eWh z;{2w@($X-x%4UDi6&oHN29q;-4_wILKMZm;=`)3rO9D3qbvSjnKXo|4Z*y>k0it1i zLIN(o7uWNt3z&!a&NGU9<2e&!W4}s^v$tG3?+6$>?^*cu%$OQHuWSi@t~aAMri@t} zz;4vXX7rXCB$bATrJe(8&q@oxNCQ9Oz~2kxW>>yBChM8IePiS6yw5i@jqp z-h*HD4oD}3W68ovhlYkC@z@bVwkKJe-lIc59@gi)T8%-7;Vfy$CVCV_4k4Eedo%vt z840i#(g|AMUjM1np}#f6{(@C8!`X}wgb6K#tB4tEf>od>f-YLiasa5R{qo~EeUgK( zsn*am2*^ed4X?7jM8DW9su~wJ)mgXo>TOIu#jEHMf2dY~${3UIv4viCnQ>)+|6ctC zy6E>s+mBB#Q(vP&`w5^LS}8sVu|g|jHn`e|sdREK`a;MR?=W7;L)xImxa#Pb#U2*7 zk>#92{&h<>`$*nF$SKrOMe~GV6jYLajil58uwO~Ht=e{L<4Ab0sSh6ZnZMpuRLD!0DUvf$P z`&71p7|Ctd`LQo$1Cq`a3F(^HQDeHicLUuNR2q`f4b1eMasKxrfF@b~fR;H_8#(_MY} zT(lJO?o-TUwd1k~duX-L>}UwqTYF;9xMVv|ovPKW0K}4_!Lo4S&t!Q! zojjBYr3JTN=l~HxUjiF~OzsZ>xn{>&IJF1hM+rkn4zhc8yJABLDFY-t;-gqiQMUcJ#hI+M;Q;zr z?=O5XrtXa;wy(P>)~|-~RJh+D6=BZ>%zyO2@)fXl^$xzuLI#ZT%4o@WQM1HjTY2`X$L*tbY4PZNYzw; z1jvM?dKi_8tv9~`sFnDMN)9oc3r&a+>8Hw(5T1cV!oZqbeD;NyU~&X zk`TZ?%xc6Wo0nXPkoEdLrogMm^+Wy1RsEo0RRl~Yy* z1c%Q6ng$96?70uQ)QBJ%0Zd3rzy}8^k7p1Kpq}Icv^glLpC8Xf;al=J+m;eYYbp(83*hNAXRit6C8PG>1i-K+KpX`B*p9Flyi!boN0uL^Dhbk@` z51Rq<9nt!$KP-lau7jA@jKgOjIfBRhQWOHX3-Iz8@XA#`-_C{E69oxX+Nko8|tU`hbELa5D8jEMKp@kjf3qQ0*ndR0gZOD2abb&$)-mH4jzj@*Mc=xy3B%b;>WV5cV|x*kGoBy>aV z#2;p&v-gm1Xg1}yLc)q@B4{cI*e-l)s5u8VB+j4kwu*TaelpBwQ*tJ_W};Vb$>E3f}<4YZ)($hB)f#$@26*Zz_>bbe)~5u0dH{DERxJ2=Oo5ChxJoyhPNlgn%Tm)>8ed@432ziLRxSCXYY~J zvDnBcem-zd4pAF6;SI^VGC8=hyfXa_X7Ijux44X+(5F`aRulf0@H)MMLYB{m|4l>? z8ktyZQc@5#Az}NV&ThwqcsN9#P3#i=rN5(_WW%^Yz!de5g`X4)eAj4yQnsH+Fz#RY zlZ#bA>|0*2sWq`UTXKjM1nM0+9-z=vw^o`#b(#8;zhx6c)HlJZ5N-fVcp60{SEF_qk|OH~q+n*#Y5KuV2(H8YO; zfzibF4CcDOUE1AjaV<2%LTJ*KywH35rEqPyW9-c5OMQWHLx6T3uSR;wI#|T&;D!i3 zj_(uI81v%2B^>e)4OPj#-q-PEJ=j(wH~rqyG^G|1?$fmJ&@Qc6VDJ;c8&lsJRMC@A zD=0{QqX9hh%Q1Ojvty7hBfb3&n}7yP>pv5WZXoBXkG>Esm_9CPppYvk0e%IDN;-mZ zUOMwes;c_p?DzJL`&b!Bv8ZVp$U%wUll@-=4!(`Ne}@MD)l^NT!A$L*40Xyf`WpW| zYT$PtUp=NWhr+`D_ib#&c1}P0ionSiP9O5LVMeZX)1QWc`qIAO_Hy3y=D0OJdZTld zRbM?gpap}K+t!i8=nO-$I-}I?q}I)wLa)3+|7=Z6d&+hzIP~(NS}RJ1TEY~JuaQel z?gi9qB@B?9%5OWV_~J=Z<$5wdVs?JJ@=NP$%VX!df;K^GkPvYBef)?EP9)X8n|z)v zR>xIkduRsG@Nr46b72Kn=`21W6NQgxl4kyd4G7dH{IGNV;tz^Gz;>)=)6;=8s|2_i zd8v~+zh0&6R&KD|-tZ{%`Yr{NM^CEN)>MeAp&D2CLhE_37HNNm?N$geJaq?I0d#2< zJf-kC7~U$_d3R)^5UmTPk6Lr#RQo(&;d#VDoUkTP-raV`#=wLE@EyW%nRpOlAjZF} zUjw5ogE>(@pc0Q8KF{f4&;n&c%s3TajTRFReHa*hcXMVkO;h1~`q)I_Ra+K$U@}(U z44~nT;w(Le@v$O8tPE@OP1JN{z+F^Az%QOpz0XRGS)KNpd|@nd6kG(W$)nR!`)A@x zjfFr0kdjL9TT_F`TgMGH#lj8p1*dHD-iQD+}er@!+yVEETwrlXI<6O|JK0< z4Jn=j!GNeNAB?pmoP2n{5K8&NpE`G#xw3UtOVCh%asDlddhUp!nsTw7WrLnBluO(@rV=U);Y}L z$5|eKF&xfSuB)WXHIwiD`!h^jTe(=jFRZ??(V<|vsKM{7ZF4Z zZ$RmHKt_P#njeN6p1&2t@!X-^(?g z@tU)56TU!Dy*;mOw+Hy2OWhgjuv%)3_z3c=YqLSe{pJCRMyzFr{k~`ns%Rsg#`5NY z_=pwbq1qA#O-!12Qc*`q+antnkM7*H+s8+@&$y5)!#AmEtNo*G6FaOtbzS}au=Y@G zJD%e=*;cL!1b%T+^d#TJa5TR8821a(o1$yMZfiw}6-=4W@esU&@SfdMh>7(s#@^ZD z{qD#JPHCFxHG+rIb3HE7v*BL)>LsOR&GNeLxw6dk#cjg z{=h=TXmXQg*J;%)h_-S5%bow~9`>HHu1t3N*%q-6pmMV559|d~FNi~#D6}G!iPXGd zAjUICvAP|018buy+L)bd!mB&gCa+vHV;ACKCcS<^nXt+o9?+34c} zCXU}codybNP#pDbKVKm;wzCYhyV~lUoHPkDtSh*a!I-)t+Eo^{3rX$ASrifxSLPG1 zNT%}91X_>=l*|=|p7@~w-n^1zgp9|5TA>9SUX++q!|orff#Od4c%_!L*mt(LUi0$@ zdM=G#UX9=91)3v#?`Ny@RF6B8W0m;UVg#I%6WGV+Tk=Pq?!QNP^)h;ece>wW?hHCb zPQ2lEv<0LcrJo&0z53vP``PI5m-ag3_6FTz`3qtuL1`)r8OY0>e) zEP^D|jtH^c`!s$IqeILuVQ3ki7|x|K4k*%%Ca+Gn|33gBMS;@byKJ z+t0&;ku^It+5w{bnYU`r+PcNedY{}jugP=VZt-LIJfo!(V2589AQLcd?DiV*`g+B$ z$wW4rFzJ1w=A=P6IyiW)jOXhGt~C{bNV#>#FN9j|o=3LVz=AY2V<$bm`15r91CJt> zL0X}$?cwg!F8s7$UjeLN+9G=60qbPWR@Z)gK-ZOh< z)><=r_10DQ?PodHy_ru{7pC`VYWBKlgd@Cxm{hh)a?h5u2cDp%0k@3G&v70+`qjow zSxj3nSh5458H6#ieSZ*qUu~F+dA#z|Y5vfK4nESDWviPeSrd;7t4Ev2ZMpWW>FJ3( z6fMih*;(P}`Cf(I>S{54SZ$L@lDu5#hP%S3uG<=Lzh=!g%zD071v4lT)(@3G*77g> z6z2!I{2=m4E}7$bhs>z2TUs!>Da#Y8l7qF<^Vhr79gAf1eGuvYODzib{|tt5E9~>j_uDs-lZ+pN`+!j62FRtHS2p z(goh_Zt~dadZ=u{&XA(VZE`p!^w1amu|*YFvEM8Vpfp7&yFW;)X(sNq0TA+!smt`( zyiA4xvuhzKHIgX4BRaLi+iR#8OHG+8SyZZ1+;0p8$)ch<4{UXshtCWOI4BHeK}!uV z97xpg(`?z*{0^RR={FdSD>72PS%prgIv#3QNoF2Rv!~M?&P%?*oaeAJD&YU#?=Ro zZTHZSKv{UFmyURDC%j7z-$>P9BjKYaK|xKj$IJel?^PY)aP;0gjzk@}8&esDNWQrc zhT=j_qUN0>B+m>hQ)fi|&&B9T7(ognI1-&cE)2bXnO?J7uI03NH0Pdcf#HuE$zyh# zk4%*DZi4#QzuJ2SxfE?0w%+Q@n!39a&VEz3OBoCHheRqvjemu%Cyf9x4~1PqjpKqW zlR8OFyx3d1 zC0bAC1Q!%Z3OdM#CYJ;K=8fsPbzi?N-ix72n-i|z?(3npT`B>$@OrKw_?eh+Ni!9Y zLVnt=^dUTN-rb8XT(4fjTAiq>gFY=);R;{LeI;HU;G7!P_<~x_6F>D~n@9*`M1vQV zX>{_Pm;Da!Ma2wuS0}3@GmW;=@=3FqAeD+qy%BQS`04r`Bj^uQ&c8#WY@!m{_hd+! zA5zfDHDDQ2)&|(v(|Y^APUF^Mdc8IR zrv3DkO;=Z!0!kE7OpsK6W@DG@uX~#h&L?Q!ghprsW)1;OuqTJUPcDVb@}I|0x=iu? zUTefIQTVGJVCt|=qhQ#@wPPPSe658yhc*W!5qTco1w|97ZbFjr<299ED<~Q zf78O3u+*G1;k$)Q+J#dmNmA;Q!MjZNu;#;bqfcy4&G|#yC zxFa(|NJRVP&eiZs;!9zANJ45r3FcQ!kX7GKXhlXF4Rm||u4n&rk^(fat9?=-w#Pp` zojunW_S|*uZGC_z6772LwyTS@9t57aM?^d<0o)?Req1}Ylb zE0=oSINK5hjBZJI9neq?wEfprGKG@}INNP2v_Ppdz16+}>^bW0paX_{ut`i#{O2ZD z=GdHMmQk@GgB-(02gu)lAHUy@F1h6I;PqBZE@kL1(N4?On$Y8NAI7X^rNU+cUV9cb z@e_ts;CH;-f=C8LDkWhL(#308s&X6C`9qzC)_g@oe2wj3Jx%}HTJIt(5NOb>kN@#n zAAFilX0)i}#knV7BdT>!2tCS}z<)8Pnewou`EYob&Od~kqhAhTwo>uOpcKCj#^ETdu+5D=7^ zt2zksaaRH)tP3L3&yOGw9}sUg3JdBlYDXB|Q8kUgwE^0A^>X+n3L==R%QYk$fm5(( z(X(T3Q*KW;6rPUaFI$dCgIb>q-N_o_Z?8K_-J3O0_7D=3biw^Ws zX-2AxS?W$Xp<3R|!^GULYx5Zc2(>Ma9vIrZF81fc>#ljR1A>K8RZEpO?o8gW_%vGd z4mKG-@XS2jqhg0P6h?;a44tB42i!&@xA0SkIoUPeY1`T9yp%-lhWBky#mgcGLbsk6 zm8Kr!at;_Z8*6n9%q<(C|INfT)8bwsOe#@&E+?sPKR;bdMD^^c_A>z zjkyQImdt!HmMvsI1LqrBEWY)m;fBWihKD&y#OZi0sKy7SBUgT{;YQS;Y1s4J4J`8T zE|f&VX}K-i&(=Gn9Kq&Yr7d)pWbtaiKJ^r zS0`5VN_Dgim{mUuPQ8YR0`B)3pt;Jj;8~GB;i_h4Z~sa-!UaR_o4!9zj0uZ3Q?vSR zss8aguQg%7*a0)MjLLqD8g<-WH)n~6;1CuT%T>^r6tKl=VV=U#nEuDdyYma0>wXBNIfaG6dwb@hiM<%;*mSJ9-GLuEon{#Z$nsgQPy7SJ8$bNKZ=}+ zZ7mN~SBN{S5koL>X81~If=u5}PjJL}Dtm#*GpdGC+NE_<|B?%3i*0k}v>!<~&yC>~ zukFnP3rsqxFa)*c)z#}-8U~nN)`CQ!6D|D^mwLa)wTOa5qa%>MxefSu) z$tUt@bJ{iaCtj6KR%HVhk9@8cP4XCJ{x43|CJjUiHpTc?k>2a&Rx3BH$*<>|*Tc2_ zW9kAOsxPXl`g6e?UfQ-kt3dZk&RuPdiku~ zFFf&pA*HD#U2K@*2KewQgE5Xi-$ZI|W?U6!7B#aqyV!m+g{u^+)nx-TO5jf6wKvgA zxt@NL?h(7@$t>4MAVmGg;Du&-|69;v-^KU9GYidd@|Xyvx4*5U*K$!){~S-~vLyF8 zd^-`KfYtDsZNvh(uh=n4F?<|fz0DdExb;>xLw?xiT@rndTS`{Ss~r%|IRXdr^>FSO z!jquh?ECof3~-~48_$Q#(sQjJ{iBQDaHaCrQAj~3OZ5bI%NQLeUhI>*J^{N*p z*?f}ML%{?O?Z)_fuxBI^R5w-y2hUHhwTs0I&$>1On~MGLio%dFW&Xz6j@)e^$7ny- z=$3g#throapPjVXZ&t-MvvA;1u%^K|o1&OSqCVWk%h_a-8fdV7-8O6d{~S$fsskF- z-c>O_LTNkK)kiAO7{m8lHygw2nlJll;R9)_F(Xi`JEI>Sn)TTQ9Xn;HbyCIapmOB} zr0S&J`49Cw#ZD#fH1MgfcjvqHf~{F1%m%hesv4lPD*RUuGM~!87YGOluWc)@cj>)O zw*zKTxMuaObp`Xgo|21Uo&r}FKPAXf19wKIrl(8D$u{V0n|W`Wv7vr9s+6hJ>b55i z>v;#9cZ(M6`+TF~i=yA`zo7js9TQ_o-T?08R{ZWzgz-ClVvr}(KLMCejs>(WzTK8Z zr1)x;QGtvVDdxjmv;JY@WM65f3{v$gaES0`kxp2x2W5&2@7bm~x@33!ws|qC?^cp@ zh(o5($kkhv!w?HLPHR{Pary!dVNv6qV)0?|2j?D<_SzX+5k!FVGbMyoiTl{ok4K#4 zVHiN0B|LVfs+u52im_6cnSEP_an>%hsBxCKz^7B6P$r)x*G{paru`RfnM> z=+jMgTdq4M4gaqh&#wL2qO;o0&4m#R7fr!RkisZlrc@G%!yGj6UxZ@87k zsH+8ES9W*>6`veUY}LJf9{Sl6Yv&yG*^1Q1C@W`^9L4mMdh%vwz@<#M59qg0q{(e2 zCd7nxxTBUrvUp9^e}2vZ3T?^GO+4>=G-5%n-c-kGl;j7o_I{JBwx?v($F4Vpp?wOC zD)uT!;m^lZq4oKwuwJtBNGYsyK%fsZC0evc@*m}Jdn3-oSF1^KvvJ0^<&X;Kt&>>2 z_T**gE3FgHO5pd!LjqTqZ}2=!trxd}t84TUjV-SQx#7>tV6QDHZY!#kC&o`-76MOd z1cNOY@d;Tq+r&O#8X)=w4B|wRUp8m+35^^;&dg-!W!3y+Bzr^|Nj0Z1r#&QDU=8x) zN+o{|%COYv*R+wxq!ctpniAm1vqY(i44zNV6QGl1u6FsHk{;K8n_>{=B>Fy(X736@ z46!Au7e;VQ#P@t+28h^$8BLIrOOM;sfy>1V9t(4pu}bH}5QD@LQRdcTC~XHJCO_H3f+<5KkZANsU<-nqKPjqA41TSvOpe*3?tAp9IFDP-g@d2i6vtv zoqhfO-LkqCPwzd|P`X41Lr{In?2JPCXL%8+I34rHxBknqI(5E5wSR+ga7))3&Qo^! ztpKxlh6fGbg(*|)kNXpQxZ4Om3vV2fyx!VWd#3-~m43IUf6t^kb>;XwKf$#X006>p zZ#FN`gt9FCEbf{%`1qnEa+T}PBe{sez#B+EB@<6$e!1)LuAXZhBWstj0F~a|IKIe5 zw(t<-aiET4JiD>rrY)(`Iy)2|N)#VHbooGDX3yu+M(TN8AJIatb;vZ@m1$}FbhPex z2jltj?*7+_BznR5?*`g?bOjjFR-`NeB0}aJKH;{9;IZ@jVCVC+hvcGnS~LLe)UwUC zL^680W6j6@7Tp(4OV@lxo{SyZ_H%!)NO?4$r4~)4Q(U=q7i?DF;hy|jB%wAk_C%TF zH)e|e7AH-G7BswLCCHkitVYnR@;S0}XvUZlh*sRd9fEyk2!)yrlgm#}4Jpp? z8Nys%43eF4|hljq#%bF;RaktKHnS9Q|aTNA$qE4MRfD63FR(8mZy*6;8E zhB5mm6fMQs$C>G8VWwfKpB*UQZ1xq{g_-7UysMb3pLfO*_oZM{aHQxWJCKVdJfxhT z{ZQ2wEU5%PVX)2s^I88GV^9e?TH+eTAT=MqdEVNbj( z+Y==e5Kd=Kq$*kFh}n19IQYVNJ8h%N2;vSC4=QT2{Yg_ZTW@{TZ}q7`cUXBQhg}s@ zCRBazTg5R=j0MDooISAU5x#BvwgiK+XepRXMsnn(bdhT>V&)fgLo>^ab#U>XQPKIp z;YTbYJrNpTQ0SWQFQPiij}gp&YH!8bf#Y<^aVM$KI?%VS)tr^=u1|vRBlXv$BJzdn zPI!+R;yGwrVNkX(4g+hl${mzvm&+4(+xH-+TKYlZTGIid{p?)Xs!MH-=V&T0-LZO8~o#(-K} z^IOKxf2HsNRH=RKpMvTlG*LJUFEzCEQsy`I66CSniZy)lU*Oqc0GVSRb$>T(af(l-heQCk@hWV_JXisSm2HXA~murR6;Yzue~^9Q7keyn{_4)az2lgm+esb5_m;eixM(Vo0-*!j8g8YUv(Pww|2%dy)wW z1thT?n;#VTfuGnJ1c~jAYcA9yx$nxmYTaH;MIc%r@{=22bEZf&0prpnDSDo=&Af74b;y=!AN9^>epJ zPjj)`A`YI|LMsod5otxK+sAnX=hd<{!=#7;KA zrMo%k8(oTaMB!DCK;_|@RcC|femjip?Kd-Gp@Uq6Q$TnQGR2Yy+}VEE6_wNes)q)0 z)rp6Um6bG}{)I`Y)R09R?8MZ!y%w~i@!zRP^0$^HyuKLv%aC%o_mFQ&ZdECgDqM1E z3b{GbBs+{m(cv#uqyS_a-wpY&a%7IdEXg0x*z_IO>Y}S^&Cpi*8gezI1d0vH?k#Lz zP=7NJsH^(Y&b*Yi!4yLuh?W?`*U%Kf>oZW6L8ptBpjIU~P~L0EBF9zrLFibw??z3WCLq-;`V>{>yHToyF|R?c1hJ7I&)|$^rEI% zt7@_MDTBX6vxDv+b^_x&DfQ{1S_?H8AcWQ@KFw%2>By?S=QF(6?BUpgH@5@uV&@f_ z*BQ4OGC*dXHeuF@X>we@c26?SV3?h4aC!5bTHNM=?P2o1>d|XT87!N-J7Qb!2b2VT z;?(J6?YUU4J0zOIzKeB?BEHdWMFHOdEttdlCD&_a)z=|m{5bdk8U8z>%Pb`9+xEO$ znqWbTu0AH4pvxX=A?u{JJ@p7z;d+?)WwKtk2!1~Dr-ipt={o)WK*Q1B40Jo@PRzROv z=p_Ay^#&EE46YV1!H6h7u$BA}+d9)fF>$lDeKeV%Jt^8@CE-k}Pn4>5J?wOv$Fa&g=`oZvm#suMotn!ih1Jv%2hkyrHS!8>X9by-4h z;P5Z1=MkroubX&pLaISHzAhD{t zZyknZ@4l0}cjp?4x_k$Xr>j^)PUsv_=E+Z$}jtfJ9q+ifq zGW>8c@z>0TUyCKNGD-6zI?+uCZE+{RaCnkgfL< z+Lbzp6RyDLjI#MQDI3T_D%2vD-(&2#4trgHi1NOuu)jU_m;FdQ^^M5VcD}7ExpKxo# zABK^l+Kx0`uZUhy9F<6RHhKY(>5#>cDcqj8E#^Q=|9uvoQ?$#uvB(X6;piw6d=mC=U59M%Sjv}khSUdJlPQrbDGgVI)-YM9jzo_-t`T9t{^>NtEdmm4v3&Hy$(`p{)IM`>m z_2}}NDkY1aS&uKxdITXSmbvA$b+!wJw_T(aWLEgD6xV8Tr%vP+)dkWT=+a{CvwOdz zPfU?+i74qJUH<|D3&ln6Qx|8CYI)?Ph(SCz(nG8N&ci$6FwlND<-^UjA}XXc`O;3L zv*?B8f~3x7a}OE`WfBYM>J+9%=em_19!}!(wBk4y{AbKkKeap-|i+`jeRnC2l*>2r#DSCL8ea>yPg&9WXbf}KE;cTktO zMXPs*{N)FA_YHOS;}VjM5ZiFY(>i7Dfo+3%inVs*0i18cJDoIZeGrJd=^{(_w+p`T zC9dnU4&68`uy|*sZFjIPkjlU#?St$wR_{BeT3t%-6!@h^Zk=Zgxgt7g6p+-gg&V8^ z?L?a`!c^a=Dt`VUQqw0H$)cYzcLyGcnVjt11TJ@R!T$Gger*3GU7P|834-TRV}A_p54!v z!YLnbAZ}q7$yM?Q^L|uxbAa67ldw?lqh^#ZCjJ@zJFKpKMdLhdt?$bzsjz4DG-yvQ%qSV5 z^jz;aUN&5^*Xz8Gj=CAL$L{>Q7=!x`conqlEG6$mL|3A4@IgjkCPQ5 zqX6T&Z~Ri9@86f-%OEEz=U)Y5iXft0)Yf{xrt(A$%Mmk8&wFHYl}-_W91z^3&hKga zWm(!qMc2il*_?*hz@f1nAg%e28=r_|Y4+P1UpcPFJ85(lWRPC~W%AncO_9Qx!=7CG zO$+I{X-!*DAwcWZe)GDPi;Q7B}`Mr?+}*R5jp<6&mMb zAA0N@@IUQUtiJ8U6`92NUF~*gMQW%v+91^!zn@`lLjHyy3ADP^Wt{O|pv#&UqoTKK z{53v;mvdDINrorr@!G2BR4mWbwE`@;W@E~9!JEHF@`hlY|&y555O5MG7rZa7 zMNi*n{(aPU;7V!qZI$v?s=t$_pfqkNm!%>y{b1xxWcgw3*?_y-!l+o*X+g6fWzMZ8 zK&-e7s zigmA{Tsm*!PoMH&H@33&9CHB2!Q`LbONCGgY1;iaX9FpN_nKJZ>ab3<>f^c&YHpV% zqz=@$Cih}f3XY2*gCar71kVBagG(MN`-P0T&~BxQk#6KL9zhATqLN#{NCDxq)Q!i( z=(Z?bfql;N*IYvIX{qOfef!1QIQ7GIO(f)Ocj`+)@XnCut*!pHb@bsz_uk(9 zB0-QtnXOcZ%@?4^DYHTGMWw1PWM%idWV-guYQIqLkiR!&*e*x?qCAL?Ods1y@b+ z#G1klxfrdouFH)+vRd=mFR`fw9l z7f!L7e(ayj+Szk|Se0=47@pi^!Ap8N1=MK+9ZKdVNBHC#( zden`^h}II5!@4H!(8XA+{}pw(o6oMIt@H{7Wr#jq=VKd#;8iA`j?z9%CXtg;=m28g zZ&6t(d0Hh%*nwXGj?=X0&{Gq;R)eK9?Xe+owxjg&$wSP`SwCk*M!e|F%a@3}aP7gZ z7Fk^11Ng^f5t3~$h!;lj=DOw_%#D@VS2kS;1AFTCA;*#u1EATzQ{dQF#EZjZ$z@F? z2~VHE6kOi1%Asc-{8efKJr%`&us6Lj1j}{EWPgtT&`PhRAaXPV%hfb}&v<7KQun5E z@Q4aLY;@Xg1CMb?Bf{QQJSJQgkoG06GC#X61qsOQhAD|`!_#_CUn6&g&sSQ3+Pww- ze*j9!s|5`RK-E~67f{Ij5{GM78z@|r3$yV(kXS)Gg$X?>U7g2d=&ymr56a=Si3vqf zN$Ly;7h7hzyLl#T_&#+~9}Y{3N;# ziw%rM9~7_Il$9&bTZQKnPIv;bf@YI%QAoj67VaO1ak^1wg0re%g^<3Nr-<2h0<}GM zlJfjl{WwSH^C*+iYx>5xAEn1_hqBNObWCb*eind+lsl}4G4mK64x)(in8h@=gyS`~ z-mAt$5l|_JF%+=W!R9f+bSck}U|%g_?$4DTIEnazuK1|K`-~84%BaX9I64uF`Vc_1 zq$%GNvIOXx`3;`3QiDKCH4>@vt)A>ElKkElVUVY;igTj2M-2sCv46}t&_UoEMSTK` z@&+Udmm!rtG1*LVI-JrqwZS57<|TE(Qu{`^R)|=01n)9WO$t&3TEGl%6N76=%0)%w zWCvDF(zm=G*_&BnRjq2%R3C1)+BBPAp#6GFe6LP_AP2#L{mw*{oAMsl(&qc z7TI0I$-7)Sy;ZTAJ1FScx5H=ep+KuE0(Ix9tXW@} zI&Pr(xS?!Y-L9g_Sj*h+iC}%(FJCtE+2c>Whe?xZ{eBTS`rGxen1bu$pTu`jYs-<-Szg22!5&hV6coxSJw5W#m?rv z169t6yznJ2g4(7F}xd)!Ku`g*BO6hh#;#0k201eg#Z`@L0 zFXUL#3$h~Kyb!@#!5UYWwXm_1nd{I|KVFzcU1WP-M_xLyYDhF+`;kzsZ+FTF!8jUk@(d1&9FfW!lRTjP1|}xa z9wH-2ZLIsGo6p0j|K!8GkeO3m+$#L+pY!9nNFxcav}HBWj{i3Z`>!B|mE!ry@xj)W zKpe9N8KRo0IAud~!jTqHoKW{4l8b8kb5cryarT&DYC(#g}F%oem-_@H5m)pXC>t zmOd$GRv-}~YAokU@5*A0A=FwHzMtGAo<}iWV|_!RcJ1RDiUj($2ot>otuKI4NGlFt z?b%+BI6yv?Rq@hDr0Ko-U)ZvL4O@JzzlP?t#s6@3$fv+NQ`axn{7i1UUG=cnA%kE5 zEdRD6Pv8&v+;f-8O%(v%N5s;0+9{X??irB?sJoA$^2<(fUF=mPDYDrohHfD;Iq`0H=G!GtcsCA;sjUolbe3T1*X(U9?ftNPx7_r4mrBy;0@8?x(6VX@>qNE%q^x^C40U@Y2LfyohFd}r!uIB2Y|^o z8psEpfkPrk9j!9oa{-+ZX7`Dq0oPCz?xZqBj0qeE(7zirsZOX}m?o3<3aT+BCOZnM zz;d6}7c0OrOYqyLLsP&8Rnp11W}U0h;pl>QaDCdgCRT!DXifJTo;n(eWY*mA9DL)w zGF5Mjka1@qdtrVW-(uS|fDJ4#1a=dV0$3)iJ~QWXN#_+Xxb_b@&9LbZAb=kjT?CA^ ze~VYC}B-c z2^-u6Zwo3M9XVul|LSMxE^nkU2Kf)Gb(;KUMG}(`)&Is3S+ec& zSP+jMp-v1nhpfRN2EGuL0fFcg&FoQ3jZ!zmPWoJQdi8}vPbB{cTkQu)+x{$LZDJ^Z zI%&X*iWINKX>@1N-X;^a4+uV9tfaW){FnNr0kkN?>2o5e&tZpj*M3AxX+MwJ=J-{WRi(3V105>@7@1;`Aa^NWE}gp3sGt5pm#NLde| zODGnKx9DP5HCtq05#q4XsfwL;$3m@>_IY_D43p~KBkuAhzq2CJyeOOQk$iF!Q)>px zw`|g9<0Du}AGrn!$bcW`aGoACvV^jQyh10Zb#9S|l&1)5uUUL{fLb+@w}Vz6$?G>z z7F0)PZ}0e2^^dRO_M-gf)=?ACqQO6U&x_$AF#U<#wS9`Wk9;@cOX?=sy2VeLz}6~W zPwpNGi+88WX-y|{*bC(gNg$vn1aQvOv@n0bjf^I!weMblo_QN^tt5*rYr>X?o~U!H zg0t`sk>tS;xne2RTJdSHN{R6_)5x?FyGg(7uobCtxpeJiXG3wnLPNr7_tZ{mrnVK# z9B`_;4(qtGg4i@w!2WxQHRT{SePG;potGu=o)goTPx0zwzVL%At`muD;KKzUAzo{k zQt*Nbb6g$4zfjr+q5pY=RV6Y7Mj zY`1Ryv1%iP9{_YnZa`N@G7Y-c#N8qm4Fu)-?nL$Yn_Fq7t z#y2stT+E3gjy6dEO5k=|(*&9m%=nb;R&zh;DSLHP5d^Zc;^ImbMXbMSXY&%0H7f91 z)T)_a`f6i@P8ZOwp!0wXGQ__;ToC6^$3P(b<^j>C3OXSRq+{qOhjsBT zAqka^Z*#}^A>6c^VFZ&()EG&k07C$!e$Myr_Wza`SO`bys;A#os(n^z5nNL)XA(6n zHuZaHAVkjqk*mB3O%jc7e!w5$*IgDNdJ`~&4P3eb6x=6Sa8*Kf%)kIg7f4uNuLFd z*`Uo7hYvC9B&@Q77qBMo&ek0vMQrxrrh}XpKwp}nL(=?Ia%VQ9cza7zf*-`h#oCL(To zo!oSTHp$PT&uN|=#dvZ7zD_^(t`CxcoQ9J071X%8i$|H__sY1NQLf= z9ikBNe{Q9EEee}zZzeO%F~1J7;H3R&g5{{<6h-v2Cjs7i@_P%Fdne@^7?B*dS_M`( z`c%&=F1_iwwl$mEf+ls#A&W{&8^YvHSMzsdiHKoUy4+Sn-4+rNQHn0X6y z8zR|PZ@XdW@pLb_(=QWu0nZfyK1+4;%B1HNYyzr%+qfOz*=MTc^FBbYtvLG4Jb&&Ih4_K7gdD%szPF* zH7gBbGkRN`+j@$t5=WN)B`HTIBaKpo@a(Zq!F920i0GjX2MNUnLV72b#LDNne?hBx z^ZXwpBk@`fr!pgO(L8_YxHk2A5FIvgWy=_u_*yPm9q3KIm`*&7%P9_joP}qwI3cv0 z_5r*@2rVrknZ#4!p#T%qnC^}F@gttw-poYcOWU3RDAu06_; zhs$tgON1G3!ZM0l%yW`<67Thi+)~S%cip!1YXfGZyxjc%p@S{2C5H)6h?nf4M5bce zo+Sm)_p=8LiisH@ic zrzFLz6Ab;%)Z$$d4>474W(H83MjpHe`>)@iwM6R-ojF|}dg!r2HXai1j283Tq=!y_ zjn-eiOtovA*aPKaGw-oGVmIP5-Zu^Yr1-BxffCpZ7(gV`lSU5;!eqYD@qn7{eleM3 zueCig_lAk2fgVHYJieGYfVNxw3V|dFyG>6@B9P^ zDD$0QSs5BZ0kQoK9_C< zUYrW(`@YvdRN58k#}~Q;$^{ zQ9z*U3$!4ll<+;FK#AP8+{DUE3uwQC_-6`dJVX6){-j59?Jo+=QgElGQ6>BZ}u{Ff%XILlW z!rGCCDw`UXBQb`sJ?8WM=OSFVa2`PyFoCpQR~E%LeJp^fAK7!PW?XFhmsDC}k`OqP ze->yj)y_a}eycm%iy~Z8nTly4RU^oH*+-?|b*C=OW}u0x`Gr=G3|mW8HXPVNH6NI<;5Qo+(exImIrd(Rz%}bI z69wVG*PYa3)rIuBP}Y+47tK~4GKg)zLC8J35QR1?>`bnc&?j`3Qo>KkU^!0&;@ETR ze|z?Gci|L0ud;1{gM8iyQ$*wRpc@8~j1$h1dI|4@KFdV3c%7Ei_eIL1V0lkVi!BEG zsM8A$07X$X4fA;GL6~(pB53(`%J{HxW^K-)o*lWR>$s=obw@jpr&Wo^?Gvv+@k$y@ z<|c-w$4R)FHb2zM0ydItwekSs>>byRs9*lqEm zE5b3S=O0{8ysk*mgF>vJlxZ@`M3^;UEQ=6gf5)JWeOq;Pt^J;8aio*rM|DZgiA3G( zxmkKTY;MYg{h|C91MK7wv6nfa-Rwu#EtURj5 z*D8M&mynF&UQ|ZR^}nK_U9F5))gk_TIKzwDG4_0Wa9c^{%Esg`r)I}5j3F((R%&*t zFR1jq2^)ClU~+1k=Km_K^m%?b0l%zlS0A(;D|!$dD$VNir3D)QT#KaiSL$LD)qzy( zBp4b>sZrdP2XjL1sX&aWMYfBWqP4JX7j9d9<4m^*iBH+1b@tO(OO=!=qA}Q69`*qZ zRu9H#|LyM3t4E%}e7@;S5s#_*5?&7;ykZ7wa=+!~eJ;pBL> zk4$LEV19OV(i$o9(%v**-DEppebVZMavq#|W9Qo#-ulxk)q zv5)MwkpRhDg4u@QIeXu1*f}&mSE69Om3Rbg6Vf358TzX?w}9t11GE`(?$luXBR+WE z0vVC0CsK{PBt_E4xM>w9ljR>%Y_OsA<)HCD!8>q?AAiZ;0d8MdX&8?7qFpZRANHq$eV2OlS({ zaA~E>=VhzzoVM*j(Q0|g6I(1%Yj{<<^~Enx16CBSwL;GyZ;Vy%E$*et8K{2L7QKrr zR5}VeAz{Y>@Ie~jtNsv(l^gvT(;b@8t#vYp&8LWKG?j}ZC5C0D> zd@acGCfGiY-|wEpu}TD~*Z!>jm3GaR21^bt!)%Q1rMZN-#p&plp4u>Zj&7If=*A>n zIY$oC+V0H)DStqmo1U5uS)ZZYh&`eP3SA(M-95bA96kQ6XvySlIflP~hyy?aaVBS6 zwU>|7%+5!YSve5Nn}Y%V+wg z0xS)$Q12IA%XJ}w0L)xt`*Ui~#U8oZ>*dKN55}hlXEu*}Y`;QSa|+l>g*X6`;BXxx zZLaE4P}YA6N?@xI#{l^PRGTpW4w5lWa>}o)p*~!zLlNoOwaM@v8VA+;?kMn(i}WoUBDw zERGZk`#79AewO3*THRpnuwFz=w8|YkG~GDxA(6RsHq@eNom$N~sfR5`U`7UYa?QEF zluwSm=L4Y?6LI8HOUKMGrEGC)BCg05owg1uP4q{(hfh=S}tujK0?fU$+hXFk4 ziTIT<^%8BE9s))iHY9*ak<_oS1pY4x6aEb+1h)m3kZYo3i61YO{}rE3)zdSf!p$fn zT7=eIe5@ZE@|W>--W}EGM9YCYL{S}qcOc4`cH<`-hzTsvA>N4Ccg+CR`Wm=mifkz%*cOvU_ZOy3Xp z4K_T)ae*D>*KQJ)6$lZgWGzSueu84?=DIK=rQl~9^T0wM?R88wrr?7p+C@mHOEA=E zJ`@IJrSg#C+=~a$fC@jA-FLu)URYH1@j>xtCe>9K`1WH^nwz)$I|BaxX~fmJrE8_t z|L3bL*N1ITgFFyE6i-yFMhq(%60R`n?a*lw55B95zltIrT9{ z7R9*MkfoaBA44fAp4jRsVsbKC`{8DO`oDev-&opi1Dfnjy3Fe(Xu=H$P#peYytFvyBXyHkD$w9W#=aF_1cJ;l=Vu!^LM!_qQpo<73e(RYyCh9 z4?AS2q}eeJkf?BhuS`5VuU!k@zvq9iQE|j;z!5lUg2490_%MRO#76F0jkC!iN-dtmV>5vcZC~3W@$lsJINRtBj2e(3+A~x9Q@BZ0Py!t^P+0 zzO7uv4GCjk7L#64uUyg-CQ76JikVlgW$;*hD$#nlJnmp{`?u%Owirr zwau_%fAr7z(|^mxZb{IQf6Ux2#H#Z>swM~>x#T+zXo|(3B+1-?)u7f;YkZblb`+M_ zLM#XR*_i#b#L$2UX&fnS*a9LKV;+V20|9G_Jsba)Xn{nprbHpFGk`uw#wgS|JDREr zBR~jVc0Mh-iVEgDY|)?+W$p}*|3p)zb2EmcG48HS;!Bm7A_=F z8mSyIK;GDshrwaNvbBQyS@x=T-Bqyof7Uc6P{3{GjT+2XnA6p+!G(NWJ_n(T(EsMm zDCUHip+}p)A;TGf3}bSf{1o}uDJI4>=9^~;02k7v;6wWvA(IZ(aPcEllmV_ekMD$| z`Fp?bWS_Yn-dSX4Z{x0)y=RfAVynt{Ek7MHD})?ss8)KhzW(evRHeCZjMR!S^F+_T z;b~SazC3Rl@AkUCryt&c>)g{lZS@{zjr}inWHdx$17G-)jK)1OvNMQgA;G*uvA1H7 z^bdWaiZYJ7*%B4J(KMo;1lQZ{)>B=9M1wOTj$|EoL%}BWL{V`2S6QgXDY0lN1jxZX zuv6NTUDG1F%UxFfz0GL1c#bm$nK-TObt@)k<{(v(~3wJ^X5IsI;hOowqRGu~8 z-yXIcR|f%9OA~&2W$qT`r^N@#k)N$$QTW~qSwSb>l_!NeU3y=js&ymytMa zHOAje8-m{(vl5OB@8~a!(s`L&yUPFytTGTprg#4=9{NX(Z2{j!n%YE0I1}twwQwm` z)ZZb6Q17@K<7fe1Yj<#K|KfrnMEl9hoc6j%l}-qHJJG%KvF9(xm)u+2&(igdp0@iA z2T#ov8b838TRLT5$%H(=DAXWYBNnB*MiiEf{ zgPNF>FylI2!5D9NVoAx7IELsx0!YRneIhfaedvw?;012t6DfK+8E+jgW1-qXjhi0s zYeKr>q2AMpNr!7u#}lOMUq6t2dfMM!xY`Uy^jYj4tn``^xqYVY#JWhwV%r?$s<`V? z9{I3=28LFUgnLUdK3`q;paP#y+Y)0>4}bnI(XqNNuj@^tXG{@7)TcI1h``O6i~2=K zZ}eSf+?JYR&g^@^!oG-JH#79=#V$i`!R7NqfGFeH#Bzb>3dB(3z>ZVxtH|)oN09oD zW~BbQyt*?W8osQEBZ{ZWwmRnYO0KuZ0>qwQYflh=v)e`vMACsgY@*)L(FpHVI?l&W zi(V;XOnK}d&=L8m9e=5fTCJkC_(CE5>^)z=okg(-el}-QmUc*`DmW_e~B8S5JZoj0_opRgb*VTz|5xW{*T+#n*!*268>|J5{;oT@IYa zvKU$Kj#P9Avk(g#kn6k>Xu1OX+*l){iXBV-cO_B6bX8q&8({rH{N&Q-U_e}@;Ep|* zBx?qc*;0vy16heJ#jjgg8q4sE&j4A(!ClhyA8m70>@sd&@wS}YDf`DMdw{cK)%?l( zi>c%JY%OrZZ;ubRb!^+h1>gR5e^o#}fLmDPPh8}mmK--I+UjeaDtz<=a!!o1F@1`6 zU6(;RJcK{d#xiQ>iL!&0NdW8Z2>;dydEJg!>JEM2Rv$7eJo+%Vq%rZ}o`V|&)t24J}0wmSnpr!1W==MKYLX-Ud3w{%?FdVt5k zMpv}xPhPffRP=C-1HmPz30^lJLd=!3hu^uX`fu_^=o`tOR+RD9UF?vI0j!X25js0I zYJU-pWLLy8lt6PI9A=LAPK8H?8P*5ZQ z)8~3old>cNuyO>gxX!D6dG5YD7xcNKd)}ssO~_(mD&g>*WtQvK_ssyTS`vNV3aX9Q zvmw^51bngZE2(v2r)E}q-jKGZ%Q^H70xO<~kwuxgfpG}nZAPC*N!?)}!%@Ha|GvOG ze$pFP*ZGTOwtwU%pI~NH4HPVrI3*ojjPMXJjUL1}mBap(k&W1yY|CpMEkljKO04cG z+7JV#qP+Q+=@vH5syk3xa{767Zvw*pTcD@*Wnd1L>x5t@*5`@f;jQyU{`J0>>3nfO zAu)?duihnnv=E ziDC*6(pUTL-hA)u=B>4y=Jfu%>U8gfnu12iE&$Z)|6wwQ3Rq*A{E?N#P8;Wd&5tOg z(KvnN4TFa-B%ivrDqv;PLR1&i7-rL1v4hX^0#Q2TZPZ(NwqFlX$9B4(IrBE(0?SDT zh{!_q>Lb--WzR1Z2)DO$c>9B8H2*o?4z07zGNr=;Mw78V`+ROMqN6%5;G0aF-Qd82 zXE503pxg_5eMjNmYw2R|&OTt(IHKJcm4rEu@|9c`(>`*Q&$9(U=i9d{pWZPTpjp_> z?6gt+-b#|Adtd)^OWBM<==x}Jxy1^-Nd%G%SO9@dy7Yq_zuQ{X}ixY}%H^EI7E3cfHi z5q;iH1WZtDy*JVyhww-a13hR|(eO$UF-3)FtB@(++Vo}6J`n~^wzNL6A>04iE1|>M zoA9iX#*2^0F-`9UY0 z`^9@O#&+*NihA+4_g6-#?E@={aDKE?#fg*!mZ&hX{qOFKVmW|Vuu|&bt)ClR_92@6 ziU`M&hO})+RvzcDzD-0(774^Ko%qAdj9LWr&cmij)|o16;K5{!XLdhdJK=Xbb9sHu ziLpE0nb}HC=WgFdy=lTJh5H#Hs(|SMP@lPq`YHNlZ>|V(5D`E^GTEQJJEVMep3e3% z*X;cid^gE+o{tf-`MHNiWHIom#`|O`gvfuyMKBJCSS4DuUIpMCi| zQR^!}awXpVgHqkm7`Z!r%c&5pYe&UDeQ_$|Bgo?5Kz>F~-;=h+XIrlFjQmGyP|{>2 z@908jL*{!YJZ2=^)Nd#|;khGKqA-xO7e9C`cDJ#m{ z8~~(TefeicG@u56^g%$I4}<$?*vinF7_UkJ)V1>2=`E;mzaN9dkmo~F8Gkn=rU|R4 z%h#)A71hXgXSI2_pA~S4_{#OKq2=oLj%oo?5>=9!jPJLFB2S2rgPVql)_U+=gQ`d4jRcWcAt1WL4<{v?p1 zr|G&rDgEgq zrEHHc0}3)51yXy)Z+3bLvc@--vDUO`^}+iD)~DgWM7Uk;Z8Qh|C-D0>w4ZDYM^f~w z0t7HWgJxSnam+9#avLV_!rFXcmP?h1VoWo+kPiPlPITzcL zDnU~nqW-!`F8tG&b~mHnC?ulqp%Y(D3kW%Z)UB9JCiWKaOBpSnXWPv8@h#;tcP{0P zV1y`5;=&ou$O`tQ+QYhr?*fal;5hLOvD^Xs)Qw?QXBeS2a{3#rZoovrpx_V3-wh#J zBZsiP-iL!Z*93X7+YRoq%kLoQ8VUo4y|Fb9o$i}Wuf&AcEU5U;IC*Ng|2>rK6(PEs zF6bepXj@n*W^@~uMlZNR;eC;RcP!XtSOm19MiRdFUnWjU$%w7Zv7_h|DQ`aip>Ld~ z2H_q`PVZ2})l-^M&xA%JOWFF*uv=ytb(5h*Lj;#Q3j8nB zMpr{YvZM|p#x83y3mX3|!Kg*9dJ16>6G^FN2gMS7G-^OdP>h(VI)`=QusDH>^FXQ| zgrWn5u9*JTQ+F%%pe~AhP9}mN&Ox(_v^MIhlq}mP4Qv@kz^~W?I26tYM{*$wNa2S~ zOigCcX6Yp23h=c*Cf&~LD6a+j`n-NK$H!FUz#@uE`ZE5nNK2l86oNCro4GlsVi0yE z5SXW6Dm`jIE!1}5DKXh*1s0&4-#pw{y#V-gQkFPi@H~xYBgB(44H8 zHwc9iMRbFU<=84YE71H$bh3zeo4c`y?foZLot(0CGZN+h?Zwc4i&4XkAqBGkrr$8> zq;m~vQNiV{w^fy!^R50OEt?@&a#HngU$n6&sPNamBM&xPnB+CcmK~t}X}7Lyc-f@O zc`kCO6MqafqQ5MUpZpXWQ*~nRx2h9vc81Jk)&T=D`$@6?)E!acaJ)Dr-dg)>{UQ?y z3j@**u%<8;`20VVp~4>s?O{fuaYK#o;HXd1~hB`=3alp{&zEYF@WM2-CrB1&63}m z0$0&xA3CF4BIe98m<7J&e~5R-g7i=)27%%~f>MlwhJ(3?0XK_;VJ>K!!RF5p&6u#P z1yFjQj4ckF8B;kZK^APD66*VTQ+k}m~uMjUU-o&lnq`_+&5!Y2n z3sRfoG(j|0){rDN_%(P%XkbEJG*bZjFH*NizlSC}$d-v-CWsOsVdiODQyjg6N{|BH ziSMR>Ya~$+6lfZK_%nnC#atmIab2o=puIggK{hyh3bHHWYhNziF*6!7XZ&7r?=}EM zsi94Om}CH?dLjh=j_9`_<`m0orQYIBBON~cuN;WX5tJhRzX6!*{aXGjf6poNYsqI* zPZ}UbmW6d@{mk)~poFHe6Q}fag8g4&4B0*coW|};}>o*hh z!sj#rCd6BG1@o_IYVl(E;dW}Mo^E14(&;iFYi86s1W=4$Fwnb_@S{xLqaPNI`Wqxs3v+$`$@bA$FCaZ(Q(!PH$uHDMszUc~% zw|enZg`b$lP?NWfP@(NHUP}dX*@cW-h%i=eF=;c_ezt^=0ixdzS<_M7ohtYDmyM6+ zh2ay)!$%m6|8251ic>^cAbg>=opdVow$VT;`S+i&8_<~DTNz`_V$Hua3N!Sl zk}z3olf_|`N@~xcqPE$X+iG#1*is#CaBv}iJZ`)HG1@{#MpmT$Afm40Ib6TJv_~e~xpi#_=hlB)OMRcMt(N|Jjss&0> zAU5z)gL@;u8x9(M;k}<1`$pZ{eya(P@DxH&dv0)`+&Ewr8;zl<%f^RrLo}u-sxmAU z%8tde*+Tqw5TT|@Q6WXCMeCzS7GzmI9jArZKxm+7=d`r66suPcqLx*CxHbusY~Ev{ z9;ie|QU}44P>ZW#ixK;q+!zZ0jD+0tzcunAwT!l)N`PrSTfL==EMjW#w;dw<|qcG^)JzP z>xv^9r#cueHX8pHgj1;p9&a=3FoRK%Rs|8bjXsUzgkpvYNeJfvWwUrTYk7w6O zGR&kK8DHjs1F>#Z00U#5)kVlfOmL|NeC@Fb-?%E2Yj~(vNtPOH z^bf{rS`a${*7QWbZ^pl`SugYS`R}FmoLS|ujDx(8LVg3d&=vP4-Ix;7#@9tPA6C!zil)&e0)ZN$b2H!&9PNrXLGaW0Lk{}(&c3@ z{hv5$bfz@nWV8(>OAX_LF}O-2B3TYndO9 zY2vVPSePsEPKO{fU{rhI>oi)k@y3`*Lr%nWaDT6b$c(;q=biWkx2kpaqfF z@6J6D7f4geFvK`bnStnsyO_nkLWgBe3Ot|a<8NXFhG5WsSc`k!Z?oO&E8>xlHtMy! zFGpwof_A`tU9A5t_Ax7>S^x|ZRE)$JP=_$6LUt!`pqO1gd!#$%!T`*z1}$y(ci}!S zjkVd}<@43T24j)T^n4MyW6)>HA_bDMq5y@7ovy#~%6L^Q+VJfLS*NkROYZ zl5XgYl!iJ@>z4jG4<3?!QKY6;Ua+SVlVTC%MU)W3Hjp@Gmjq7ebtD*6fSGepQHv9Qo-ACbXr!gOudQDj9{WNhT6q#*Kn2zQ^@~ zpd42DD{*5L`qa!jCAb&u@QUTiS_KpqcFCj{`!w-ec=47r(3cCu6-Q?QwO@v-Jva4H z>9H;T;7tA;>Z~>SuG5|<$LkrI$m5uKJbPIAG6Nn$@c`$N^^naq*4R7PWnzlN(Q zYEIc+)uLmC7Ghpq*k@8{_i-`darrjss9lez%W@|46BkMdE6eAW+8n@DC7kQ{z|c|M z>qVvewonyD2uoI!y$pn23GNTnk=6&y-iKl&U4sABzO07t-!*QRF||l28JfD08+Ps} zJMcdOVA(h6nA4-xzwhtvVJ#4g-8wN5I5J@00e?4+*&6?(on;JA)fkC6CweCnnQ5d< zivyaUlPq<7d7UE(@Ly5>PElta)_%5&PB?n}JiTYWyQB&^!^&nwf^Ch@Uu=8#f8yU2 zEAP^>{fuIGwN8)RB@{Le`lEhbxvJL)@H5_bKrLhLA0Z16jIlr&oQ zUb89jHWwYU$$l4)k&FsBT5Tto$Tt$dnHI7SsVv&d`HE<?$(AoZos79hs09Vk1yu75zOj4JS3uUd<*RSc6Xk$kuUg1;rP7bQv<&ar+`*taz2d{GX@Jo25({r0G-FRnnNF}51e5-m zuKms=@;O1(#T&gkF#P7V*@s+GB4afCxr!5u0iX?Zcho4eOO}Z6rWssh#R1)uEh)QKW=)Qr3R1s$sAa{DiKGUdU>xtc-@@1Dp znvolnar#9@7J!O^*i!cp3i~Gf$4Il$w(ALJ%L`gU;Ptx9|6(M_nZ zH;fP;LWcwxL_;yyzz?P6I7;)OVE7MmcZ3e*wn;~rKJJfgSPvy=WtcbXnCqcFIo-Cl z)cMoXT|s^asDdlb(0;^r){O1HZvJH3FqBuQjudEIaTUrG#C<<}eMZ>#6*Nauy-h4f zw|`K2Jwe%xGk!F3p}A)LP{fhRHN4_aP)9ofxOY<+*bbPE$FN}^dfWHvmQSzJ3}MW#3RZD&ynToC<|%5~~g@u^<% zLULtNHGuq6B?k42T%hV8_iTSQpx?c|&li{Gl&!WZRHw9Y*jCIS2%Tzwy4@Ty{o3`g z$Vx>O`7@jG;&S&>>Yg>K?igE2y(%)JBHng6M37k7mzbvWd;|zjIOUaw%1j+^DVwz< z19jholMaN&8}j=Yuv_wg0)vU&Mc`0cdFQ$R_Yg)oD{^2O>S@aK=|RxPEWGh$+PEs^ z)joFOL_Y!1^L{AlG$|EI5q1@jb~Y_@s;k-uH+4DC(K%%DZmibf3bR-dq;RPes5q~& zjG0IMhg0$2wMv2EFEP%+d+I|T)p!18RY)Ozqc7#kUkk!TART4AsiQz3A5gm4|kJj0>@8uj%ym9li8K0^8;D%m0>F@gt9aZjQ zCko&BQZ@QK?|K}G%s(96v8vpof|YuCsL_LuArxJ`zOne`c4XXfP&oU&LF|U+7V>Y( z#)fz^GgKmv+W=wwHe|^^>E}&BqJODxH!s7C;IlLNxUlpjOG)+CFJAWte^|H<#nlDv z={_us;ShG-_fRx~UqIm@<}d^?<$__l3%1&=(-Q^tZy6Nl{Ap<&z!^C(g03l3M*?L@ z7(UNxthRiJ&dUVmp?Hk77K>Xg_c|AtN>jJ)1TY}|^6*H{5oB+Dsj{GO6e(6zsFQRLiXSF_ z?~05~5YH8u%5MD#U{xh*i*Lw*K@FD&1zyXUclOIDP{XZ}Mk|Oo?q4+pLoN}M2y=2C zUrO$y!9MYPcPN)A)gAuTzIHgvp`7~YJFU#=vx{%h5$2_9zB(Kw<{{7~j*4?*zz_UN zWsnQ^A~j_&Q{_u>qB2xC2tTDSC!K~RzCx4yD;_5@t5_B!4Yb?!gf)48rgK?OcNnZrm{i_+*?h(|K@ z6l@4d&&%71qSJ;UQ;!f1vTJbF=PdejJ|b`9#XEZge#sU&!ARl>)H=Wzs;F!xiDz3z1OSH@}C=oI90w!;jsi?dVl5DZo@^qlLpxp<$|}R z=Nh6Mn#%TI6I!^~4rJRFiWx*;oYg=M?{I}_$?}?Y-ti?>Y^6`!sT+jk*!bo8+o5=; zlbw<3-Rk55qwGQOOUQfWu2*PQJ_$N}QZaqwP|v5T{2o3*=|>p;>t$6QMyU4@ zsJrEk`nEUe3rTXRYA=IBmzj%1h^g5D7gTCs($~1Qdz*1wz4w?b&cjmCr&z-Dt-o&B zNRGx<3L#L|Qru94Y^v2hD0?Qu&r>A|SGGVUlcm*GLyM%$6*oG3SAbm^9)Y0UYuzXD z3y_fl?$COFOeOX*ktp*o$CIHyB7AB^e&PgJ&YMM#lTr0o#$TQnw^zKk6}5Chd;Jdl z7eM+mF&<^|0F01xUw+}MUh;NAo;?P4bPLjPu|loJP5H=YP}n)&>N&z7LoA12FNM87 z?IX{Px2}O%WJo*KZ$lk7B3*N9kHhWy_Evf@%SiXVrjqvq>Qrt=a)Hl%1TGHi zF*b-X3N#i*QqC#n1yxB=;wJ3^dR1<(&l#l2ey>%=>6Y3VBa#DmBGgQwD%x3EFmQF^ zH3F)WlWqj#p(P5vS$s2LUHID)f^lA_mN@C7i^#XX*W_<656u4|sdHgD+vkUO?|2ma zs(&NMu(|D*i523WSa#-2E~vOlPMB12=ylC)1D;{)L`zuGu6p{T0BTkbjX7 z6KXxUCpiX8APA(ccR>mbY9@PY8v);Af$5j85%Of|`UMG|3iUU~qXG>`?lZ&_pI9tFtgQt?+KxhowbeD=@4ErKF*TvnmR8^#J1V+bVvpAJCu9-=LzUE zr(lxhswy|)>}V{nEOP{hfg1f!%;B9pyJoWqX5JyBU%>YEJ;X)yhEtZj(Ankc@l_FJ zG8v?qSyMM_E>oq?7WOCnGA2C7mpI&SMJg^lY$@B>FQN=YnIzDV{!s}vO?SPoqmx{} z5YcAuf^kZb?~(RYU_?;>g@}F!637^?c(3|S$*c+|92fbaAweLq2KzlcZvFKkyQ(B zTHOcTGCp^T^fzR@VtxN&d)+wvC~Vhc$6E$nTvV@qZ`$S$&G(0K1wHaJ2+{+y5~vDJ zh?B14{o7L#|FB#B1SD%KeaXHYyiyUm_g?f%pBvk{p#i{U@y&Roy{Q9m=sIP6dkVk$ znNGvNc8(JlPB-1uw2lhLDQTMa3_{fl8PN5g#!__1SkqJ4^#>X0CDy8Xn|}?432i@N zQ@>o8X&5U>1rVlbk6T}l&XEe!VjdTR_n~8-1O$h#1}HPYucIq>gbEE1zx|WW7fr_; zFIVW_9#7!zYwuRNh3=+8jGkPt6T;FrX<&vAEE8FkYyN&Dl&)YlsWGf2G=42vOe@5) zxXu~dG|M0&@@ zZc9p-POX1l(({TojfuLjTz^BqTV-EydV;fE8_`!F^%#<@H?;KF6N`Xd4CuwtZSH&O zd^P!TGd81FpWTGD0}UzCtQ086g`WSRqHZtOc_W zV&#eF?ZGV^@rdSYszy-YaOJP4z=u_eAPJ$z|Gn}GKe;c&BG@VTdo$D1IXd%_SIaN> zaDnCZFmjws_)-B+i#jD>H>~D1s>^X&x!Hp4Pi_O(ryyt0X@{}5FFs^g53QsLLlRbm zg}ho9szLc@|4Py>a`$f=7qT$(%IfodNGrBvwhA@(7vK?G;r=Z@+?r=@GJXXGfPoJc zOh0#~^#sNzuj-Qs!QOgs{)m_3vLb-{74{Zol0Y-_>TQd9D*2$7xDGA7< zU_cXudhQ{k>|&*mLhy5Xw^ewUX`^L-yb1X2JyLQWOR(DcGb|Zg>XG;5Dr#+jku;f{ z6;_@o5@VDstO}14+}#&SLxyZgfbMD_`V$O-e!rp9*+L&+ib&2eQ&Jp7zNLMC8R>?x z9r|MsH<)1(f)vCDDBd98sdgiz61nw&m%-$!GhjzTDXVNsO{@l z=bv9M2B$Y2T^dV^(T(tz;H}V1kSq?xs@j`tIK-#7Ge#Gmo4_9aCAx&WZ_jWs{bErYVPToO5O|_z@Csax0^-8-AnAi!@A(3$J*8TS_98#MbkGf&SHqn$3vVGd^xh<%O!Sr z4zWM3rIa-s!H?iYbohDL_EAXvQu889_>h9CYT98XJ&xHEktQ7V&Q6xn>X)~kUAdTA zo44qJmGhiK(bAVyRFw7bclA|yWU-KRgsx>I=>S@Fj+dS?z}(Nk#(*3N%T7$9*pI39 zVzI{C)F6$+T)sJounW>tPx`bww@m7LvxWP%S(_NON6K*h?$RMK(nGfx*)b*TmhH)B zkj#v-mHy#C4hs46f}F|KhRDWQvQ@?A%5K_VDf-e@LH~^Qoz1eF~DlmgDCi)$K)~$-g{$E7+u>legZu*Kgoa| z_A&%Ct=+!Ho|LBT`OtGFy`hJ4Z&^R<3^s?ip~F$BmlO#K+}MTgwfs1F?g{hWW2y0O zQG@^~+I{y-1b9t`32N|vcbAX2=B%{&namFHCWnsC=q5k1F+)3V)1r{fy}@@0_4HZE z?0Wc6T)ox5c?Fb-I9@O=&X3ML*-|X7j|T6dDK+yKA;T`;M6w|x50e9;$IKkNc-jR!ktZ_Z&zs5=l-#T09;e!#nfq`;7ePD{moe6=9Wtf zT@6Rir{TA*NPEJ=I+!Ql>6b`PKxQK~#@;OOvd*KC`@R)TKi_+v>M!S(UjxwVwz}Xo ze~Vh*UO$y^ZvV%dlG#}Fa#Dj%Xr8vBy9t%Xk?Q9MM|cRqXJ8MqXvl>B%*X(zoe~K^ z4=@MKQp5-S>k7WSSqgqBV4a=Cyt0sLnY2q+dU72-TaxuMJ#?--y zbb5y&#y>Q$)p&*T`9wWRV*v?MS+{OfM*KIMyuRaf48Yo|XY5}A6{HwZ?$GmFW~hPV z_(v{*)i&E!HA2Rr|vBT<2#{<@z%Ap(Ud5cJJK+x*} z*`=*&6f#*{O2gtfkttc!XHpFdrtwCE6*kd5jV>hm6}C+!SI;GHzm(X6xPbMo5}IK7 zQNLI*ofy6IaZ4=web{wdr;Q-!ZJUhA!J_cSA{B-ntMRsHZL`KzjCgjtgCEYcq-x(w zAhZ4<`R(r0VDsS9n*H#S860(zzAmsA^e?M%-#v4zGc09kA)Z{>jruD5UFB%o83Whu z-$G;`%WGl3m~tS!pLlz%YY<38!dfKktGa76CE|K25W4-LT|asxwQU1<%;71S4c<}P z^E#ToQ)|)dzw~@S?BSA7FNgdVWH8~`tJVmCG;K>ZL+H;OgAM!fa1EV(HHaH~` z8h(BygllG3?`xUy64PlszAzov`#0khzy2KZveL9Yv?Wqoyo0+JEfT6>=8Y%vyi;{;kMIR8Go4OoH?9 z(Sp)tSg3<|4=%aRJh~WG)US4`e6Up4aWrGVMb$ZX(axtC2knObsDPG^UNg$~J$f`N%6a6z?YHwb(Shg_&r2a^)M`;#v-6R%+D|>(MA;}W*^sX#owCArneb6Uo z`392~yMk=X3+kx6sX^6dG}Or`u(SD4AM9Wc;28(k^y?3)q4!;$Xyf1*; zhcRIJmZimoTsGk5f+!!&q={l@PdYyCeQs{^c;o8On}W)jM89wZz5{>%zOrv)9hQ-> zopF>Gj*$uv#~8gl%WKY+!pik(LvJ0^er6&!zyT&;D<5V36&)aaQzs!j$KJCHXwBr< zFj;QAH3;5ttht@>y!5>LRj44KmEWt?8@>W*K7?lL)w!M{q;fE?hMcSUXlwsnAkd&5 zPhIFNvGAyNpmkz-V9p_n#WE8Nw$<i)m319{4k1x>mL`EmuJ1|)C>s2Q)FB9e`t3(!jugJjr({*C6>oe+6m(#L|? zF}0wObZN2^||duORZt zUVj_pO3)oj-15MH9wIZM5gncFVJ)biM?&iDKX&EF<-`uoC|^{cg&r}xZ>t42&;4oR z+(+g4p^jF^@@?(7oBm^%UM1$9<%q|t4M1?LP^c_XL+@HZZcbKpy`d|jHmQHNp3!j z>=)}k`o=X^B+;f*CGY2oplhhQJxM&z18x`2`R^b`MdKB%r;WMF^9|kE>Q(8Rer*g? zJ+*@Mm>7{pvAk8?d;Br^)caar-oemY+wJHkYc(7-sNF*a#VZ2rz2SM->>9JErt=Sf zTlGjXlFeqt9t;;*-!_p#wGdzBhDpy=|7q=5sX~G+L8oA0>-1qQ^6Q#ePNg$n3%)X17g!@BEGPqgcWsjhND%ul*bSqqJYIA)Qgv`?rpi?pB(F z0M?0?z%Aj+;SD$Y)Nf4UxS`VXO}@s9PS=%{enK5G>6k~UzT7#&Hpcs65<|vAsMFxC zb`tn%luk>wy-~MSEg=a!H7^;ukLu4d|Q#k9$}vkI3_48P-k6^Ca_ zK$Uwi6X>d|y=!AI*fglYl^-{>3{0DXjp2VvW6z`KcPQ(QhV(bS0Jnh4FM;kr)4(b| z1}_b1HwlphdX6>>$r6udv%1qRAVDYR&j%6a8eg2=rW2i6aeriTtm_Qq+%fdR=`#+P9AWD z#k2NiI)3H)_Hc5%^gG}&X;y=MP8*x}AxlAEcn>w23GbPpc#r{YWz-e?Ht_J*);q3u z+zSPeqoxA`HjpoFk;{HPq)VxO$%(4SZ5k4S^>C##*sxHTMu%j*_-p08cERIfME}Ui z_lQ#=Dx3Ft`qn48fvKfjwfiEeM(IS=$@`{l306slw%DiK>gby)#K1s?TELDBBlrc4 z>FQrwQ?03G=z}Erww=DDQ%l>gS3%l>N+?)46eVHPeJIPaWz|=Bgu;ed3sr*#j}~O4 z>gasklTiItXOtejEMfxT9Z~akxoudCvuKkoRTazrWV2^Ky~|pzPe(n@9RCL&LEyg6 zyAbO0V5nD5gV3xDKY;PsCCkXQ0MKFdBo>X*3;|v7*0X+_GA5Rx)=^OP0MHcxn$~FM z0U%hN7X7#>XxzOaCGK2-R3=`(0In+y72)d^4lZi39Pt2JR{9$@j+!~U%3PSparoR! z=<--5$?)y_Ryp_&n0VzR;|EV%d7K}p%;LSf;XU`N40F>R1C#S`VqBG_pPYc%f(r1e z3&f=m0@E_dY#C(m<{RkVz6luw>^^snL(iXxoMs{=eC_xI|Lred;Q#!@!^@xf-Xw|G z^6!SrzIu3^4}JFdlApb)t_<&b-*@r7|M907*gVYM+i&J)-}$e&bo!hMhEI$^UrJ^4 z({Z?Mn+lXoLx}^mm_~ii-_@j<$Y8tC3ypLfb`LH-Kb8r->E`Lm(REwh8@|U_2)*5j@uvn5BGH_b>r(WR??T?1bs@v7xPtE-{ z8b?_Mbfs71)_idy&%|ul`M-PnCK5fX*UK%XWa{WyCSE?-Jopy^VF+Y3lj;ZXwR0-F zx~WHvoEz>|0hkaf^E#GQW$M#;Ri5p)5b#&;&NQ%+33_*Jp?}{FQbT<;J_jcDjr(|@ zC(SEQ9%42devbS=^3gA!=Gz~+k+~VNuKwYKp*oNlg%lzz-xJ`Qk~w_iYEbXaCTZk4dAsnwX{v z_KlilxZ}a85h%4#nRQ)hcyDS}hrSGSwPvEL(KN;NVSMh2?@uiNbQryH15+#-rTJ}q zz-Hq0^V$O`na_3l7m21*$fV;W5+?bpWJaB`!qWsYwY~ofS&C}#xds*&TLxf-LAok3 zsDG?x%%X4a>ISsAOXG|mJb~{K7;d*LX)Q~4C~16961SA>&e^+HO} z{z6a~239goa-fI)z1!*DzKK{SdeI{cgY4#Q-0*M=?}?Yl<-#Js^n98B^|vqay4$u~ zcQ1+Ok4^B!7cVt^I=1ZI!O#8Q-{ir!KN2#(eCX|uaL2c8BQF{9&0xiuvbQ@wgC zJbuRw!mWh9Pwv=RkdPkk$4o?w{%ZrTWOMns!*~&kOCx5{y?qm#Zr?|GQ$JEl{Ibo& zq0qd z+1x=r>#eqw2~?#>rioX?WDdsXD}leSS_7cI+&IdNQ3#dYaJ*x7jpj-? zu9_;-!tzWD03AljlXYvLsZ#4s*_KgX0U#yh3l2dbF|?|vxdQQ+NhT8xG+ha{w{ii% z5Y(NYLO?3E3g!aWi{ZX-KlU=%yRC=2_6_m$;nBr*%s?`EZj`A@lf*MAk^?;?`?`sx zlbDGZW;~9Wh+&w<;&gyYKcLHuI_$?5Tu6t*nHPbbZ_6Z zP!7;__BkczP;PY zjZ83e;zH=UY{B7w|NYCn`R?u4tqS16M4rz)cOmj=GE9?q|H$|8nsC zciqmZ7hX}77Z;{gAbqtzzx_Z3_qMCrI!cc6Z?HWTYzKidmzfV&U_=tLmiCMo?p8mb zzUcfw-H+|50Ke=m{w`OJLjYY#*wUkZH{*sORXx$fd=s2?DKtE@a|HogbR-2kU#zx@OfF97xd};qLASlDxY*<@mL&@=_|%YE6=i z!$9|{Eb4b}?&g>O_5Hl>Hy-Em^kV;olptM?@?4JcTyEigTn+fE!HY1BN~|J~^8at| zz2jut$~y1wT6^zGU7gbj_ndPRmkXCG2m+!Ypom~1n+C@KW-+`lIy(B!YYsE&t26WB zC}J8#6a-Nb1Vs^1k<8`7<>q@&>KrTWu-5y>s@+{xT^*~stGny@em>{yuC({6u-9Hs z`aK3v*t)@P>q1WLx`7N`oaVx_J|91~^*dKuGkWUGddtUNJdbZv!d_9Z(7PHIIk`;JDFPRtv00hDvOjQu}veB&)Y{8F7nrS%3&TqqU+q zuysKkCYGh@!F#qhq8f5*wNm7|(O%%FQNY=;=K9SJdHxq%;0^!jx%`*k`By&mz#?%Q z!)2pAXx;cG{YnlHG*VhIdh5lu#(yJ0A;;(~H!yn34OnA{N>!3DA}Uw0iNRWnpAGPH zS^PqF*Zp-$Zgi01xk;8ExU%K3<@FkW__z1;&H?bR54TnR4>AES{l0H!Yt&4QTWPpEn(w?B#tr0 zV3NeW)YP3r+oiI%_MYEM=LoIf!q~1xuc}03A6g=sUB*;GFb1VG)*50I+S7P|)e19^ zfiuIdHR4`G1*eB#q~Jsa+i-oY#=kzi!q?uhx9{Y@j24}tRImWsYqHQ#u+93{rV@AQ(1X>Z+1<(>>_f;c3S@6(mvtx_aO49#@Ju^Cz+miKa z?EbVUb|Pxf5-`@D%nX2H!KL+fnHN6&B6r+0#_#^kXL!p$-p~D4SE+{ap$IK&&vWVc z`#@<;X3({8%a0Fte^7fI!`Q7CSbgOBmQDuN!oS`z55Au%R`a_oI7ckXmGp#R8?`rCGZJY16&Tx*6C8=LO zthG%U2)^%uuiS4T2(Sub3{fq_M)77EdpaTPRR<&&xLW+3cytkc-yC5*lS2X7LV>}N zVe-WRk~pSTsZw5Br&21RmMhqmit9FUaon{Q+^!`dI48u7O2FWme>u)7J#P}<83qtjx}1l=)ZS3b>AAE=p-!sdV`4W{{Of_`hgXz#KFnD3QXGVOd44j=HKR!%pW^v17m*>{` z>?2D@?*Le-GQYAl{aQ|0qxYis$mTfBffs`0w7&>f$oB zN|hvzH#=Bb=M+&&p|wWWf0tS-S1MxdhJo*A0X?83<1uGJEZb@wZ!FvgP0`X~jNj7L&88f#%pl31$M*zKo&(M%sV z#^QNSfGiVuc%CAc^T`ArnT$s^4iwK* z6!HN<;E~Jv8~3@zx5D=|zNg7Fh>%sQG3%v}N;P76rRqM9aztWm(|CQ)9nbe&J-4-% zICkpraXr;KirhAg5_f-W2u531_wCz)I0D_Xw<m4M`?Cxi!fmrCCo1G zQK+tq4CMUwPFAI;l*(Mb??KMpbaBH#-z#^1@zZ$R(>|ZM%hy<2USa0p%Ph?;P+nVS zbzzb6T8Y)gB~}-gS)7?8tW;QEStANVk~krbT-HDm$0((U>*;~kn6|nQ9itSC?{clV zcLu5vp6~Ol7k?!`^y@#%*qN#3=M?f3M~0a^f0ieG$uoG__rHoa|LSk@u0Q-!)|OUa zejPsY5PaSRr#H}!jPINP<*kk)fGaCC?wKv|1s4vf%fiI4h?Sk6-zYZ=IB zjDccCoy_!LpcEM@u_ZB3O`M@uO)Q>LM8=|(`+U6mHqB)8wPL1}FpyC!)`Lljh0iQR z_&TB%TS}3o92>&KQi&|J#8Qb}WHqtyxy2B_ZnP>~2EY&g*t?veW}Fe38qcW_nSM`7 zDU!MeDT)nAVyM*;qBx;aiHYKbFic1i_j*$|Vw0q609%f@Zbb6elnB+2G&Piu^|c=hKi<)Y{5XJM^v5slvc*sY(} z=KY(W!%lSLGqo1(U5dDGDcWx=aPu>7b6?KaJa+16Befk7^hT+7AQy1Qjbq$#W3#Gy zHB4A3)rb?zYAK`^C9IS}s$oo}mf(Ae%X1}u^nd>gt7#NeDTXhe*+}I-spN)>8|OwN z#=>f8YsB}k@jd7KYsDl9@A$1h+152 zp|r9_d2OAAYcnj)%&~B7hSKU9EAxxgDpe|_GD#d0M-is(7_`RC*@t4#?-#9HRBJmb z5iFEYD9+w=k?;AXpWJHvx8cmC8~DLr|5={-wO_$6edlYr`rsq5T7{220#CdEquczR zM+e~YV%sE!a+ol?en`KS!NT?}5CsA1(f?(M{`V`zJPdWelu+n1q6Drl?A;)0!2hWa zEV5KJlp@1Q%@7$E$uo8{&D7Tlt=Nd_dCD24VPYvqmdH3GG>!g&ix6t%jC!q9T~xSk z4AoWbOUYi(8fVbQPUL&TI5gJXpYE?Ua(m_48gG8vT?aOvyUm7>nQi`j z54zpkF?Sn7^ES;WXx+9tHj;X(Y+Tpeh}eIf{BFl?eSE7^WiQ9r-*(&m?0%?yy>>M3 zbKArTGDIgvj#Wx;F5{8QxX1rYf+hMKCAS%}m^m6|VpI9Za+lv4nJ>m^* zBr=vL+~%8US=4N|R_w%h7KFp%>6eDNVdR9A0OT?-aq>e1&`f5qTFqU2Qqxy3vcJ{hZlKtw!QK^Z0+P=w$$4nf0Tlu ztj~p!9CyvEH!mENa_N2BvA7P#GI8+?FZ`CTKhW`Sx$|-S(%XKY|Mb#t;en6d1*H%^ z@hCj`5)3xXCy8<06SfgAG}dke0lLaS&ixaF?XcDf|4H<}KN%W;!ISNX7mfj8?6Qas zh@Wb5iA^X7!cmd&G~f3{7fwc*&ql4@$*Y+UeBIPVL}`U;ld67P3D?T3K6;&%hp$tf zTOx_#Z9SNQuX)9DZsGQeBS$;PIxl_J&1j|gvH$%+9++7>(T-NF6oIG6`kJAvN7mO2 zW_>cg;>qWSc-iMo@vjfBaQC}Qn8wwEu~3U)yCwkZHMFOB#tXlU(W!|8k8k?od4Bn= zzsI*f>nmA(bOzRIaMu-h$|aZPw^)MvX18qv2r!iMIXl$ljGlC^I6>!_&;!b~eJgeg zr-XElkPIQA6Vei*+5!4N*YQ2AHUz;=@`6P;IvRtZ3RQ0v?e6sI23=YYo6d2b)>vx^ z>LPW%m)6T`Cs?LclWdHPjq;O? za*woh!i^y@#*JyC#-EKbDW!przsA$` zZGGR{ZM9Mxtsys#g+m7sn6RXtgwJb8Mv6$%iMxCs&#MK(Ld=mE#&|zOvn`q zJon{a)A88PT)Kf@c=H>0>N4Dc79Q|H;d449jI#8@U6InJDn&^Mf6aqlrS+)%FU) zb{L8N_cfzMC`g8o&>`g-EOaIy>i_6-Z{+eym4#BoTq&dy8OmWom{`KZ5XMf0K2A1k z`;}^}pYN{o;4sDD4x4l=sZrKwq%|3aEkbXbB67~S^HLpy`fb1dc;I^*Mzpm!BUvf3 zf#($0vp$|yjPv14~wf?)^*kU^jL{8bpgW7&my1o zvDR(l#E=ap3@)_;3ir3-%dx24gD-*h6R zj*HZgN}n6m-)A*;pL1*)Isn9m#9C^xp&FTu`6ErUO$=1ygvo&n|MKt(-~P07CnKBQ z)2^QPghupkm>giFn5A5cH|{IVEHLr-n|e5^O`=kjaIHjbwM1oMh3d*0)ulC(T8P=> z0$D4?lWv{hm%rZksId*vSEIoyap)%rKnyDFoZs zr3MXM49*T^$@q#bW%TP+xce$RI1gur-M^t6c$%yqaPEd1c-+%IzvK68jN#1r^E~Bw zU&6ot<$K)+dVOV2ug&_JS3czoL%A-N!zcxlBU0BZ?92iBbql8i&#UW$oP@=XaBMLK zW|um4BKkk~!dn1$?KIX>jto)ajGQpBtk)81iD9J@6B$D#a{sDP!j+X8S66E+mLnF+ zG36+s6edLV#ecfbMz!X2&EwY%os6&XwIUyAvc6^@;}K|0KG4pH^){oasa8R)ZfsN{ zLt@;qU{lO5J$BsSoJdoReNSyDvpWN(?%eP+Ch(!Iww{i4L%p5NMONCfEgN_QzGfg7 zkk5Jy4`dj~1r+l^-DpmuvhKYGzI#ueRvQs=-_vNthH#bdIip)C_dL&21a*b!Le3}f zHN|{@R*GUi!1pxS`hu;P4=~nJNR8%x56EL6CAW}Sx?t30w?Ww9KwT#2bf3DwvT zCGMKkn0b?S%EuK3P|jz(5HOPWIX9H$+)$R$Lcl;qlMlQN(cYkbtr^Yx zO4==z_4mDoHw~9Ny@F{ry{tfSH zxx&>49_Ic}-pyw}{Bb`0uODId(W@-Z&h5*aqLt!#j~U~ocXnATBA0=o6C`RX96iRs z+{(WDbqlA2i6J*n2tp^UmSK7O^0vLA?0r@J* z6vg2oZhYKhxcJyxdCccOfywh{8J-x!4+5fENLa19)`tsAEX~X@cjX#aAAE$_N3XIx zw?JjRL=wjb>X6`R#TQ)~=GR_y8&A2R%MRTeCShvyM3xE(N5pys?!6-GiGCy#z->1` z_T*^^3CD;yf%~tzxuiq7<^VXc6!UQ7896D1tyDvIqE(N+uefjwxM32eMoygae=Doy zkY~Q;ZG7s1g)NV1-^0rUWQGRFjSP|-F5(w*XwTbt-zJVRaY9tC5S6M#r3!I1+(^?m zapGFnxq6dBYh9-l-phBIo7_ZhH&p?r^?%BeCpadKl0c2 z^7r>HZDix^1*H^9YdlY*JrAYzMpuL+ZtjxMjo;K@*5hTLH_gw#@Rsh2|78QX?ZVD2 z5QYB67harO}$~Qd)*NWuB4?_=O>DM@e|JQ;%DB(v!8UH zvB54IaGhW+T$zWNrCyJuXUwgK{N9JJ@q7P%mCwzUkCpIY;3*zEIlzxR_YyC?bBck? zA)M1^#^BueiFXzXhsavlMgNbBXq9ku?mqp8CE-D>yfCYK(t?mptocrbhGp)bIT}|8n;XwJ^c7S%^Bd{oXB5y}Cxqa52mD zXr5=>afYvW>II&0#~IFy6?&%dzaw2x<2~t27Bl>(=Un3Jo;b~)eEd3Z`Q$8jU0bJC z*W)>Al!BbExoIrVtDk%+Z2umiE$1>G5-6HwC$f5|3W8N z3kxe<%}DOg41huoZaO1k9720aRk;7ku5F}*Q_93JT$nnQO1(>KHQxR2kMNd%e1H#p z>Kcn{RigOl>QU298JR#6_?n?YhGIV8!c>tPCX3v0;~2M`8{)ASN4e$P(1yV2vBem8 zSTcoLStv)m``<1cT^Qo)o;1yKZW(1Xf5=Y$$q~3P zDGmT(dsa(u-&Jt{^drSQ+;Z+z1r&rHP^!A%JhIHfYLzff_O(V$Z5~}0c+2=2&r{?x zu473)>yyiP3>7kr4raMHJ;n#a*$3l!C0M8O-_IK3U+Y7l(M>W5#*vg&`&ejwrLw)2{Zv zAnOTX8xrHz6f31(k3=|Xv~p#}BgI~iL^#PL^*}?H+lTg-13-*_VJEDGYm0Dgt5}-Q z2Pg#>r(k@zuY`Ky#PGniRX%dh9RK#289sLJJl7UWtgO4f^(nrmoKc_g8LS)h<3l;l zju$vPUf}#hkuzg?rbY^k6f8Yl3;HCNj!>`E;*eCW|t{_GPo zeDI+a?wv1Fi4tOC+d2f&7QRY32a~510~wEzywBsN2e|W0k!RgJ!tGN7Ocyg0vptBg zjSs=a=~J04By@@8bvI8)^uPZY9fTXFVV@m#1fhwgb$IAn*8>gx;{eEIoF`5^^}=?n zmYwRqwCL$ih6Y?|P@kvjCB`zhT%j5!tdwdP1DQaR@jVJT7ug>k$e@*T2=pzBYwn`l zA6L+>vQ&wtgkscnC0wHhMULp+&G$NdN9LS zAvjRW;I86nm)bj6=W2sRy*we8bTcQN6FN*PhKt}TcPrDfKw2MQ%9?HQf z=4Ej&?95sjN}c!X7EU1JLy~PQbcVICxOynYKfvh^-(&)p_Akc2upQPqh2GNPoMgfY zU~*U%^TOUpFUpl#uSX*E3Z-1Bkfins+Yu))yDa)3{YcpyZCm;NsS1)&qxD^5W45ILO=0N;a4(@va6PC{WjtcBU7 zL#wY5P5@&=FeD;g!XByAU}3e_qY!#YE(5~@y&i>doLMc&x}qOZz|^QKJr;z65+`tV z;m`w`tH+CzUXMiRCF4Ub!%z^~5ykcB zf3F83965y?j23%63gIM^Y78BLCfVs)`TCyg$vZqC#=o#LaXs}v5!L^`L@B5GpUd=m zB*IByz3lq&3jIsQhY?xe3p=p9E&`$bh*D1YPdW(+oe;)wed$OJb$T2Co(C7EU_^|6 zVHd20xfK!U>1T!qU~~{D+JyEuqk|&uC2UU=!_0E8Mqf&FV|3ZHfcyMOS%^QNS7gp9?w-BL!@pRp3C~FL% z4c0n+kXqR5kqAePu1Ei6O(AqbsRD~@M|QZA|7+C>ZkU8IxiAZRAWi+3I^O<7DVQE} zZM+0wFNCoudJ8VXmzQ}%*oG*E`ITOeLg)n}gHV*Vph5>E#-;urVV2>^b^xf<_?MO& z!X8M)HCD^L9*NK^ig{_#BkUauEUiIVYI^&giD4IT5QJ8&h51!!5898U(SMm6goBc< zGuDpQHaWQt0HxsEIE>3hS=b|$@W{k9gky;3xj92bdW5}F3#D90aO&Ozxn7S#IIh$p ziT?L16T^@fF=3$tqTXZ~p3Gi0O2PRFm>dz~U)URI>i-dmYY4}X=@D7P3wtMR`xnZb z(f3S^h~rRbkG0PDm$gOz5%{i^uw)bp2gO>~j=XyG+94;;0iYF}6XRdl2iDfpYf8Ny ziO?$sa?VpP7iwXzRBEndNa$~J8CU-=2<@nZPW(^kKc+`rYfwQrDCJtuvWHGq34l^? zb{r-p?O)gj)ex>Nx;h)7|Ipf{{s(fQ7WPPD;M#)Q3jNLakjx!Id(!B?hzj=~`K)vW z5jw*dS7O+s`Qzj`090LQV{*hT=mlXfqzidT&+A_%h9!b0?2omwh=mF+x;I(`S>p@s zC{>TNZI^INNbM1c{tKP3T88EIo*n+={CX!xq<6Qle^yJdEUEu}OFrZ3cg0ID?3E~S zPD5$?CyWe2Cg}AjgyV>@Ft-9p_o8qR z*b0xeC8q4r*ADkR#XJlT^m-J+NhXTn`l6dhdc?_a089+SIWhi)eG*1+RTlDni&AiA zTo&-c-m$p4e`)(CC?zdJh3zR-x)Qy!C_bVFd51s2-+5!)qXt;S$NJumWs5-)GfBvk z%sMYf7WhiDz%53ymJS`QUG!f>L4|{2ahXGW2EQ=00p6y#JILy=HMD3p;EkEPw`v+IsRFXQ1t^a25k%; z78UPYwrG{&I$7Qs!ATkOA7!+90 z%Hk`?s$&uiJSOdhkGBJ0cmOU=i>FQ4Kjo_QwRnJ6FF{yR9)FZQ&s+Q{UJ}polkr15 z-t?xv_)olP?(&Av9FB;pQJOE0=6SX`Vk64a^?5k{}TMMroF7en*wDk?luedCLj1Q>IAXWMSDh1e<+id>s zv~u^U`eRBp+}HAV<33d5zSJ>x01OYnB{BYm0}v;0WnL7#`xS*t(Ua(%upcTln3r~5 z0x&cHg>0`!Ask2IgKLD$s|-I8+{_!jb41$1H_5&d)Y27AJM+`C;KebC()>yG9PjbR z`SJK+e!yJDZ>%Ly8~-(A$FE9Ks|c9GTXjEg^tZ{V-;=OJn_e!4{_z^{Cc zXX|itOdD^de!JavH|loRwhRxrmcl7}-ES8uTgCO*ji#nZMt5|UjOj4$N9x|o_R}+aj(1U@cSd5FL`*1>o(Jz8E&cn4s64BSpUN+ck-kL zaSd3tWRr-;W@Em*P~+U=Iv!3HOqG^{wnBsXnC3ktN13&>&qi&6w-qHFK zYW+>6zsp9)fTiX9ZFm3998U+pU;!>pN$VY9|5)p4Yu3B(c@$0v#e&rC3j4!Ym(trs zK`-H$p_Gf@r3Q?#E~2urh_A1lHlqIxW|py%4Ins_a>1#+&|rvsD9rPn3)6fe$>S$6 zflc;Ro@T6K!ZVEOn9s#oyltZE3QLg0ED`Y9%x!!ycb5M(F~@X}Y&@gk$(!$~X(ug4 zbE5&$dcL$89u_iJGf<5V&jA1gV?`J{*D$sYwtHo_&*_k<7{ymVI?0E_9BYYkHc}Aq zH7p#-@mmQE{Ex*!=M-zoV2QYr$@9l61zt1O-7J*QDi#wBSV%hiebtoalVOfeCIkG& z;s9ScSmj4YS9nHYe~y4aS!et=IRIQK&lZ&GuzN(S^KQ5Mx99j-*u^|tniAnI;b7Dv zr>xnJv@UR4J%;W{EfYj*`ceIg*m#j|xw!9dyTg^XZQ4_M|27^_Xg|jE`JRHa6U~`J zi4g%&VQ1ER+m7c%lcpQm`rl24Lz`_&8lv0k=5)q1jd9~KwRxO&sg8}$Z5-2f$J?0G zTIP@RxviOp3a8pEK?%Xrt_S=+_=~kXubv%a-ueXQU`9*gdAxFDjVp=IXV(0e^IUVQVz$anD9Gzn@L2-ZRvxWyYaR#S_ zOs+Sz?e8w-`A{tfrcL>ZF}!}c$hVD@DC+KwPXW8;g}3`o+GXrm>zw{cLZmc*Q61tv zR|>ptbeSI?Um<(SeZI%*YF5ZO&uUgucZCCBj7!anj%f{Vx~NPSw7zzKd)i&dbenCu zxZPOj>a7dgroZdQYFgm3y{EsCRcC?<&bf$?=-H#4%Y z*9J+2J;$rAjZsP<=s*z9cpl$2yv9X8 zK9J!Xn3#K_EMIqdg1^2r$3_2$gCq((WBJa(WzP9=$DNt2)_iH9w=LBAoqs83`G;!3 z8PYrO|1B2zhM}@clRqpxk0%8cesX-30d2@>@UUpylDlT1Vl=af=AqEz)3tzquV#6W zth=r>mM<9R2>3HKLiW1l_s%W0Pvt)a91jOTHh`PXis+7TaN@+({ui>%Q770YWmIoQ z*4r8LjoXbBQ$Y15X?+Z`G2vd9$#K@fzK%xA-ZS6v%tHPIaz{|TCD74dyzYaNXz zFfn%}Szdi*l(%1;r*Nb#(G*%4zJF|u$9JU+;RxBT#(ztB<9@cSwBEnX>$dyKEDc#* zJ7h<;6GuGYdwBg~ky!i9b@*vEKsuB-=0i5mKa{e3`9QVdJs$LP+h$>`6&JjOmkyPi z-_s7|tIM(CZ_9apWnqX9QE;UIjh?A6r~NvuV4}ZOUBsI_C6tiq>vj+QD_aY!%;ib&M;(<+rK8 zdXP+R{cToi@W|}$@1fl^)q1Y(^q%Us?PtM zFVD?1zu&#kuJp|oz)o%X43cW-K7+<{d%K^Tg%NA{I&1lArT9h8@pI}1=ccm_^N6wh z-1QZLiTE$Y^j@9q5&c7pK{fSLvArn>;JXhPn+A;Hb1{{AB_vj*5|d`U*l`r8UA|> zqV2fd%|YJsf_C#;>*v%szHJTu`aX=^d~Zr^>bEp*cbq>=^X+!8ZxqRG>Vj8SP$aqZh~g`r;5TC{}q+q1Lti_663$?6T_^(-VBi zo2`~xErPY9bLhM=m}G4rx2bxsHDgJQ->lxncV%wpJ-O*kEv`7`U5xO_g@n&DUHBdA z1lpO5wFuUh_r1FU@Y5`#GgW>ncUyBgK$7rqP~`3F!@MfFy8TXqli6~-cMgESbH;x$ z-?JeIf^Z5k7Ou{B|02C@q^o5SnYI>7714D)El%r(#b^3_nw8Vri6yqPTiY7{I~o2v zjD43>xm~xrF37jpHhvcEZnquZF2+e~v_>fx&AT|&Ve1{C??@7ObWU2z_LTaZmb7fQ zI7D{Ynr*hWWxs_i40g6A{Y)+3R~LuSN#{m^(VFiXUFW>tz4oM9S*pt8$7e?P`y1!T zsgr5E?3dU=Y!xWb){;3$W1w0D^ZPfn6BIEDtH8Gwf6pQCy`hh=oMT=E{2%|U%Y;br zJziRy;U-(*+vBUe$4+fNW-XOWmN!J_`Hk?NBOB*_`LXaJ{zi@Sq3n1|OG9{vH@UL| z;Dpkf6_M}3r86*C*t%d7`is378MNFd2s=@#9OxpwD_bH~+buHd3#xQcnTq6WZ0q|; zTDJX2>wE9^XQ7nq=`O~fm=GMa8@}9a(Eh(Q5>JdKRjdC{yW>r90IkP{9VS^l`L>uxW?y# zLFYsTh!g%)PxIsIAsuDaTi2g>cd^#yJsBsJN4G0EPxSj{bkT7Vwsp0-i}a4ptaX^F3qh zOnZmrA-4RF#UfufSSEi;TAlss!XUr3Hq66SMb!&7OFgg+YgL>RK31RL{}PP(p5*R~3p+7%~;fh6R1YP_~~ zKi`Daw!4+I&0xO_i96W_nT;{YLw-|^17GMg0N=Xup@Jh`6U zKS<2C##j0A+~YPK0LCzr8{p64DP9vly6@v26}=Ljw?;WzUx#v!DZ00KQox0&jy?0jDaTq^T$Pkv!J##r855_W zuz#wdYbz`C2U^4ANXHBL-(N1UrhNk2S)?#VbF&V4^~m8x=Y4DWSS`ojmveko@pN1> zKUoX7hXPRBlE%Fgq0+oBEb_jq1-^Y~mH&5onL*uPld4 zHze2jrP__GctMlR@VnkQz9YUuu7j=^hsiV{LpGtJgC<)nM6+afSV!bfW&qn~q}Zmn zx!UY!u2lQS8(XTi_A_r1)Y?u+rs479v_NZTq_>TFZ(~F^M!6H~JY}YSzcI~QYnu)0 zoucImw?9SQ_-+u|X(t-gYq~j}fjo>3O8URBGqnh=FZFs9!f|1w=*r9lVLw<4b1R!p zZsGJZGSIOe)oP-6`&t3DN26~itk!(r=o%A;7X1f>#VEy_Rtl%a0q}%u43(C4ZjI6Q zjYL=59H6q+rS>bu8!KZhU)B84`2})mZT))1iGgmzd%ZDUk$ob|K^DTW`N75()b&F* z*$j1brNYx~2c?U9iT>B0r}p~X7Jl15k7;cE=Xu;7t?)d%*z~-cY?ZG_=K0gi1u*sJ z#t9z}hWUqRj2D>s10Dac@hol2Fbs-V>GpO_Hh@A7PN2Wo=ccnQhLvjjXGe6~aNEr| zPq({8yi>zGHN=f|sl%rJFKM{XHf&R)-O^y3cRA|4`-gBu$LTQ=#S`{|v92}G9_sUi zKEU@}?Y}7h3;U%O?YP(%P8nVr{qJn9_)s;=15tq2;o2-lbDJOXZHE~BPtnHkkL3*W ziFc^ZhNI%t4oXwptjkt#ey) zKr2$~y|0lo0nq_60PfKP{Eau+oLS*%URj-Cz;6BRd`o89C8Z`wbb zMtbA+Fz6GT{74xalqjCCJL?r#+_^qa=p!bEouaoO><4RMVYNBMRXE*@6kPqPPIN+m|49`CWSpXL^2{)TEPtHd?EnnjanTQKP%!Fsi zX^XZN1FRU$r)nAgaHYswSMwxkr=FB3;@1|3_@<#Ux0e=oEC>2^{{oNXhM?9E`S&!# zNyN8S9_1V2Yus*16iCpxjsP_jb1K89^#JeF)jCr>|&b@Jg$C%?6 zGQX^ItSYZ1gTx6pj;m;^jW;~t{vA($#;zQ`2w*LQY(srSoH%bkPVMf?5Q6i4Sej-)=?{JM_QGB?X>G&EH zqj|hvuUSWx~$G=sN#sP5HQfZ%;3HiuP*BJ43{vJlWgiAq% zuP#=2+fbfY%}laHgA>45*0WjuU@_0nFE4HTy{_T&R)4xVDy|jNNsT|Rew;5dTT}Xd zELmX4R=6dp@U_W2rRYActL(u(AJ5~d;VQowe)b@*-V>|%yvdtx)->>ZUJzd67Tf-J zQ?Q0_N@n=Pj)nH$}=090G znucI&iDJzh++ecSQqUHEo6k6-A+ygY-%AE7l*~NeIy2qeg*Hie_gaRZDurx!HMvjc zd6aB(Rt81g6EJ~{leK8?bJ5j;F2 z3w2>{6h-(?*aKnYGKvHNT-v`x|Am7P$FB9C&>#3-SEBy_GqGkV(H)s#kJfHN6K2h zHf|YbF5?^kCw!f8G;Y5zf=6bht&XraJPl_>_)pjcV_{~=iFOGBxCOm`G?z8ul(AZN z?f-=SV0;L2-N_W1k3A|DlvW2W15hY_cx;WLKG^Fmil3h!V%>TKYVSG(%32nTNA)lr z0JsF3t0vQ7P{*fayC3b=3SKl==KagXru*0McxVR)K+@P@AVn#b)#=GV`=lP^{r+fk z^xxCGv^qx<3b_l1ienSQ(ou= zaRPJ8q9f8T1U`&+FM_vb6_Gu-@gFIVCugg?V(8#OvJX}Q-npK~-%hQ38x)Fl1L0Bp z^i$oh4*ngMkK*%k5vsA4-&$p7piFR*g4nsEPWyu`>JvY3$UaN}%zB!uaC!;Qi0b0up8Q!JGo9|W- zq6tx~D4%O8%Y&-GU3!4Kb%9clcTTBx?W2Q$?=9WW*Cn%?_xYaFCOakTjKgyPgfTok z3#(%M3wuN>$r=(4K-%Y9qW}Ft;5+fZE(RGqWl`4F zodEm$9YxCH3$s;T(v9f<0UZ!px%Y6`43lgt;I}7~CEH;uuT-zERr+C2C-^|C8!*}- zrEJ=Ue1%!ykNiszZk7*OYx%M4ZG21*@uT5`Jb91C@^Rxm-WU%AE#iM#@%8Zx`zg@< zhU7ZG5nUuyx>*cRPxD&!@K%An{SqhqdoaukGfyR5Wk3||8bv~KrMsj%rBgZuL8Tk% z?p;#4Q$kuAq(QouMg$b;?(VMLJA8M3&%5)+%v0x_XKgx-UntK|s)KGy(wQ|f&owH0 zE^Zq~dLNa2oi6Ugc(9OwwkhJA6mh_RVXmzmXkKs~#wV_qDOKXWN@R9zfY+H2cSE+u z<61BQ&z$B;I4zsi?DTEd@sir)y)L2!PwdMvsv2g#)7D6SSMeyAKD!(!y;l|CeN;DN z`_Z~sZrYKmmAP~HEA&_r%-m>S39aGtGQDo3#BsBA4S{2EY;W!&bE>rH7CQVj%F`$K z&aEj-B+G2>7hgkLuO5ugE2ry{>2?Gh=oDLhp7q&9-Q!{~RPu661WAOlUJFZ`&DW!@ zYyOET-6JQ1{bD?Q_+?^$$hc(~*jQ{po8clGyAhV|WD!4xQrUAu68Ym%=Z?yVTs&yT z`f*1+9DqWXybxq-KRgfvxE*#N>SRF)V}ra9{eQsf0iHlQ*`6{RR~|Oc)tzis#s?TK7kSW#~0iY5oB=*x6Y;) zg_ko_-F)f>*phTRC0fTQufbLdE9K{p*^-SmHArBI@mR~|#3v8a(;8nH-d@Rrvf_uz z>svp#y%z<-0|SS`nE_|7&c`)|6kS;Lt|^t1vVN}5wmTY}|F0qHTLP8eUC!K$3Wk_m zQnQh+@AN#-GdJrwIZg;5TcLD?1}VJ#{$}>O@0GDi{CZ2RboiG$`-b?OtvI)xrY{_R zdzr5dsE%gOU1vLr#KMri^8w*k53Xw7FwMix>ZNF(!+PcZAK`sREY_@fb*GT+E1tFr#PvX;Bc%JUzga^Y?J6dBP9+ zqD`E3d-NvSf%=&5KG)T1d(-OQ)5!X3IK(uI1jQw~mp=A-|6|De+C-2EhfY1qE9bXH zNuy_XTm1e4&FO-uRyyOK4F%qAJSNd6&;tox?v~>!#~(hfA@+0Q-Uo=ct1lusKcCaI zl>o>Cp@?~ahGEMAcVPijxhJ-9B+GVUpC@(8KCnsd>*M>!p&rxY4Id+=D z8O%X4eKGhhJ=4wB<%{;Li`J|$HPOLCq8)R?OS-~xJO(*#Py--BN)FoN@p2&w$<|>} z@=UB529V2aiRyM|*^jn0>=#Na+yd^_EbSP-KDhBO>$4n+MpUH8IbGy4D`gxcknhT0 zuH>J_tnJ->JwmwMn0n#=*&osTH&FrMih>;Oj(cBAH+Mc>-F%Xc+#IW=S^PompzDw8 z6)E8fU|wavGsfr~nrt*0ly28C-;j6+Hi_cO5Teze{mdOj?KZ1#DD>1qhWizDRV>Q% zfr$VB2EXs8wJ4u>uxD!0Zq0v;x0AX>nPVO2IIJ#OaLEr^hYdNYJ>7^OUyk_xUZwiD zRY080`xLOQ?zZ&HNrW_JEpZeffH?N-{Bz^irU^>1C1QrK zhg?E@ByD2Dr>xf$$&sc*!@yEP8=~Baa0P^mj=&*w(CHL-f8H$hXWuj%uxwzMXdNyW zHRnZ}oy_j$>cE|vyUHE)D!=)`=GE}jR2gZ%a(;&0-<0j*(d+d{^1}4D4FxljLuR*I zr$!Qm;kR!sp?iq`27i_!9n+2T=~E&EhQ3JQQz+u7u(`3@{b$f&ymP1EoXeiL0(N094d~( z;Orn30!I#Kf(A&3|Dzo?IAj_Kj~CP5RT!8ip`+c)X!)tsWDBP|I_q!2F!lHJJ{51&N&2S{OWRF*z{A-In( z(|C3_#)DG@ ztrbX8utE7aVT2$qDy9z0uD<`Zf6X@TQSy%*OGLTwuSK=m#rC46=Am<@hdU0lkN%Zg z8DkfuQ@WN0A=~OtWgHF!^%}8hjBb=iZ7C)5gjCek!Hz--F%}GIJCw_xwc{I{#^Q2q z*Sh4d1!U5_e~dPu0Jd?AWTM?@beb z=D5!Cp}N*F3*O{gtf%ryJk-Re$i<_xU7t z#qm3VnAP`}u^6yvJeJ?sqjBeRHNW|Lb!I-5GT`q5T_?>6oKDBjq?|&)xm^wMyHd*} zSx!{pnlTv(`oFIc!;G`oHyVn^6?nQbg~#>V%M9av#4E`=WR8Ghh zZ*}H1`9TPQOKlqsI?ekf1lyPc;0p6QYFz^-S^9;}&<}8O$ld#N<8ReuoL6a-6%-^!+6&H;~H#njQ;50 zo=wd3#(?(|28mgb4s_>5%1*~JNdTeh8+%*d{ClU(eYN;cTNlJI*$bUyvl^`}yVfjN z?m2z^*bWn$FSF?Kr36$pOcJvM5+%HT=WUOMQDO`@lp{)nX{aqJRW{*<@h-(maJ~6& ze#xMTC?02rT4B(;U1P)*Ik?3#K%mX&pWW~_UW=I6pH0RT@6uWG8sj{5m|@fr%vePj zc_PK4F1HlXgvI|HH}4>Gl8_t^U3ItUStRRwu1$B?NYE`b&r0jU=Bd(rYkzn5k>u2GPSB$zuFUg4ZBjK2U<#>OEU&>w} zMXou(2qZ}*hrWpCuhTvWbmp!NH zNEluksSugn5IuMHeZNpTGk2W2L8~$F-TTmrjGd{O!EgK$fpaSvBJyW!n8B!VFa@LT z4?(;DgC%j$Qq4+tDInco%e;a8#Eb;$JQ*SQQabok6a;bmE7mPYx3sL%>1eyl@6?4q z0-d+YfJf~Maa6of~;tSPKwd~{T9d7^+|7$PQi4&`A~Gsx7yB_l+L zLLrfCrCNrv^y#JDQ;+Bsb4|>9Uo)xOb4q-wPmkg-APl)e8&AWDCS7UEh5WGl)a^j${LCv3bo{ z6K!r@o zUnR5yx>cXQrdF&=eu~i#7LZ@bb3B|XxTp-%%Szzqkzw2(*e4S_dOdXWV;3Wx9}FC) zREk&GX64}gtv`9J%xj*-gk*>kB$YaXYHixDcs_nEqUoPRPc_4@b_usYHmRN?pWa<{ z>;>P^H%g&a)y6yINu&tNYwzlkS?oW*Lio-viI3uI&fD8I`qPc92!JUM zV%_8{gjeLTrT(nX)?Axhw`pB924tgSvGr>y{6a_j%<`~&(nwxO0wtkp-~J0n$s@@|P#*R9dlgu9sbcsr?RYH80fjj)ks=ABW#546T!NDH*ldJb@rbT%Rs)T>!2DP6 zM%4M;H>!2xOPt)la#e{I=s;8F2xsXy-ArzK^D!LPaE^=6VGMQk)bzrOliiGwQ|x6D zc)mij`i@S`iz)8`xgJJUyfd)=dh}O|980ZqNA5$(f|t!z^}8>Fr*=UkALA0p=&Ri?+znzu|S~qf{&{KT%glH&D0+|!L`qx55}h}Mk}6TVt;7Uj_~aY@-+(_QyAF)%-?HME_W%^}Mm3Dv-02ahB)5S`%Y z?Kj{R2q+W##%+INdbJWfm~|q$1(!EimPzWKf&ih@F|P=-13Y9&m!l`?=PurU7CBHz z+QqUnWYYlDOTi!S;2|V%1X2(eHTy+f4+eFmC3sLTu8V62pqiQRczR5T&N&1|3LlW> zB*%lLYDX}mEgXd{FyMwXai*T=<79EX*!}t31uy%q<5e6_6I!&3CwbCx{(EGVxTk2U|c0hJU|`~g^vJ{$*OYLn0if~5*->UO)M-rM-k4==5GaUy7ql|r0E_ny*&f4mH&UVjpsSb5Yhh2a~8BE3;W%^ z>2-7k#WGqAk)FI{eAriD+Sr5O~c&-`yC<(vr?jm+Uh>+Vx5nm^$Yv`L$ui|3|cbQpEycK zT@z4%1QOmSVIxI>AiYxv4WR9#I}B;4IyU|YL2>SAV+x}WVscj_P`T_{A))rvMF>hT z3nX+w#sFDwX~N~c`C{_=U}V3MK<@W_o}rg*B6u4mT+7*0H3S}VT%#Ej1w1g!V8DVB zLz*uCk?SX~W^#)edEblI?(&QY*M`tzk^|1s#GgBO&VJxrJpezf_+(`JRZu13!GgK?Y zQna>oMLy5RucNF(#DAqmgK4hW%XS#V!_DRZM_$bL^Zr+KiXmM>U$=WADvv7nTi=?o z@`+gCdqUEpB8CXL{t(Hp}B#2wbd9Te?gQ&H~mQ;D_`LI}%lfDPn zqzHwz5bmJiAQu^Ym*NZalzkouNXGI4pYJ*DLmy=q1|j5iDNTXJUC1yDU-NL@b8*N$ zgeSfjrowBiGYX9oLJSp=L1BV1`9mpjZz5^}f_{c+k8zr!vR6rXb^HaiG=qV|xHI?a zv(z?wF|{VK3uFga#^#F<%S!!29Wo+ukXNC+YeDVeaVO|w<`e&7HCba#+0LqsSFTp( zLhoO1=1-p;_n4Ah-6ASP)lehL#`Ul6l-LBTi`<5c0M;3o@};qJp~J9vq|-?l@YX)P z;iokMn|kG=SrRcwGc|j+`@56rwY5yd;#t)U4i~REju!Lel6Z-h!QV_zHD~^tXv$3I zo1P|a-*doYNDx=qKI&*gXEO#1c-3)jiJW6DSAs3zG}T}S03kAZ+jpc=UOmMokel;W?33$^E z;|*Ri%Ie6>q5vhlPu^~rVxB@FY|f~>POyVcpCdc;V8AcASA>2&Vf}uC^D^ZH^lSa_2+ZFCnD2ET!`AzozE< z1#7BJloM-oFwcp>zrK`d|AP=tRFJye#lh)Q^2d4ko1|V=Ah~|qUB)Fz?1PF^3GSt5 zspmk0tpxn<+0TW5a@1OVw<&*(FMrj*-mbGL--}Nk_My1g@Z7#lznnxr-O%rUhXP905+|n`{C* zA@VZqOBBxES)>Vn3W@_BU5P z0GJ)ihoUktW<|+KAs4lNvmU^hKlRSOuLqYlypLYwXN);mu%1jz%h?f?Zz8|;z(HDS ze5_r9HMObFO7^#7O51F8?$~LX&E9AVIhjicz$}aVSFRsH9mvt8A@d8yqw}pnE9mA7#);@n2?Txis6mv^b zRt_1n5o@waUA@-~4(y_4%5kP0Ms_|BwmJ-KW28v!E_LR$VV|kx5RkKLTpoA=3B2G# zTM(EhyIRpTzjo8ZL;js1{%%VOq#F{OK`NSZXdiJXFv}f#{ccroRwTQ!X$yn(5M;Ns z-j3IrT&}k(c50Kc80Mn>EB*n8YgAutG3mv~t`*c#V9#sCdYPeBA%*5Md^h z4XfGIZp^9sMdYH8#H_gVAF$QJZa)<$XZj{*8nu`uX0MNQs-Re-omAL?08P1|dXHxE zMpDNaF>wz?4~Goh{F||-n<9s8v(8_}PYpqHQ9xb%fnF`!m(dfh`t- z0ca(;?%A%Ub-KQKF##_OR#)%y*-&i=W*wSd%|-|cAXDi#=_C3qEUnb#a?FK*><*qR zNgPNs=6|Ydib8L)9TLy7-Pnnn9abGA8Zli_2t5b%noNuhJbwHt;{j95YBX=eQ}+#Ktv0wRV#u(IsiSb z8t>O$PNZ%U?zdX`a6cu3>Zdf605~8B&3*`)h-f(7JuDWgaefULUOs##AU>~9%49Ib zw%!V90VIyAAM(dIRyijy%N=_-(NG!40R?TQwk__n+)q}zT8BgFVbDMSTX@+T?68sk za8!BN0tuax<`qI-x*g{6CSHhqqn$9X_)9uDuS7L0EW$W{d+3>Y2cq^4gB}wFMbYYE z^9SKZAyo6%W!-*C1Tzb;EAQ9P#P0_dk~vu?(wJoe=@lFz@)QU`y?Qgs=Kd|fg5u~R z=k_D1shn*WTdSri!RwX8S-UHA^_-cCKt+fLo6ckFM99<3L>g{ddGMBAg!ZX-GolcN zd6cdj!o7dRtcH?Q&en{1c<5^QzF;O8H;zL|rsLCUZ%gD$7b=Dy?Li-MJH)W3YM%E_ z#A?t0ncE@oXL#oTl!ZRV)bqcZN|dV1T>NW3O-xfqxx-{m8ts4ngX`@FNmXozghdAW zIRjb&u9ZaWV~NZRveG3nM1pi*B3&#HfElrmvMXW!@n2tT-bF({g1D>kVzxyHA>3y- zXd1rz0Gwic41uZp`xyVc^aj@sHSKM@JS1Q2v6wa@6QUjGWNVWE%_HsGg!n&`8VQK>i^_*m8jK^&($qfS^MFj_nNh6d1&Mcp5_s#83CkXc zMSwmZvN8u;k;vCfL^^tIq*2lV+#<|Cecoq!gp*uxmld!j3NbE6u<641;u`EI2nl(T zyFp&M9-15NUk3NUGTfn;$4+(@ReRd`v%-W$8KshFzTc=ER%~^4onk^;fPR0}h`?_M zYX0ehl$GOO2bN^BHgWAiq%pO(X;P!>Cul<1V?YA3@P3kA6??xPu58)+@L|&-CCj{t zu&bzlFlxN#;Xn9^pNR7~O(j*a+OQC$tO2&lr(t@$*6z#M;`=6poclCa(6+WWkVKUZ zS!ErE3q6K-Dqg}Ta8Tb$CPwWms!*Cr0`((dT4L)wQoFVDEQ74jF;dp<)9!7Dbldx{ wK-Y?&_xsq%u5n$e6VI_;qB8RzxXdOT_0FV~3`O5h8UeVJwr@*|s88_jTsHist2;`vOWW83Bd zRpZDj&VqzTgmR&;_tL-6_KiGf1xv?SD52NVfDdPeYbt0*JD$Z^9f*yKL0uN2)mkF& zKLaIOv^(S^q<5dh;9`uR|GuaB`v2YG3fFhz?5PnI8phvyer^>U~z{+iswbRqOq zKGZ4^#QMix=gY_KwU~G@%oO2@7!r&}ADDRvi(Z8k#+WV9E2?gTq0ZObS&~k&hyvVw zld8&KuoO{Yq4N=c`~Ihdl)1ouN?;q*{9De(^75eK*BZ@e_iKJ2rO?rm^AE+`3ScTI z(s#~&tbSNhPJa-H60Nd-7>DkN@gBzDY=Cszps}#(T9~VeCwJlbwbY5vvO0ZeLrEk@ zqQdr8t2-}0^;Pq_Hci^hDU`0F^a10Ckr4RyDl-F1PXfr-KNX&94ss> zq0ev6Oe_A$a$tp z9*k`B`;cu|a0D!@bF3a0=Y1PO9GuC#A=`j2Lpn!kXJ{Ok(bBH#m^GMH)u5A^YIU@aP{@4DmU?=HLU#^vM7JP*MuR%ZxQH( zAG^-U8{FG(da6AzSkrG(H=(=@dQuhymayN1F))?ok(QS28=5THTOR8e6KOu`&snek zo{)q`NO#_ZUNNf1I!!iY(eKe~?%B;|am*?8fL&nXV^T zcrn~I&g%_E?aqq{8MaVDZ4He#SmYe_NQONhP#i;3OG88Vdd)PJzLTaMAm@SVZ@1zm z=)A#RsVT0=UDzkFQ3z>_M$Yux|5`9=f^@Zc4-G*=Ro@fO=A*l&ohQLe2RaXHin*OT z+*P44MoC9XT;6@uN)?!L8(ob>*Alw(iJ)N}>U0&lT12Rob@#-JYRk+U{}cIUXam*J zM;KaHJsBA5ABbi5uW=RtZiH>!7w#&Gb1~A zkEf=)&$Fw&SAXrjWd_v!>Axs$KWx!Dd)V@z=Z#f;o^@TIdd&+rP^WztGNBcTR&%8Y??uJ6eAh zEji6O2D^&B!wpX}u2~<;okWPv&F%j|C;XJk{nrMKnWjK9oOKDM$GI=gWKO)Q3-!d6 znYF_=9(hErElYyeMD)O3(%Ajok57o_pBooGuGcR$HT-xe(&QUT{sJ%n^~b0H`JvFG zrx5*0ht0q>j7jpvh?7}v@ze+YKcvwG z!Pb0WJ1|-UhFbKFis)V;avAN3ZMn);wyjqQy}XQ7U!Qn6GT~sYr)A7ccax9LcD2Vv zMfkYAJIu^l2#9s=o5%iESln&Yq}Q{y!HJ(Vo)bE0&HWuk`}fL)9?4;=@C)$zuDXu3 z-1+>Y-Tuj`g{woxc*1p10NFXy$J4NV9zxTon6OixzXx$61iCE*o`-caY@CBR2HL6Y z{L#^?U1lKUXA1Ar-HO^ZC%#$czDTXUn!kI3qTT%??YpFn1YwmZ1vI-mK;@q+1O)n$>`fT&FpiJVPN%Bt zS}1)weId;J3yRr4nUmmbB>Eu)U&GDd$j|^EM)c@43Pwma`hLdzSjVM9R5;){-bt1l z=3Jh=>RV^aq5d^JhC+hZ)AAhVRkp1@N`g1Ho4w(b>yxn2#5R11mV%4{c>nC4_m4U4 z_;xS6P3NcjE~SLPr_NV} zsfLPz>0|5L2`J7EK_)s-UH-8#{JrLehQ?YG-6@~wK!cToU!5JMwxyVdQ6IlOLHXvT zqNv>X2gb!0qZ;n6Q_$d_*WOdgu(MOKpO^Rh$>W}i!DMwBM*kt>T+`~CD?z~?CZ>9@ zuRb=4I3p;RuCj&-9l%$#!k`D;8L1stgpO`K@TD z3FF=2x(#8y^;os!cCqUAb-K-Wh9q=H-yhFe8a%ScMOr-m_!)NIbX4GVLF+7JU$&kN zTU*bShsvkmkhBq+0;)^HQc-2bi~{nKb0xFaT@KjG5e+~?oJ2NQ*J~-W&EqnYoXs~b ziqOQ~e6VESlPgD34A832{$$urYRaWZi#O*=U3Q5Z!PO92R z9{ux5o0$}+T#m}-`t>_6zv2&Wy(2gcB1OO_O^Zn2x4SI5r4!)UtW$l zITOZSjk4yxB60L*AZ7}VR&Kr$*KPg^>$t#&Le@X0LhQCrLuRZ2DGzv};zaBpr}8$o z5LP+X`JkBM#%EUARY^t4?;*Br_(jHe@qz0`px|ECiMe*c7R?Rz?ai~{e}7Caps7hh zmO>AY^-(f5oWN>U;g}T;T$_x<-1?@F4IvSOmBj^uwhR5P&H$cr1Bg$vkwi`-9twA} z=i=C4OmF{6x5E4|QZg>(gwJ5%%0*xT!bK6%J)47wiE>0$RH`}65JF!`Pj@qJk|NI5js{RSzK;&E zuy98#{lqxMFq{cLe1Q!g9nD5AJso(hR%gECACYp?lyV><*i*;XW5RU!A;?U@K@K-R ztY<%pq~8YF6yu10ODU-wB?`c7(V|!3-;-DSzE3-x;;rg{>jvS;9C}^8dl-95)=EK& z1^yq9gfo4)?zuVB;)W!?BN^i9(%4JKR57K)p!W{4 z6*2xM{O=9$q+l#rVlz1u&h!S9U})ueHtx6aQ5%LuCY&z+i>9hIUy0OoX9JZ>R#G}| z?_I)u5W4$9Ckcn=KyJUeQexEl>MF;c2Vum%U(;dz%%+D|pLEj!O&T^PrurMSmX>p; z8Bbp7vF<2wwOd6W`%i0<2xg2hEjP8Lm|XHoW{ZBo{HVGjLiRNey3w}mD(gEhysch0 ziJ|iDLw*Hgp4(~bk6+{S8PLg?o7*LQ#mezniu2i?pY7k9Mf)|20S-iYol~0wkCP*S zj(nWy{D}qs@vO6J44ik?to3KV>4noawx_WsN3Rgw-eC;YtTR|~c8lp14HHrnbA9Dg zAhwz`KImMx_91`F)+342O)%7EL_UQKZFlQqmzF}v@rkIWs*Esaj4{7+9y6hHr<=4agl~mC z-&YEY3l8kZyDlgg(;}kdtpn?5cSl?9g9!SPQ}LRX?f;?H!a~jEBdi?*a=(h%A2M900#Sq1sv@4 zDMiJh$&#PobmHrxJoK!|>OD?h!z zl^>8&k7Y-EBQxl}fH6xmJyQFawTCKh)%Rij2GLixt|n<$_SXTje3fjE->ovEFO&Uw zs>$s=M2mUNGq6nxP^QFyudR}RPCa1k*X}4*W9T#gP@db#l~&%!CTp2;*2$-jQfK{d zS@{DbK^7Bv>$3*l-oi679{OPClEbna;47Bi$R{X(M8Ek+u4okgDB#12MaV#4nOjr1`_PjAKST8Ye@OcSFHoQ6!t2&w_};OD zmVFHqmb@$}c5rxna3`e9TOqNq>UxFT93Xga#rEGfZv!!Il+ghA8q08Zr>3Wt&<8Z9 z^%Kh+!lBK+-9GVY zu{0Kx@Q)9%_W!JLpWxtR6%swz_jx|f#qjxmPd6{9Ot=vKdstF62q*(7?bZD%W^8GL z7lN0E(KxyNB5+BVC~T96yZWpKg-Iw1KvdJfTmcyr5jng3Kmf3I_=%Oin>MO zcWU;s0r5ARX-D8HSRyCsmI>w&x4aN2JyST6`rPdj_!(w0;;iTjuwbC;PDfu>AojAE zO4+(hF_%kkb&mGtjvx&i=8(BOoFr_wO(P|M(8S-WcW~JQt2WEOdUyl7ZqL}^c87c3 z3X~GOBmwE`3~1dNkwEKRsFOcrT45SL&8&BOO|j&s-IGG#>4SK$f>v^CAr}AM-2Qm^ zDNnbB5r6{s6m;BEU{<1CsQ^)KxwFBSeD~+3DMj_n=hU6%{a<@OaToDs*kkKbeEPZS zfAi?Cm)91J8Y=l5GrmwiuIk9w79{061lo#mT{-VwHT=8kFLfRfF5Neys; z?v4i1s^V^>3>)f8Tg;%4K!6K1a(7%f{y+}*A{c|QDl$cNpQ<;h-ZFIM{w(b=n9HG* z8*v3IdZ9?bwtq6-QQo)v`j zR%5l0>EKsr1Q(R<_k`Z5vB0;pM}HYh*t(pFzEQ$~cp&nQ{BLK%cT7-!bLXk<@|UsB z{TbB@4XKj+e~W`k_EpHfN+*+cA{Yxq0W!J?~k#WQwuuuY^YMdDWHimgNF> zcQfmfDP~9ScQn)HtO(#dvGjKaUc#>{d+7Wfg@zY;t17Jbrt^egYv{sR*GK1WGs*kS z@OphPJHdCFlDKqld0}~f{h6ZiQ11C`@ZXAW(T}j6;oSeN|NXfh^a|nrViG*N<;=D6 z9m|BmZD08D$CZ7*C4EBY{%@bsbD>+a}pX&ntt2>-2f-O23WUfr@+>)DrO zq&x2?-t%aRmiKO=-O;T%{QG#PAUgzU-{Jm+-GR4zCX$RgfScovr zb81666Cyx4%j)o3|Jj>+x5AS%>v6bxdEZ45Jn(Vgt=_Dv-O=B0P1b(y{v+_Q6#+rh z@@=le``)=UETxWLu+uP(oHD)!1FHIey;>+G{M?#EVye6S-nyCY4)}`3hHF`lVT3qs zM)sCF@ps!=#TI<^Dhc(`0x}Mfu~PTWSb%=`275>1&fTyu+zH$Kbw6`}DCW)am|IEc zhdVjsM*zTPh+!ugaMY{YTOtmvN6_2bclAr;zeV8o<%3@hE*lAdv<40-Ab1A=fDwxT z)}5OCzaL(PUt<7-1AYx3i4W|r1-2o3V~-y;n)8FpMY_DUSOU~ zGp{{FYk-Mqe!L7a?zUw}`00~uNFKjbZUh@RjWfAcxBY8So1;P3=*%d)P$4v}xWR+x zvyNa=ZrV#v?GqFUa=fZ+T^b?1%WJwwHKI6+;`3{Y9+wjIr(NevQ@9<#T^0yG|0(#&NX%1?+Vj+-aVseOTDSH-y^SvbD%S{(C;5O zcWoQ0cJya_v2SEsEc<|(sEuCY%}=j@+AxJ&ab>+1=sY~DB?@I`%iV7fm%jp1d2+g7 zOD*BP2Zpb-i=LqW5B^D%vU9{e?lrN8#w^b&D(U$z{6QSNx5qnKF^?!IvEATUZclEh zJ3-+(MNY>XZz_NnUYofvtU9lu%d_yRjy`PM6CFp$6-vPSNIT(Q=)Q=6s=PSZSp<~- zldu1I!=c04@bZT*8S|-^UO++P2eH`qgpE*V4BO1SJj~~2e@Vs_Sa|sy#CxUvF3ke2 zI@)kCdTtN6aSUc)C5bdXKJ3byTt^WU#JbugkKp94T=zwKf$X$j?VP$%lG1*^H8j9d zq*@M%eJ_WaOrn_JzLNZ6*uo=WDU)V?ss5uLc}2Ld(|VI(tLmg5S*SaC$Xt9}CT*mS zs^ZnPmj)V*!sJ<8v~QCA5^_!(hhjAC<~H^;S6kp$xR8o2R|g*1(| zpG(xGG}`oW$ZqRMZt|_N@&&>yOYJhu!JJ%}l?E71+;!3lbZKVbRJBlPhX{@f*{}YN zGNOAYv(NgSjYO<0nR2nWVk01_-QNZi674nov{>z>P}TOrqOb9np{>>aUZf^B2VC%R zj>>-MDT?#jTS_%auPkbjY%4$ohKA_ASJ*wIk0QZ);Y^P`* ztHXzVcjonev5tjmtb+#px?pXD#Du%RRp8qIvjx5?D@g@FTduYlT zc)g2i>^A9#*hLx*hO}H6NlOC>#=9C5V3!4eSrk=3FRz@uPDV~S0L5jQ%98+(w)D(j z60cnJ>}vOBd|8w(S;lwL#Si=AT+Q$K1FV`vd|-^(RE45O9TldxzH&I-MQjpe3R?)O zjefcGZ%JB1dr47+d8*7TtP&qM`NBoNb`zbN}U>pWy4DUY!aJR)Yyy8~VM_?|&yBg&||OuXjQ!Eq;(tCcBK30?}dwJOgSGxO4oH#E&fI>{0uJ=O2k068MhGS)x14q0fZLDGXm-s7a5?U35h4 zm2c!onUf~U-XW66$fF~2h07JN^w8WX?$9+uKiUpk73Sop;MX13)D}fu8MGbJq}a_i zxLHpkB%$-kD72i;Gf&b#PuBHkf~2e}WjGl7(GVVWrf2Su8fHmZlE5>xOwOas(dyli zFgG_NZx4u1z)i#=eA0LNY!42U<`QpjC;(6 zN>suhWoVbLJUn?X)Q+m}^Wuf>>j&*HWp6~a195teefLG}_otSZ)IxUj8%1+IFNYPw z%c#2SQaKz!k;0sGOM!%b`$}av@BMd1c^(G*8{Tg}RplB~RNGlqijE|>3kQG;rI`uw z4ipiu)wh(e7QqFb>$}07%MLx9DX&gJC|q=Pvy_qOiZM7E&z~|&=D-Q))@F2)-BzxD zOuzX>QC%h0)o1VB%U>r;y(b=X;yw#-q!@CpiHK46o(R>O&|GivY^K zL!<2-qyBR|g3s~J7crT<>X6nQ?h}Q5pgI)nWoRaOY-(_H)q(z@Q*!HUwlOHV)@)s) z#3tm+mGl1dbg{~d_%?5W4NDn~voJm(A?y|;AIy8-0iUn+G%s>M{XSr}ps;;U;JWil z$a?ILx~`#uoHE6dr3%-l!+>7avxB{&4;Sk6{`(Y%ufb z{jzK)iP*K$TMqE@Bx$C}#kPtMUE9HTK&iyP_2iS|OwiI{>x2o2Y$TBIkUvzum0`Z3 z&kI&!DbL8|8y_ZL;?!TiNDA0Vde&Vch9bjH?BJSNkHB(Y7ry!c2+X_;>U z3;<-%5+jFiy+R*#j^$~iTRn#Op&JuXTLn1cJ#gnu6iwPMy5x++Zs0c=CFDMZ>zqY| z&aE>KVvly?o46X4e0RtzYK#q47`j|UhtWv$W_y$sA5DvJLx0*?*(rXFB%r-_@GnJY z!j|DSe8?N=an~(F)#5I2*`bXs(eEkx9ly{}!m&x)vmdHsH4IqMwrfj!tt2=f#dLIs zufFN$_?^?7Lbp!4y{gs;tBjsog_EJO2s8uoPtDuMBs$6 zipGVG?>>}VRMWN+_|6&dh@#+`himH4(-#(fG4h51SFlC+E=TUS+S2c*pW@7K4yEF6 z7;)s7Eg+ZdYoh!@UZ!dv>IYucJdBFpvspG{MxAMBApl)aoaQ0DV@=?W)VVja4Tk<# z1QIuMsmv@Bn7|1w`fP29YRtVz`PyBh8QNk*-RrX^POvgEp4VeM7mbq>rQdcp+q{@_ z-x-Nzo0v>a7iNzs#P4?-+~F)Y68m!Hc5)0$p&&_2T(452-;$O(b+ZNou zdq>3v15f}FWp5q!s(m40U(D87*FSi-*j3_~i+xPDI!0r5Ed!Q*NUABW0xtn}?DQ1< z+NRFq|C@JP;F;513g#e3|mdI(~vQHQc(H!9x*3ev;S-sI< z?qtXRzRdWOs_bLCmA>y!jQutRmrNXsnWaCyIK^+iIAC9Jy)i6O8)b|w2C$bMj5y`k zBo{_!x%p||#68I6%h8sK`9<@%N`#G%Fd-6AQN68O?7xQ!;dSc%*e!bV`ym%5!tv97 z1_^cJCDk;cG6VA0d>3ika{6Y9IVApoKGON54g_PDaBSX$_ zYk1u4QuhUv?x$ssZ&gU4CRw1H=acqbJg&1q3z4b%Mx=gQhxgQ+~{BRxhy};>c6=M0q2?7@XgI6Auc*G|Hg1h zn2M-hc@}`m9`k-LZY}z99gebEt-??7bKQma^FGX<(UAJh8$WLeBF;f6U~uWr7?Oum zXh|q2j0rONOT<4DHdOkE(dPu`*4s7ES)EiN-NgWJ^eq|?k1MfcKqLTn&-p}kZIG>c zi-9ElH9;n_$gWc#(;tHA(x{9O{P=_IdVf<@2mEE&wzjd`soxt-_b6T#bh$%bmI)3Z z&hXsl*#g|}TuW1W2e$HK-iqS9hl`p_QVPh9*E;bvLE2P$0U&g@PbF(i)H)c#0Puzti7Fbh4v7= zfs`~=rf6<^GO0*E~K*~gIZ8OE(Dy?wTUdg`%`71{%HckD(o~>z%j9`@RV^w2Z z-MgC4Gpg_k`tHMTN1s(y%U8fLM^dyWsCX7SQ^PncGkb1b=}?Pbaq@wy&HjB&N*d!M zUO>{f2xg!^ccoCZ_-Z83c(|Na4E>lpBKtR$d{pdPa=ZzpxEv+2=-H{OIZQdXHxtjK z;z!LQ-^@IG2spjvTmSp9$1LsiMZ>L@N*oQydhYQ)_$LK#rZ-jQg|9aVceg$@rPknF zOwXcsc}P;b0xrQCd)w2^BC2Nv6NzY()~(KaI^cw;PwVY}ayew}xG^+rRl+VKj}@}fxj|kD&`%0LQG0-kaXz`0*SUOzEVJ$>;dYCX2t9A(M|bQ& zC8?srxVtf3uVeae+q=M#4!Ciq1^fP`244|VhR(Oy_|Eq>@V3^>_km=eL5 z2hYx;@i7E{Sr;FXOEfEH$H-LctN&V9be%4I+cHNh3iux!)6G3%3D*QZe>YYDe*Hs6 zgVDVurccvTF$Mz+S}uGYw3c>*O=l0NW9zYRq=+rp3rkaDgCiFVxfUjECN<9FwCrt%`$F%4&Ut=0*Y9yk;6^P(Hq zp$U(KLW$<8qOWI-u*FNtZPzAEKI8z&j3w7`0g0T%Y)tPHue95Oh9cUW-eCKMgWYUv ze!|bVj*W)Vqp1Mz87wVS0)+6r&-L_m}x<@~9lT(T8=Cxd+HW~AkT6#SUua=7Zia_e7K zx46o-vIE1^Oz3(|Dmj?x%^PlAWrml?<>~3}PIPsBB0|E1ECQbvpcMUzhFEMa3fxpr zFYFld*+RFI;*sj!lHlcpfOh~ZhMe=JCBMHdQj&>QUGK}F-&(#-jjzd5Ah9#=^!|OL z-Xm5q)L&#FZYeY|h z{?(>XG!i3*uKjl?W z8V~Ec=AmKgI2i`aG#}Mx5sXA~AH?l-iR-TO*4DcfO#2;u;f;+n*hkmQl7vOCgB!|B zm+0}?#IH|H%=&p@ZnjU#jd4W`&Bvc6&Wm539j^K%GFY$rc~9={Ukyc)5ViRoXVP7b zq~&tZ?D3abOp9K^7v<6xo|Fb>y;aq(5TwladL!?X>nPYDf3Jq7w~kZ`5F-pFTar?2u#FXxXJ z3jBZ*$9VX`pnpQ3ZTz?SQ7h;n*JLMRpbRP;~a&9p+3Zb9w&lZ^n&B^y@O3~ zE#AOb$VhA-^o_O|*D-b6>bwh!Y)NHs#skp!cg>X@F4M8Sb9n#`u?zQ@sd(CdpnO2L z8fWlO>@^7$K~HG>b2E(yXdzNf;X&2RYFsAt6i9Xf;Jeq?*KHtVG?vjmWj^;{87;YX zb;&~#)~Swxs723_UXb!TbAAfOT%WRA62jNPQbX3AaKDStKYPYqKqdn22jp_&=Sav%}j)BNWM;KU~}iPRSchD;@jCM&$xPIsS4n z7igp7Nx*JCafPMiI9?EjnavoNJ$Y}l?UxmauO^AF5Z54GHS(%?$F%|xFLQykly2}~ zKzw2_eVNl>+rU{G{!`{(6H(SR)vP;OT&g?LH^j`_T|~mI`gDwo*SVeo;aNQ_Tkax+ zRc>pyeAVrbF#3{Ch;&77_vvVuc%fy3fo6t)AIWweHBf_eJb)y8B9Q3*8FUMd*y4Tnm0ExzqEg58hmY?SB9gbM#`^j*x1nxjEAbs^wcCbemfB5@9Y{n>P9SS zf6Gn5O{+jR35oyX7FK;|>ih1t8+p$O%q~1@+|hFYwgfekKBmD2`UFfs?igd#^Xttr znsp5#pFj85nV3UeCO!Dw!ZC0D{P8^SC7x|rbSYz)@o>=YDue8MR*T_yEucLsI$O5m z3*Fk}u@(n|i;HKqix|8#2FI&Y&Sp%=AW{o2Z+zM?uSQ)w3vd-yqWq^rgq@yWj2-$>`a$(zi@U)M&sG_9X3uNoc;>L1xErEt zf#hQa2Z%785TgfvsRL@>IiX$f84h_Up+QQkdV85{5;2vnpfmY@q&5~)EhzglEF5P( z33D>Cf-D!tRxh1Jc+RJWaupLVJ*9pf(qu#=9nh`a{tZaOFL}mQ1$dF0Tu%|Q2H16x z7OxLwEMw0Y{}H=%G4j52@%G59_=qh>rHek2P3R-0Zfq7`=bm^rbupE=PO?Mt>mzHm z8}X|z_BZg~P*97Ix@+(?mdeYK4AeBEca(&D?F7YRvqOQR1QGGw=4#!`i#BeATjRkX zr%<3pTN1Ha&CZaNys|}SI>YFFPmG#ALBO`uxE#}Fm~ zso+c^X+PAZ0KH}9?OsxRII;i$F?f z`H%4ON?vw$5|hUnj~}$(pn0d3cEh5KQbzvzwaN#U{Mqd~A-|RU_#^mmaVs?(*5SO( zeL0i48vcWo>r&dttT5ZsL)%q+c6uZTlG+ch{!s)%?umeWRw*0M2)-+ROushkuQC1k zsgsF{rnqpa#vSscsFn&sqd%%y2$n!f(mqG`n5>0EV> zS39m_OJ2u=hh)L%5e_fFKvKvvx6w1i6sK`72o^xBh9Jx^NTxUDD>t+%L;``gwupu? z?VmRSyt2-IXK13vcqShfhSqvJ9`i{X;7a@8b|NVDB(cv%)h8{uX8S?#*b&a4mUW&% zZ4IYTP3bFUxaYHW*OA7z{(!955EoDJ$3R#}<9K#m&=|jSjk({2o+u^M8k_sqviB6@ zsi7ql67moPUHy3&2GZ%-9|mbHwD8(58})s06O!|C1d8${XfhU`pYT>d<&al2K>p%- zEg8YU3?e)*CY<3`r0FBF+a9dm|6Fn8D2Bzy7+khRymTxXr=^-zQUCpqi}Anz;EvB_ zlM@S{jvEEm3;xnrQTiIwxygq}{~dxo=~;wRYN8cnzd=dG&WZKCf$GKiigiIbT50M2 zc$|6JRf?7;V~W<%8kh5hop`S1%T|VbhcIvvRgtO1+Q=hyG~c0KRt56!!PK84d>ENy>AnZP9%> zp?q>@hh^V6dhf}?qgi8bKQ&mj#7sk8kV!z#JSx?zdY<>8X1?$nXkIfF+QWCvU5Mu( z-m$jgpa(?y|Y(Ecxnk<_UqYsY!|Rf4^g@;Gnpa z5%ATU%me8+pN6ZovZLmH(FaL8)cNN_YTg(Nj;FL({Sa-hD_kfDAl zzd}z;8iLW^p@%HLW-WqG=S~|Jmpak+%T^hQM{=>17_QSNC!5tH7N!=?9MO&`(q?~2 zy(eA}acW3GM%ww`SdV)hbf~>{%q1itk~1>eTSwzIK@0nFbn*!QTdAEXGVlD4Uw<&y zv;o@crjCIZ#oy}u?yN7uAZCYj%;yuVtIilA*T`Y-Zl}z%Iv$)rdt!TWqP8*ptE*N$ zDs{CH$K|Dl#zDuxGYopp8s#!?Y4iX-LxIU_1V~?EE@_x}FDQI#nt{i#E6jPX*N{fa z_w-G(c~}EayHyJz|AI?vN77HsQaZC!ms!`^8yKr&Rv*UxGP?SlX}rgNPhZtL;!3V`Qos;Vo`^ zHH?8nMgK&E=fzYr=cO{4*$Ypj{S5GB1OcYFTGf&9jnd!eP0BxcST#Ky5odF zz>UtR3myhD24q8#2^l;6+cbi$yjhR!nBLHi?`lI1)eb^`QW%Xfo5wl6yX`+O+ zT5%o6Hz^aJ*CnN)&hXSfDeYMrU~!A=qcS^g!w(LXqYimKIm%tnOzY(_nmq0Q0q^6 z#S37hX zs;mgZ|2#A8HO#bNC`QW%pv3siGCurVAy7eki$7gnG9xS>?UOq2q=b}Zb*wvf+z$1U zq3I`9pOh1<4_Rad5wBuLQB^(XqN(jdoT!-nIT>4~BbdjNtjAJrNyv0aMl?A_ti6E+ zZv1sA`5wHGH4PKrr$njD^d6R}w&-hyPh+5{YnewyeAGj(ns%}AvY5jy-Y3JQwxQ!200$&b2@);+Ha>AqhG7V zzR)mK+G8xXga}aAbx>NnFt#i^IDRWK54$W{_pB_l>N1!iHUu7ItzPxk;0Cer0VPtx z5g=JTq5(K&3LhJw1`A7}7C*#fP^%rsnqF*}7~)chkr~jot(`2N5?q^CFa6%q_)SoE z@}h&WZAC)eVjo4rkQ#B`qZHtQbVO`R?qWf+ewLb6yOI4Y^oM|M;~NhA>GF`XG#TZr zkFVG!5HvhI)55=~e46XkI0HR0&z8Li+IM#<#+QGDTz}WpZ#uNAH47-TJfA%~qspo> zFkenfwS`U>Ip~DQ!x87F&a5l)qnBqs4o$)2#d}xSA=-n?`8^>m>$iFCwFx2+s$hLr zm2vQe5xS=9T3~)Zdd#C<13$p0N+_sAVm!yyzBceZ*G#s5;lC-Ec`Yqg3_Gl#<(#&1 z9xR{s%$mlK`H&>}@|$g#@Z5J{a?|}+nWwJxeWe{eq_9nwd2;eo4*e)(NYr`VaR#Mx z^}rCaJKzAwiTCw~`=mZT{$S6Mw)TMTvv)yXICbL<+(`^oXZ#RB^-70U{Z2^|&dJq=0wHgw!HLSWN z<8x8++G}mCO;hP-9p9x+MX9Fv(%*Ca+dLC4{>u3tcmE$-rX6|5kJVVeGVja%vVE?- z)kw@mXsLK0BbEWz$8Qjdkk#fx=*>5F3v?0+`xS-&XUBg255-KDE7&s`j_J=};3026*`$mlkHI?n%4nqjm{O z&#Y*=P)13OLF&$H7HP!K?8}?{qh)i^_qgtrD1V!az4>u`FARtgLOPxY-G>7%^9I0U z$#khd%7_jr{C97X9&!yoI`Ddh^0BwtMbr0(EZaMD)cgw}Cr$087Q(Jw2e8RkA>geN z{G2Hydg%N~sEy_x{2Mz*Qy{nuqwD?Ym`KG26ukH&N|PZ;mbY>3X6Pv-8)FX%cHSlF zj6*VsSGyl$ATCdRo8bp0nnrIFycg|(B0n1pH2#Bz*LC89@cQNs<}dmX@Ift`BIMMm zjJcU6?R+{5p{;MnW3QnUK|ARRR96bo-CmK>Cf|k+tA^A8@G=JYao&xQ8XPDrM*B3P z36M2iwWV*F!j|?`Q8VB9SJvL39lm0RA81{6HH2Qk{VOCJ`&AqYpD44f-8Lf}U$>Pwy z5;V+rHn^oug3tWmr{g~xgN-cIbJk}skbif*60%dC1Ml;4Ir^3N>dZy4kR7XMU85@H zVXJvY&aDeiSl0G!S47Vl8C@VIpj>NH=%D-!ofy%=ha1CGZf?aRLKYTD;ML;*PLsJB zsRTd-AI4E|wR~lBun&(L;}#q0+#iD>e@r!>xDYdM{JFI&Ij2LW$q5Le(2h z$S2tV-KZQtX9ue63z2pmN1JE)=4t7|#_@!7hJv`~S#{%Kla#{G z9#S+4hm26z(GI9YM0j}x95R;Z39Q#KOZR$mz26iiI^Eh>r!Bt{Vi9;0JE16JVPE2e zb5t`f<#ybO)WbX)<9az>kMuTdIz{|C<7u><{C;u{tFKQD7~`aAe)#$~{Ynvg^CKULH^yVY+bz0g;gS!H-4Eb%7P0 z-3qnLicMFN zmWF@j(^xBQ^Uc4isW&>%%*EFx;KPGgk#!6PZ^%Y+Y%V-lJu4k}Q0Md*;vhI6&$*fW zz$JfUh|x+VB#&A8*e)^4z791+)_3-x{^>yEy6DlCZ>q~^_!o)mDUI7&T-ycpB@=`-zq8S@kH! zwJC~^?F8vLPFznM4DHzw7gasWCSu+^q;}Rl2X#jizngE0C{sT9A&|xve`=#PHj9YH z#6Dq4nLsIB;)~s$GxGqCH0e`$L!zIgOZ@Jf*60@X%`&a_NU5F+NYOC`p^9p2IrsBa zdz-;7viWTJMsr0OC&=r)%MI{_8X8-{j)WHV+Ds$4=n&6Yl&%sp2T?{9#*NLM9m;B3 zpFJOi;h~V-%8*fmhtJ3>JHPG1h9iZ2-aR_>huJQ99=h7v8kCgS7qov%{GMDlFsA&F z1B6*6(x_k1SQ%yt8KWi@InXXLf2sZCQu3EDZ$3K)=yh*B>U_(l`-@_*c${27P7yLj z5eYQ4T3`S@0>>$b?LBj+LQ#hs7d@jY740tEI6w4KzS{4$a6qx|t1-CRUeD{SOr!99o zO;Pv0xYaZL7r?(Cc$I54ZnyUFk{r425_Gn^_cR%vDwCkW$3CZ^99#u?_7bS7i!#6r zN*|O*+X@oJcclMgvtuvgvSli`{D-P5OlfuD%x@z4&VVoHaYJeJgubs4Lx1V-i6m3l z_G{dC;N{+(O>^d8K9*3R=Qxq{Z%f+ilOys7@-ze}u0j-S{Z}S4%N#c%w;dyRHt$ogOnUB8Q!>OUW1PM05i$HK z7L$><{g`pKVKHPtGx}&dS zsc$e$SjuG2xf@6;J<$z}x|!RpQAV#4@oYBp5~~e1k_bC4d>$labSwy3izye+Zc zxfrvZ9dy6b2%$&QBGEAZ$OydoCjIlX zmEyr`vFd#adr8VB$`wBip4^)u`~~Esuc8XW$AUiHgd~Er%6-^+L2>s9`#HWnql`+7 z7Pdt}lhg8y)%h!kBfm6p(YZiga@GRuka9aLod*NmOr`pfGRj95;f;T~Q5C6G8B1VX zt(gWhKe~8*T*Ukr;bc?(Crw>(USEHqT{h}HgN^rYtvefq@Q6Tw_Qk5U)hju52n7h7 zuNw03Q&ormLpLiT^|s*1SiRfA6@R>x$Hz~Z<7}OB`bn7Wm|sG@-t@})yV;X{t?lMD z(|WEe zJK~>_e(6m#5gcL|D8!w0TcAL;I>-pctqI#|${bqvve=QxwcE*3X+jUY;Zb^yi*5nG}7ic%0CP;ofJ>&|$SNcByunGrp~4t6_V39h zHiTizS9)>CBv*6+I!R5s4b;vPNpDM$HEwDeYoOTi`jqGzQJKneUQgemRFe9XI`J;8 z)73LO@~Wc<*3|#Q(pfk(`F`)86afV(5h+Cxr3EP|6;P2>x;q6%HyaqFfPi!(A>E@H z-SL(hFdAW!BcwO>z4`op{{ee=p8G!MI@k3&*S%e3{Wr)@$5!{2R6nwYJ}jEw&Kq2B z3-%$$mr}7kK_g+)^N3!0nugG-gWwU+fK#@MzjP415xuh<$9^fcfL#|mJg!5eiy_X2 zryeYt^p9(-IcI&>;?db(`b>Rbf0drUTu#Ct4XZ+0hvw*HoZ zy`rgy@klj{(h@Geof8#cDS6(34$7S}dPnPTnfOCw?`lH2QEhYs%RsYnzZSfHw}9&! zx) zc(w?4E+LBZ@wZ+aG{6~q&)bXZE%>B%XoF)0gSDhQS!ns8NGEje$x9RCR8+FLz8T>0 zU|V|hrb#1VbngPS%}|nAJ4}vI*xom%{`O{y&q>pwinjLcvaJsW1|P|1h`$~~WpwlZ z%-NJui#Q`byR82XBt7@p5VVovO?D`?16l+%JmXUfdIgI4O~>HB zVcR9Mm-8zgi6&9MF)!Hhldgb@ z`k%hmeTrK#FiIqz8H;na|FV2q)?>69x^s>b4+Az?Q*}#6&u( z5IZ|N75=osP(+8!_c9~fu%#&SrO=Nrv6W+|?Fb}sT$Q8fXu<9mSOcMxu0#Ky?zrVm z(!ChwWxlOds@UHQM)|BaE z4i@P1w2fa_@TbUSUza_f^jx^?VNlKx?+Jb$-j`JjF8EfNkv4>P={vvCmtAWO=nRWX zELFcvZ%_h>o4xPAYEbB4%!4=66=uW`pFxAunNg^9UF~oH(@<31KTB`)8mKIFqV)1~ zJ9fN-{?RMloonur5un}o<$a=#yg|M5Ety$eZ?a1OhDcpgdbGq8!3X6SD+fsrAtL(Q z$o+$28#)0`<&hu};cJIKf)lIGkNNO99$H12D|L!vcqmWvA%#JVqEh4O4N^v>YdK z{v_AVWj%*b&ZgV&mmILm_$R4B58{AcmVN!%u}1MrwcJND_Bg+?Po#0%Ze3fI=$)G5 zLqE{FP|5fcH`^H@+hNSn#C3e1edx@cC_;?b{LUX+F_6ok0leu22-iJm<1rXo*^i7Mt8k@Ouq~=6(f?1HL=ZegmW3{@;%ML!S{xL z6JyiF<27lJ*YY2YnM6!9je71cpgzAVzD(Gz)~;I9Se8#7j(Ad3SrnS^y_URrZ7c)w zBsGOZOdt}as;>E=H~Ybw^5eg+g}^CK2||BN>!9}M%9K{U_uaHYU7MnW?KA4Kwh&UO zIJEDp8i$is`u6amL}aP9xJ2iW&Z|w5Kg6Tjk+c`HbKW6(2Ob1f+pR9mii&qfFnV@M zDUo!!94LzbFYm95Q91cs#uS5BUw+1Z_fDVIdomdrHi%^--mT$xSyk+ayH=+d^ zmq4OapbNtvMQk6g1FOAX*|rbxzn^KQQq$!D`~EJ@Xo!%OX5$ekxq}-H23{L`pJ`$b zU}Vf3KeGJ&CnDTMHG$peAnMN zygE9`48ftB#C~ye4f`srN;v`T99$Cb5gmGftNXHH}2ET{2Q z%vZX?)faE%9Qh2?#*0)vh+9X#4#j!7(7*1kER_EVq*~CW$?o5+_p9Z+-q`pbPvO@P zPrY&nFA75b%v5LQUf?eFIhe6%k?;d&ZecO?t*|ov10VB6H1N7`iQ*ROd8Vbcb>}@u zwPKN<)|OY+^D4~s@lx8KM&nH%zvRpceM^1y2MtM|Z9h#(p)2|H$EGbu@w4Bn&h9Xw zdPsFGL04QRVez#rk&dlOT$V}Q-OCGA;1^2LFx?^EXW{*VktI`@WQ1+cJ*&5d&T$9! zHlgE5*`K@)NX?*@y1^Q;xjKC1tjnrC8 z4t*=OkuGm}=OYLX{X68MH6b3pi)`8G_&FRyd%EDJuFZ`1j3!PT`tpg;DYEZf(8t?t zT$nG^Mv$F5zj;3JYm@Kw?RIfivl_`T_E>eb*!5;`h(aWhCx^Fb!hYsdJv}~rG{e}$ zF|YMe%U;a$!$y>8{nkJs)0vzYiSs>?YbzrqVc_-W*QnS{ z)0o<8yqULA92W!o^^BfRd#u3JdL^MQL!f9aD1`cW)F&d;U0r|S)9~ z>TSFRHe$epDLLuT$f1w@|61#{0`zD*Q(dh&%uQHL_AY^k9n4g{MF zZjSM-I|1A?)BXC#=8Dw~GM+|(s$=u0-`Gq#OLlWw+_bzz~(bOZFf<4G@ zED%m>b%0P22pX`?i9>9TQ9JDPUC<{BQ;V87=jKkdcV zdaUW^+Cf;BW`j`c3rEaqX<8_Lj@b7tp=e__AVL9${W4e7zl{k6`R5d0Ii5XxJ)Gvk z(x(`Kzv;8Fcf!2XqSHPhWe@`)f2pGJF?PIGex0mbDNVjU2~40Pm3V!Yj;5b3dVIa9 z#2QIO|4PomL+3+mVrm)dpD9rqrrN9jcra0rAQ-$pTDXL~Zgs4ErY~}Bsdab{n_Wis zT7rr+aqwUQ0{I=P266F2$|L!*hBMmlsd0;}VXy~uP$I<>nqBnY6sb#~x<^`*4=+EG8zg*W z-APuqV^EQiLV~GhX+5$&%|x~*nouW3jm<+08AaJ5E|L@DlZQ4LEV4G$fN}Tg39Gx< zN%yL8CjHwzddPc|oxwh3sX(AT;*G;EV-7a51hv}90(r)yNW#;z*B3|QiCK*iOhnQ$ zqdmumZh_=8&ggfPm+Z5oR!5~MO$D4>L)+zPvDDKKaogr%BZ6%ptFS%&QxrIE*+E5~ z@V7{~oXmAqlK`}&m!*5fIu1%xQJ;xX3)J{!dmcQ7nyJ)L%kHQ6zL6$zNW|(wjsHGL zzDobyKft*A`+qO(-#;7n+}x=vi+>NN0~>z-f-^z)g&ZViJTjY+;4uDlVw7ILz35?v z_Yr^Z#KZk{QvLUTYFwN8Fhs9iG)BpOsaUP!czkc_2zak~)9%2+J+$OHC|mAq+4S;d zI@;dYv)Q?Jj{}!mRTP%LE>0fk%|{@>5>#-~3%8NbT^k3X1X4P(P0cr%&LkPL5c0jp zY|))siKF-UY8izAlVb(MkSy;!2XT@YIb$c-Z}nEo4~&h3u?JSuo<&LA0A{kN!C6SmD82M#KKNZQh35Yy@s4jC1B zzZSRQ{lr0r?L_##fLOdi8GD`_wZi{kGeS3ZrZwpO?oV02(#DW+-_$wc+pCUbG&wu* zTaMgX0?j0b`lj|dzRi>84APWw;8XIgMz;QiRp-}U=v9|wX10|Oi7s+zk`4SupCl#& zH|p%>CfICbYA#P>^ZM9%6%X~!EfE`iA)gz!GIl=Q(;EzyT*+@KP5ztXOn=?KA6biBjmDw;>MvZlqKt+iJhrhxn9a2H$bdUBj@n@OM|HhQ& z{11o4wIX-ca8#b}x5M08YgOPX+Frb=v~?%74V+!;j%eRA7J2#EbSa~+%q>Lesn%gg zQNHX`%%t#v<18%4tb{g`Qp&F{AK&}r`ry#pbzuKivVX@&4xx!*``=#*iXC7N2lccx zm2yAR#37S9c&1w_Kr=1-jHgG$;}$D(ww6QM1*PDO8PiCgz@wR<8$a+vR*Z98mc!f_t$bgRO>T%L&DETP81K?jf(F{wmT8VPA{8#JE+a|12eUl zv2f}~(IFP>A?^Pg^qJ*1aLNbB-Mfq|R21a&a#pj=dPcVFRo*cO;+x~KOCH5LMC0QM z|4fiKO#CRI_@a2tPew2K(n#<=sjQtI%YLIXZLO`>gB>|~*WUvDx(d+R~ve=gYKt0^qm{oo`f<&m{w~gmH9{B<%O<^o`i4cOM0s zPmI3Dn-i;b*L-nEGSO+84&>B;p3`b}FQ!|+dU*|hu9g^=k-rT4|N5MD_`A(trAq4g z87a@6YwPL1+6yV&8&iOvE2#yG8JZX4p^%lygHTGu%niR0IONTm%hD|A-ae|7_oxte z`vpc4vO^H?n?CUMg_ym){YtS3j@zKlY3%{~*>x_pjGE&>jkTQ<6IMh>W}~(E#IR@} zDV=2E3Y?p}aJ6qgd_jtmhK8W1C{yAF7gK+0ba{932Q`bff$7053kb84;r8L0 z-)ILT`)7!Z1*+pVQum-?M@ONhwlHAl$>VP(JLp3nZwyMO+H>tsdjJ&}0{tp{YnfE| z%i*0AfwN(7yg`)Z@XJ%&ZSP%m(AB*bnybEDW-`%wkp7F{9z8r38%0ip{2ELk)v#D} zBY&-3uF1hb1~4jzk^9c66Y`+9siV|r&qyJKZ4qD~>MG&1`>cO{+6GK9?R z=vx{3E`joJEi$+2aMM7;Efg2>POtivMx8>g7k5#LIo+sY>oi56x0Wur2M#?cJqy;_ zvE;`xsd3f}hHTMVPitGEf$%gJDU7s~m(;Nf+gZ&!)^pGAm~D3*-}X>egO3L0+*P9W zdVl8GU(^qhu*l^@yL46g^Tq4Y59MEHh7Y`cwa3T#E z8&HW#;!ihk#}yuokRzSD7E-yHx22I=l_oOf0iNIoO6qc$`pPtWuKm4h?^lz1xTnYH zXEd9~jD#WzQPQUYiX^p-otFQ1`>%MrD(OZFJ z2Mzqs0tc~crWb_~Tm;Q*Ny0ML`ZZe}892@_o&3fSFB3tU7|&j{ZYF}HL?=up>u_HP z2-S8Ps3rE6uY}j%BCl&5C0k{$Xr#fiB|R!I&DA0lJ7z4+Ca2Rrls&*L_M5) zA^oH!#{9QslE!}pA=iUDuH3h)1&wd{fdqAxsqR$P^3cFi5Rh#Zve+3ig49s-c2qjs z{CnT3c$`UfmY)@#RpgpO7TaFyNlP@7uyuuHKP{X05@G%|jjW2s6Le9x*u zKdFK>J#v^7y4V377?GT2u|xKLfamTLex_C8dih)(Ksk_b7T?76ZdIPt%U6BiCEQDH zT1wZ^{i>mwQu;|!)qw~Zb}r4=&t09vbK|_I^bd4U(c7C5>qIG4LwC&BQ+R932Fxm> z;sfl*DMO3^4hg4zSHI?Zbg!JNtB_m1Dtd0gjZvTyQwWls(;M!e$g#ii zp+H7`j`F?yX(LrbVm3(L6uSEk8hrCd`0VqFLW!<@jrbCMnecNv1xxibfuhxaGryR) zWuoIROq5mc8rJpc!^1y1-dae0_qe$Fq|kJlJ7;!a6=(eRKwolv&CT}&%C07OqxYR- z>rl`urRyONJRJ&-PKA4C%7h}WIh)$6rfAuDh%CW(o^YM%8z5681GGWb)?vm4x-{}$ zzDMdxB1sMoHpSj1AZyaSqZpOgjxmWucxa|hJOuZA>hU5fqCNlKF;N4y7ltLv%gggW zAJ5Fs&JJ4X;CNj06_s#;A?O~W*L^y?PS906{q~@Hce=v7X!vC)#ga>qk&WZmqGHjn zmL_vE#311U(vtP)k?s~hevo`(mHP17%}vuo+cRZHYRu?=GK@*$2)w+(@we9&hWKgD zLzc?i%~e0MQHcxQ&`Sc3%FXHr-FqmVWsAC-b5ta?D*Lk3ZBY{Z#64E}BFG%Yggf}( zliOvzkTlo7D837KJOfJ56_O`7+4ON*7EzmIRWPTPSciZKT>3km;xWiD0^K{n zfPC{mp<7|{r?Y@M=r$_-MnQq}>K4*Uu4?S!JZS{9ZYq`j6KH1 zXM!)uRt}$|CDJw`43C|P-|&IgYKBB8BRwQMs}4GbUed(uKKE%%dGT+lajvGdE=}UM z2Od{aGNL~SPy42)0FfnouC^wtVWve?C%~TM#$8(LXt&y69aO85dy0~+j!Ntf7T41_~ZvQmUe~lwcJAGiECoxA@X& z26seRgF}s5$xLgM-3!Sy?aRHtGk&nt__dM;CnHdj23>CS3edP+UdsH&sA_O*5O615 zZiTlgy%CUk>8o!%MEY~9V?RzS%q#j9jbc_=Yu=$jxE%gu{iNXBn)&fXcQ3fbN;^tc zL#z#I=Rk=p)*d_vClBT`y9Ftpzf}LgEK9R|1bp2?QBkxN=2dR{L`Z086>+dF=6E!_3)YswG!h6BFmivCcwN*oG zsHP7U|1>JVtKw2Db)1Z;d6R4nsECjve_THrv4zAk_fz;YE^} z1*^I%<~SBq-jZASSG7e_F@X*2jNZJrnXLmtQZGY%Bb{|}fguV!s}=1VL#c7)_WU$V zf)9RW=vq2};0lhdqq8IVok6I5d-AZ^J}f+$==Z6ZFrhu4}^VE(gNxOOZ5DRF%M-XoM{`(Mv30cuAK@(#&B~(uWZ>ZGS&ME<=a9GTn-G(4fjsXr z>1KP!HLw)K>RfR>WhD(#wdl!EACP?W&UXF4?x8!?K~{%jef*oVeDw6g!W#{3-E<`$$HwSnqefs6^KUFd*)TOpJPoVs613Ei??K=RZb8A z5+xZl7YjF>>%XWj{yp)OcBrk3N}M_CiThLCK;cNmpvNGmnKQTQQoj@I1Ly@qmsfBY zZ7{37AxwTz&l(J)Y}<9KIPu5Qz9mbNrn-cF-nl=&I5qNxk&0_~$ARLX(`_x)yCo@9 zqikQej`e7NGM7?f%2K+%nNqBFKo`0OWGq3%!w8qWa za~E2WZ}fTKqHMLaXPZ6Khx_7F8nAJ5l#J+ub{AC;$O&XcNK1-9bFu^sO}F~HhzSnI zP+n}}I#%TxRsjV~;#4IjlJRP|3z3IhA5SwwZ?OFDw0v=|om9SyH6tL|@sk-3E}DPT z0fE33}RtVtibu9~MFn~YncR3zFy(s2=D%Q|)5tuGN~ zsFknRAd>y;DaA7;x-ivBF49y(sclvH&-hb?66q%M(#k*1&kC?q-q+F*cxzbtJ#oRO z(WAI0-*hxHHT0X$QwID^zFT4c97JUK$bku<^@11shm*3Z*QR4`AO2336Zr{KGBIuG zY0<{rtNO!$=%4qKiMp;w?yUFtnD|pIiZAJ^XfxFwn={zmWIe}$M27v*iD;k=w<)Ty zs~=O?;JLtAyN5%U=$Cc|NVA2+D{&p93(WU`m^VoLa&WxAI;5U7XI#$rwjy?9A;odmA2I?R%Y6KP`R2iglwppyMlzqvm5o&zWxsN%ZEs)+zz1p@R;vVPu=Iy4 za?5YGjTbmL7@xZMUt^0NZ#XZ>?}x7Coou%YX)JY$=@Xe=JP{wW)6gs2q6+2l1^-kH2lnj_xynKZaH+m-nC%MaT`)wbYhEeVQ1%JDOSYXq9 zxbR*&CTsOz66?nD)@dm~i|0D+a_ctjt0<$h7U-A||H&}tN~4s&<=7Q^NXae>BeANEkq?>iD+Ki1SaE19UnqeD)?}emPZ9RGLmN z2umLK_ZC`)FQ4cSPO$Qr&6n)PV~`@KO<1p4AytKQPHoOnqUoK>nw!UrkNnx5C>p!6 z%`3RMg>I%CJL0iWYB%fk{p^#nRU?R=f_*rDzk;Rn-}%>;N&CLEBre8km;oeN=gd2U z+9)n*rd>k`akLEoc>W8#ivik`yu4R?{9^1RIgtv|ObLuv)_KJ!N)bH5*BHTBJK;rx89`RL|g^0WKxZ8~5pOir-^xB*xco$u2y^)L_^ zsLs;=wWX>szdN+q%aB+m-o`h$ZSDrkChdfrzK+m7+@eX zKEWEPtp6M)e;SvHecvv;aeI4|BDYGUHX&M7O7&-Nkz^Hzj5UeIUOiP)C&RPgl_8a1 zAK?+xUXGzHd@DVg1P{+zEUkK|$mnS{22vQ}^eQchV1E0SXy$>WhQl~w1@w@6^N#u z`I@=)%8UWK$>5C_(Y$SW;Qo5@D__lm?Ai5~9M61a1ztyUiMYT#pIqG{IE|0@g(XCT zRvIfdz6^_ihU^T!ZaRmQe4-flQz6#|ytw#-)+2{`y|<1=A*J#U_?vxc^VjuwUO*Om zamKn*Ot)2n*9p=}KXuqE2|lZ#0$L56uo9RKCS@gSy?Q@x^_GXvMnPUB3{(A$9_3)1 z_N0X(YTY7U(t|L$h}bB4md7UM$DcJgGx`WO&B1{)z4MxmgEn!?Q_ou5azqDJ?wybB zY$hjmolf04oR0gT79%i1I-Sen6o5;|K6mX1{*cGHKgytS=ArsjYe9x;KJU5tT~!j6=kf3sS%nb_tC@vatV z!tcZFNeeT%4+WB$z+5^eqv@@Hi`b>wr|?aY7l z3C5k8w{M`jkuM~4Eg8dpOGWLFrjH>QWs_+HO!zW7^9gVutd-3^Wu zmCQk9U57-++}?L}l%tB!A3OJ??U$+dVr||L>Qk&f7;`286bXnl@l~=>T_7iy&&LH- zbvh0=atJ?)8c#gBRi0PsBTTlUYIn%Y~Sl9*sv8*=LGU23frAx9aT?u!lE``D~0>7+VQyTM1dPN z=x(`GEhhy@}<`LNv%k zk0uVSlqWMx)FhlEs(m>mXxPOj(XLh&qIj8QZ$vtsXJM+pCS# zTG-v!j`lt?W51Ny$tc(2?~L2IeV}QRk9rIvT(V zjWOdA;1ap?Jj#BH{cw@(o-@Qx@zaOJ0Ea19hK+xIBIV;t8YkC}e`{1xS{2aXI>lIt?5dS&6_H* zzH#X~j0cAw&ag0}-c*cUKA;W)?JE_i2Jv=vQ!UdCeTnp zk)$E;L(I(XMe-HaVg>8I7pRq*`acefv=fnvdEdVlIWq@ydRjai}V%u z1K*E*z}*$)9Qz8;2_m(_fC~WN3C=7bb{bVR0oFez=-KfXi(=|J>`Q7e=@*Y14@z2@ zb{EaVMn5thW7_3tC@)RK9WZVNYP0ZSone6X(~FP)%&A}^Wll`Nvnh!%@nr#FZ{zA5 zh@0D{!S+7hQ*hVM=?x&U_-`(jFV91aSY?6hSLoaSoEXZF``WgSx{Tcw=1z-uaC|Hq zmji$YdWyoU3n%YL{ki3rsiW_l)Wwjg;Xn8};kFA^y+;n(5sihbf_+qc&0 z7STs_@%V)F?DeGtf%P>FZ-XO}st)73(lnO^OaBz2rsUcyNH?RmgJWk$ip{_Y1${qy zp&GzeZ_eiMoDH@6n-(OZB%RU@P~@xQwVMxV0qY=0r!I5#EV5v_8u5j$pxD-)g64Yg zzK=A(aR_~U&0n`D9*vxn%DgfSoc{>S?Z*=E0R?BLXuwPi>Ew%(bL`EIpK5T0MW|5L&<8DmjavQzMIUe){mwB=uwQc zEbz_ACmVKoj!H}%mEZ&R1wSpUkyhi@+oyAN5-y*bJ_C^6NBM5Ef)%9~Jsj^NU z@TtY=4d>Gpzjc+SKi5CS){kS~oVnk=HsSEl=9;2qDWEv1@1-3B}AH3 zZ8u^*{(ip=Cl=CJbHdn(=3YISI&b-&Ze8w|mRjrj#Qci+YlAo-8f|v|l#sAHjJ*y} z%m85*2ZABXTvUe%NCC7Q#z<@(R(9a3aW=&W$t!%)1%Mp)S)zOo?QZA_)o_w{m2LZR zzIaVB*E|8A;VFs=5O6n2{Y*RTVya5mjOI>CKsH$bxF@dW=JRh(JfRPGgp;qL0senm zw)QSWJ}Ak*rfRVWyCF<^X15&{$i`A`em0{h%?axhyKxP~cxd0~J-sMMM#5ui-8O#i;#g)k@6ze$VF|lJ@ z9s(S+zFx{P@BhpI`+pS7|9fwS%S~{-c@R=Vx@p&Iu0&fwqSI z%k1ThET!DwbaYT<4S_%61_YwS9(?m{P~Km;FNglD=L*@qy0*sP@@cQAC*$bv$rmKC zh>ALjq+3KgIQgwopC>`6SIjfFG}7LH?|*!C@4Q`2LwrT5F22bw|7tT{TweeWl(mUB zdW?n~>+Zoi7Kajh(i`@0tDTDVFTw=c7<``@6-^AJxT-?lA zk6#vd)Zge+4l^KKIeM;~Dg@WzR=6Ts!_KDZSY))Jl><8wz+M6@Nl|sMB?13+*>bRE zPG2IQxP_c_1G`jQ-oE8=I`}ih97PDmlz*VVY%4A=T7N8k9**%rGl-sIHi#>>O0<~W zu^~s|#~I$8=EZmW{;mo32H*BJC6n?K^vr+Jtihbw&M4!;3i0a(>~Pv)U7a%aY4NuPzC!Gyf-i@c;-&Ps z`&`4&;mm1Rv`?0x%Tf0i-r`%fp#d_WVb53D=$X3~^S&sjDh!X^7T%WCoJE5-Wo69w za_bQG6Aaoz7W_7nGAPvr`6DsVGf$S@<)Ak!LnOfD*fh3s7tD=N77my@+_pg}Yj$$KQ^ZQ^e3gOk! zl07-dwGVuIq4FoPqNLencBZrh@kgFd>BHKVY3t`z{NHPRV1_AmShDl(a=84bV(?+B z-mb@qiqnfK_-FZ6suT^|5O4G$u69m3z$A0j;y*`Ot8&=0amD+bAeS$Q*?i(y!pjT=yOm<{pqNv15)S+!xRV*zOvGy z17sAS`TjS-lG`95Uw?#?lpa>|)TYpQWF_Qh%};u^VQKX!y3g`ed;POkJghD*CZj6= zHYaz_msuBCyIcWiKTZbLhnD9;k?g$LQeMqRr(z`c`akynXK8{VhB1okJH%b88TwCW z_O4bycQjj%x()QIb1<1M92|0rS8t2$M$Z1Jf5vn~aXvv>@uw#ZIKQ?~%I;d{qB;I= zBU-b8h!T>QYYT__WRrQE?We8f@?>dmmG@*f<0sqOS5AWz!`as(>y~718RR_YmyIMR zO(DEzF&@-uh26ZIC;4ntvg9lMJ)L4zxU_i=U7Ju;9j`ultGfDiP58hgnS*_<>E<1l zcJ(A9zlbLQQ&W`R{|Wa$SfvX~$MSX6kEWZAyI;S&j9pan^`#Zgw?6dp;$H{ltm#1R z5Y&(Lnv$^-_ab)D;H}F3{`iIG7>ki8#ynmbHcMqwytJTnzCcTGd;0`Fg!t*)RYZQ- z++xsq=`TZFXDFM930U*g(huwV^}i`?jl(_(0PKU%*rvZ+SM6lDlFbQ*5YTbXsp)4I z0bgX=Fo)y?3YQZ(`sE+A{snVHhV&gT5B7>n{JtJsS}Tohl4-oE*Bw^%&8UnLaXQZr z{>eRv&!0)Lb$lUOXN@Py(Cw=WXZ1D$F25UzZ`?@Q? za%!le5~c%7e+^KUBh5BC_8(NG>E@P$AA0boy4M1g*G7Z`DOF5e$5Dg>!)#ciG!H3% zGAZ7ZvUw{!qD-@CSE0DO>Bs@iNTvV<;xx`X6!cfVMw+H{AJaVeJ62NHl6^FL4Ch=}z z)8;&fDOmnMfj9ALZvK|yd-^pPqWzk!@wdf~#A}yl!MpPa_L`b6XZ__~&VOyUS>j?i zBxVNR$W&xNaF|k~#9pLWCoyVS5>^e5Xs3^As}9+oexuZQTKJfa26*dha#Z{|>M;9Q~SrA@l6makUqbJa;aGrvM)h|5{F@bBQ>clDR3 z4VJ}HOUH_s+3A3r4KQXqdS#k}YBcd}nLk7O?t!HomPz_eu0l|gG}m)=5~@dk+c6P& z8d<9uJs!ii-CrO2teD74+)%;ef&I8k=5#)xy&-E`E&DpwjCsP{V#%zlHrwj`Bb6c3 z74Mq_KPv66ylaDaxAD?#gjj-dkU;{~J4p=?f-gX@E$vl8RX3@GdV`qDlZP=dS8Ak@ z1ZAc``&u3)y>{oQXa~fEHOU?>3SN~hwN4AaCar@-z|-}YQCmUZ;}GiDm{+k(N|BU| zE{t3Kp?QU4LHwQAWJ?tzjFl|$B{k=0jm!(zOG5_U~2k5c2udG}zxve?b|t{w7# z_a8no(EPqIKAGg{H65MV9eo=5&KV$c0ZH@SYu^v}jKsd{>W2DiE_MOiH>oNtT`^pv zl5LR@fa{kYm($`AbH>u0cjS+^F}Q%HnVJ5^x?q=W%F)CaeI;Lg#$t3Np|>l$|B+%b z#otk)vK|7dDiqs=saZ5#XBmLYY5g}LMUcq}R;L7d5&{n~IG1!A95{Mado~hzOWb z&Xv9X$F~59k7rLzAP8B~{FgMKF6}Yc$e@(gx9?XvnG->20lsUX;^LfzI3A2H|74h$ z=uvzNf&eAabZFrZzzkSgw2}8}H+fKSS z>iDXWEp@MGP}%D-^P-*kP2>h4NwB!p0`9^xyGJ4llUf`?=U1KRw|W107Okhl{RKejI8(-xzgK6|E#QT5HE;?Qbe^5gT7R8!*O#$W&LBqsJS zY~>&A7=p|+2yndG*Y?uD3c49CQhx`kdMiDDs$-Ko3r}t4ye5M5G|r9JPX9Z3gPo|m zAYXqJ#)bDU#&$;Yv}fFfYnd@|>TsC7b-=6D9rbJacPHj#FUYIZs(sF1=6D8CX`%KW zt9`TL&p>BWDecnDL|sY!e;<+Y>LjW^X8n#wgy$FS+FTsAW*gU&Fm?_UppF>IB?tXx z-(RrC0OSLlj_84ymGX0NR&Ke=ujiyYrym}^aNAv!Wa-6w2covPC5qZ#*N)RZg9{Gd z;9-Sx@ZPT=9a;{(Ie0Ov0nc$iB5Jyap+bILwc11Pz+)$#o*s)QsQ=xy;H15Q`mcld zYnaZ-;rQ};o;K%y3Ph%tbN&D=zKc2w{iY5Uh)Yc(K4P6{W>A%w6%~DLq{4 za-sQZG~T{56-Qn~aD13iSH>nHCk^IX%w-wF+nMVJ?3q5nZ!)B4FZ8A!u~cT@u9$L- z#!VFYYaRiC>sgMZ7g#f%BZ%z=lqYDB5@gUz2OS=pX%bzLNy0R=c+-&7VGltG40cq- zm^rNfW3e6`T5DVWW#-TC`E+)1onCjt-)C#UJ=eqj(1Q}CWBDqki#*Wuy0N&!=d;+R zv*QmaOGc-adHZga~BL{HZjUsTQdq8!IjFpF|Y7%662pyPmo)JsRN>_%`x4sad_nuqiGJZl>!FKI;ULf5vqeaA7X

*prg_jt$GjwxCvb5D!7T0{d)MR18vxD$eRTW6@C|-En49;ukEoA0xO+DlIW( z!lId+w>F_m7}NN>Vgj`%dKH%MHAS?=w_O2xxo%#(yiUzP-g5fNuzF{3K-qe&Dy)*6 z0C*go`-i&LPFtSxkAK>Rle{os_xB07SeTCCKj$`DQm;HRDGSv|*)?a>=Nepc4m0YC zpPU&`d2H?#+WOtC0-bb4Y&O_IxVFYGc-B}786y6BBvV(KLe_bEIL%)9KdcwD`nI?WmgC-L)d@k z;gb)h$sDD_?~Jbg!(5od^aXz}FpIHA`;-I7;=#cf`Hs?T))c#5`+!G z;((Jqu$|+<)q1zixtltp>z9b_2P{#Ivl5z?giar1FYidUr6gA%#nx)8Q2i$&f&obz=$3nYGPn*(A%=4GF6u&2;hv1p^EJ4>W*Oiaf5T!lP%vS#~ z-jN50erQ7VD=d!+;o~AF_VYjDMwxO|)Y_vJW~Ou(y7ngX*H0YZ&7DxgJ!Y7ZdR0H` zduI7)bp^#TIVt_>dmH*5gAl^3KH)9STUD87%k|;AC$pP};590)zk;o5zMHQE`e z{bmnhAuDV2zXrq3FrQ|YBf74L^5Fv!4#am{?$hp~%ETOtFYEZfeq`*{4jS&OJL7+! zN%}@j^S?3LM-o0ub)V^Jn3OyB#^1|7zp4c63SIa~s2O_a8Cyqht8Gekfw_6aPq^u` z6;EkWL@5O@_j}$qp1h7gnFl0{vepnt(Qg>o4eTm0Q6OOV}#GhTxZ8gA|*k;KkRlP2KtEhKd zNWcmf-gNszLVnTrvv#=nl{)CSSa}ExL0Xowh|{|k_T|CesqwVC)P6WLe9`*OTtz+3 zgSyu)#5O)*6P>VyKHh1Te_aoxm(}uEF_MxM>-qy0<1g)vy3kymMVhbs<5 zKwt8KpK1scOy(&yoAD{PO0f*yy0N}X7VovgwxSKuyjDk#ma>_5CtQ{@1HQhl7iod= z;EIlYGV-kqssU26+ZB`NpN5XhFIp7}ZVF_U|q4NSW5H~{WKb=KP zQ;q*29WS5Hy0fs&$JKwCblK+c*q9jU2h#EPc-p!FiPx?e&osgU%Q|PW0@WS^-j3tEq8PV$JL4vi1$uxyKLRdAK+mD__s0R7mt;r zX}|T@C(hl5sdfLQ&)*f&xYtkle*U`05uwZ}Cc4TD_wQ888+_V7z(4sx+m6@>I#t#` z{>44+P^k~*JVvaa7cVO;t4P}&rHk4tZk9IsLbn$B^_=r_{DJ}?{M*m@$T*G3$(9V` zcch$0XQxpgz>q2y=c;3{XJQOtoa4LSr&#M5GW6pz^X@JYO0^v#>eXVk%4KXpT$nRx z>Nalr%5#pSt#MMLZ*;4`aRgKppn7llG_rf_!%}=Y1Dy^2 z@fs{$*{@#Q{!?4W_wb3`zvC?YdbFRn$Hf^~J>Y-LH1XfqbFzE1O~MfoEs*?E$J8DM z4Zbi*nZp$=6V|*_hpoPpX&;iSO;4wdCNAJGaL|=a7vXs%47OweBzULiNN#9f_f>60 zWLV`ZwA!2JR#pK&ys0qhoL_~fBcRhq5gcbi5PzR*nHe0ZjBfd<`M-&>;8|qq2atq} z!Bb_*q14Y)zRo#AL^yB1w;>PUwF{9-jSKmM?L;{6EF@3l4H@BSUrbtPPjYB07%r*j z3C3MlPl%ePUvxhPTz99Wya+X#r7P0(s)<7UV3V$EO;I*R((6WU+Ov8`3GAQldWKi2 z@C*yE@5a#M?Av|uh9ED1Tmq}X@=u!x=`A}D^9}}=@l&(v69>M`*O;STybj-47b<8Q zxHuH{T`Xg`E~kP`04PL|OqBr9oGT(C`0aowWivd`Z&>McSI6*qy24>^WRWAYg5|%f zhKJ;>(vchB@XVcrNLPxnJqZGXNiS6K!^|T!Hn2%utrQZhqozw_s_%4>pzQd3!^GeN7fUNd1p%_kK_H4^ckSS5N!p zFpjBhAi*>}hr*zMEQ9AvN|Ckgpz+?lg*{j+3;Esx<>O5s>*gmdyD9dqnmZ{uW@wwK z0q54r@xTy->JYF&ZtUf+lPLAAdt=MZ%mljk{KjMJ2}`#+G)7sYO*mvQq27 zjno+pjGm`L@>LxSXZ*7x;!SbrOkc5j1rilu2N}}FR|fwW>8V2#<|c%gDZ0ghyCi+a zqx-eSEh@&|7Q4+qCG{qZOvP9G5Av1658Yeo^rox`kIpuK~A9LMtt{zpxz^*alT z73;I?2LkMVpKOf9pB8z!gY`sjKv7I%4k9x?5-z@TJe#GmuJ`zF38c>Z_~pLn<4N_x^ImW1-cnSVl41e6{r_0H z%Ah!#W{U=QcXxMp2rTX_?m>eDcZcA?-6dFXm*5^CI6;HEyWc18cdPd2ZWYY*w46TO z2N-epMh!aFQ{Q(2hS>1f=)W4CViWZLEAV4V^@rQ$B$~m;JHPSlW=n zuP+Gh=h1oS#Ak$A!NRwz&S!r2d9Al7-J3f1=cN_xZO5VE!{)%mPdPBo*F0Sz-M&;n zV{^pcNx&dtTL*|h0m%$7OP1~U{-9;_ys+W2ee6H@uUiAiEexSv1A>Vb0Q$%&$&dOg zGeOGPCj0b0%C73Avl|YBCEEhh2V@r(6b(cu^JrZO zuo+H=_MWx@`{r%cC@fW?dTLpmreQs6X*XD|ja)lx0v_FlNNs$| zI4x>#+muH$CC(D<5Q(S>hQj5a)YNHTVvitOdQ%%zKgoliY!&z1mndo z4IXJc3)SQfbfx!czti2AA3n`rf4&Ov(;Sqr$!Veo3_4&K*jBg2MsSnrc zLQ|DD>sDi99u52cYz`M3bSqQ?7A#=1V&P=m-7USkeD|O^e?Op_oA;2*Z90X&ShLzZ zuW4N4d(z;aS-(n3G5Koa0c?HVD_MBLYFYsSIMCuS+V#Jm0Z!Uac=Jt1cU~G04ErZv zwK|k^vaJ8BplBD6&fHdc=*Gu;m~{tpmN?>=PXo*LckzW=XP5W3Cdr)Sj5(qO#2&~q z(pXzBc31TmG5L)p=C@bM9U|zTjxFKwz#8n8N@J(ApYaU2R^@Mi*L!<`&puq^_y{Pd@6OcIG^swLS9895FS1 z3_5aH3P98Z0aL3(&RYYS!}2WnXXh}1(DvzYS;~!YE7eFVD!nBQ_Qxe#nbl-ef6$Pg zy>@NAMXNF(*+|cPG4K#qpR*eJPIK$2_U?`=sXeSZV_x7`D2e;~^#l2ucAmn|pw` zYs0-b!uP3#-%Hrk_{jHDox$~hmIl+mB>iopqUg%o(f{VP#8rGZ@d0%g*|ruL6%P;)qrSn*E(5JUeeTD!P@~L z&&nClv)>f0mqx0hr#!OV%m|7>T3)p2xKIBZ@lOXh^P|r30gG%YTje6Y03K|-g=#)W%Gl^+z|{@qd$AyGk@L`dK}c3 zPHp0%@YQ&&+eZ!yf`!GD)b9yi?0G`D`JAz^up&W~o|7FK(Qq-bK)3uN_4aQ0=EylP zB#i(5^N@&!%_*!izbKmk-w(4p4^i>4s_M!r;Zgq?ok?21U3=Pq8;7G7vZA8|7EO_# zIX!Jxq%_dL78O9E^q)SNzI*n5wLad(;d^WNAFig^=n?D18O*(uRf6}w@vf6vzma8w$!O`WkJUhO!w6XHoJF&e#@!GilIR$Oj+un)qU?|vn zC-I%kXqAN-_juWST}h3aRn&3IMi`VK%ysVxsvF_mbfK4y=^UCEo(E>qC-NM6sX@Q6IRAQSXb zYYAeWSPYi~vipGS*V4n6>w?plqjeO``IwO77z`1>Dq$V;=8V6&^Si=+(>@PrK`lfp zWXNwNw(vcnqurfy}@(Y_t6dY1QqQl24we5)SDWN0nj4f=p zXf;I{*1|-9nTIJ0qXNuhWx~fl^_^9`ok3T85MnfWEXH8qLyO{rue|Rgf-@5$xf!$x ziMHx#x+Z5GnhZdrz*!fduI7Lr1v&fvy($k`A08Nh*_)W$I`8hvobo-TxjS)WH&VS# zzG`_kF>X@LU3BBHx;ep&cPH6H=?kYSQh=Zyh+My4zAHQC{TTKAG2ge#y6A5?bg2efTibH&7NVfEU$Uow=0SPs_K&s3AL}3Ut8$%^ z;6w^hGljLaay)p6w>6CYgJjP;rW^fuI0T^8v~r*$GM8%G>UAI*>qZsyJMx^QrL=~> zf2ptcQj{ez>P4v1WK|hcK|k+=gEfMH>un z(9vkDX((JV9CV?8w1Wj6HwvDpg2ISQH?{R_%tkTKRuCdR9XX-|$;E3=jBMxq^+3tU z_m(~AFS(Yypr8Bwu(g)1SaZ5|(> zWW0Sa@Z$ZAnz}NWW;%>V1Vh%D_bwQDi+0~+9Mqec`_-b!1mvu7zo=u~dal(dp0`k4 z8`by*&zl#u8;1iklU-&SA}~uN&1ln8e+GXPL^u~jS?BkSgcp-7U8;9VEZpvl9+O8Z zpSu04v0%zWiN@&j-2}`S(M8pY%5zr7!KzcBlLlPHVyl+;tShg5^%l`aK*+Oy0LtYV zMdAo8E$w$?rCA%BTMdnU)8Sk};2UP+afC;Nf`=C{!_-UXf0}gKseH32DHQ%T$_?mJ zCz5cEqGl+5S1eVa7^X?u)*f+UEatbsJf(c_08>}hhf-$X{CghQ9#77$9!1&Yt;Cam=gL9l zb3xRchO{W;_w%_LkSi3P+*6I`^P3-Bw>(QDT!qh2C`2RCQC|*rq;BEI)}}{}J|{

Xr%M_OY){Bb~b%tsJR(#T%>Mszz$R&K$bw$oO#*t*30#YcQTiq%aWUQ zeY?MspjA=a^f4Agt8|ND@mEq*{HPc~_w_rMoKj8%mE{j&;kkjcR}^A_<(ahxGD0_k z?$8HOHEM)P=HM6Vj?fiasOLuhj2F+aPR}srG|37n+La&ZRta*>awCazS>*Vrd$uzJ zJIH;zjfv@h^Q(LFch+qQx^vvok^bxsUi4LOL)x)Zx({J(o7tgTd(TO_D}r45-H`si zdBjIw!S?kjvvEnp2o0IdqANuhrfhkUekL^9sL{fh1a_+tdH0fO%k*tM=1_{`Z$(qm z2*jQH`QbEJAybu`n3>JQd$z<*t+%CDvSszT)FfZ5j?(~g+wqHdQ4S@9Fd!&UVlCK$ z*c}NJiCWLKwqr2}jNg|`Yv}@#bQ{-nF}}aGVQEXGT&y&=oTuJC^qGEMh3X5ZWy^bg z8t=S$+T2WeR=})Zi}I5cjKupzaoH#E?>f^HndDz&ztW7#Op~2Sx)00fKphD7MtwXA zc;mj4UD(Rzfc(*(p(;bA*O4}Y?$Tt@@U7Jr7gnr`6O$ZY^YQvsKV5(&1lSetB|l_mcI7Xl?p$m?1sqTB+ zksjJDilM8Q6pWOuhoml`fp@4s_A9lPSxeyM_PXr zh6YfNFKwFq=L5;r6Sw8$W9rPOH;Ie_o+4{)5v#;z#PS_4;GZkO)|vF9-PTVJvB#@s z6dzlEygUSZ>Cn9V^-9l0K|%_{*)YL@6f7(>y)`Nj6^b1x~RG! z$wZX~J%(HXGqc*ffssB+`inYo`KU7>Dm`?=aQG`bRawFa)23V*xI-8zMy|B?u&4@1 zOWjOX1L%(m&b0On@ra1`Y1~_Ap>=x0M#zl?qvLCU!XloL2sR715X5NV-}G#$JrcYm z|CPt3FT={U%8~I!7dm9anS?59c}CQ$tH!RXXfp803mE)*V!{mex_!BM$_r~ciGKGf z^aylIguLOcX^N&--QB+m&|VY8Z4Bowo9`gr@2`1&W#;z&vMGhFiX8P+cdv@QZ`N)w zRiMdg*3!^l1a;7fQx~EL&<#l@h$qP8=aGJA=Nas);zr_9|A9@zxZ{4lwIW;ZC-xy7 z0Rk(DD<-B9U+CBFgqf_-eE69N+3g^fG*i#GPu#gdgjRxQ?Z^-dyr3kzQ|AqW_{l|p zMaIFR<2^~YLnR(>D&qLhQ2r5l?1eBa^?@moqZcK^Em8fkFvfSMeXkZn@C!>8cjLGO z7^nALA1<$hgyvVdLTD%PijVfJMw#j}hvF+LLjbcM5hgX zVryr`wTnbRO-v##rXEg6*y}Un$kkxM%^1bfD8hmuUrr3hz*jn+Y-Fz0N5KlCn~Nt4 z*~2Bvd*5S{`tY78(<@LJ_;T*|HMuek9|5s*~ zcfjjwxOV%#!+}OnneGq>iv65mZO9BjtBu0nXec+?ai0$v%F?_~)qRb-;ws3*)>WP% z24?-N`Z@fs_hVoF>hBk2@8n2gB{f6>#@%r@e|>cvq1$kVFFU4p0Y_ORUnL(XgKPVI z=*;E535;tY1fL`4diX0!q-M>QCt0U)^END^Yn)BN z%imSV6FJ2=pJ6L$DY3^F1ZbCOEBQ zFR9Zmqk5}0EeUOAqGpZD-1c}jK?c$v8uNlqn$cuC9bx#ls|>tGE#A(F_Ai^xyM{#3 zwV+qxduJ%k-qqU6?Z_JYddw1Zo9W|?U;kpJvi{-;2>{$p=-{;rNYUx{>eg`pc_D&f z0!>k4#<)^Abkpk|iq^d6b`F503SL@NEaL5Ti1}r81H_w?zs8AjV9}hyjR3^^txGpD zd}L5Uq?i@qrNZ|uG0j+yDURTjSZP7uB^M26#nC|ls`p||+88|f;G{ldzu-hFF$z^} zGPlkjB0Vbp*R0o8RvZ*;m)J4C2X=mmFK(*ZaM>-8Y@fRA0>f=m8V&K{?3`8k#t8$H z{`FF{i!5ApYh$afOd5$SJ8d|ehKTMmlpn2@2!j51Y$KylvT7EZ^ZCi0OrBpbAwbHe z-S<81^fgE6nk`X-C&9s&L}?RHm+m7V%yww=z(Toy?mJDaAqEJyGTHr-`aa_JzYhe7 zDm*7-W|hZ}>U;(B~pg|gd^2%Qba-SYi= zm%pl5N-Uz9Zq~;-2x`Jv)_6kC`+Lja)X(N>sj-UReP>{wls|le>H)GcDmFUEN*Uf} z>#K)|?@_|I%nX=X5JHS`=c*{~hpI3OBtZg?F?P$YUUk-Co)$??1wy&^1486mZ0CK)IdgU>*`bq!!Wyn%1bl0R_gZ}KihD1w!z(MEX*|BDCOo8?u z%W#I9B!KJ{LZm8+F|Ys=;u?wE%J{uGQq)s0guhBi= z4~$>6?t!bW#xSBFHfO4d#?Q!kg>1B8* z=9?!igg7;1s&Z%__rsgZ-$>RH=~U^7G|K3=SN=-tf&*<6cY)7}49c{n zuKWwat{F8es5-yG0|p(kmO8sK1719YHr}ofHK6}lsM%mWLTk3RV8;jkx=^j@59~B9 zJ9J9!!7GrTU-gkRwe|zp$cUYxOeUVpf#c$u<3UcWO`(}_(3N?6U-Opi4JckyIF8OL z?{egM^TRp#iS7-SNem18Vc$^LO0q=vDZzJ;QoTk$++`@#xdBIb_G?z6!rgw&-V)z? zEbd9($)Xz=NJW1L+5KXKNV><#EOmLXMv50{h>yrymU8=HHL~U}gSq7gi+~6aDh>1w zOhBoz2KUcw2j|fOvzh7Hrr;l(u#b_+#2ibYYFjL%$?3c7IBZa`!YBBG%GeUM-6*vK zL3@@6CM&55pO@kN`k-;sY=~O=i_H>B0#iT%3i`}=(FZ*5YW^Me>m=u*4>>-m-d`uR z0=dAGa$aF#R677~$ys%}buCpP*r$$+j2um`Gg0O(XP7*I39LYXOJ@2M@2jkBVd`j` zZ*{fMu?yHF^#Ixw-kUMn`HsSd(PsmJg%IY1r=Sw-*S944Y6@;8vwT>|#_pddY~rQa#+TDLz-1s!jIp>l6X_Vy}(gODDVW0UN)%$<_$EFt{Le zq0+Pf@u@JTXyWWND=Y2HFzM%K{w=b=NBQ*h>>zBs68z{%*|}|ZUpk}?SkXplcx{yZ z_Rpf89Tuw*uz|Cv83;qelofI&ij%@d3Frd3AXHgy>JXAzIqB%TvAc(`jeAx8DyLfm zH5Bxat0?!gF30OKVH=>_RYu{>>Pv)e8@m2t2-irUX^#@|3#Q+z>1SPZ%Q_3$)n>uB zF%SP2+`PwSg%BWHrA%@i^##&`1~6CRM;=WU^uj%zDb=S@pTkv6Oq`ctNgWj%lj?GDe}nP@-jq_vP-gmourkmnVWa|1(Db%o3&D*T&4Y@IT_T z2w4y{i~!KAq7(2+y21Fsjw=o3wCCPnNVdmqz{7kVuj=A&92Y+ejREENQ?6`bFE>QT zwd^5})FBs#>IvjGIFp}*05(F-Ra#1v_H|f@Tv$=-t&S2u$d6}@^uB)tqKt56g$5kg zM2TXV<54(*xkF8erZ8JjeD-kuSu{cTaOfP(W%?HF5@5*BtE?)h6(1~$7D|q@1C5?~ zQ&UsL6>+6mue-qz`!#~KXB#uKFHiMme_*z~+ScHBije2NB%$m_$w_Yy>Y$-K{hq8w zZ&`ih?(X#H&qt6MwWZi?cS-ks$E(|onf$17`=P9LU!o%5k$bZ=PAv!8Q1;=|PKOWgo*Buc!SIK9)6}2u%SFL_yb*0&UyWhhj;k>)h3eJ-Z+``(1$D1XK zXz`Y#_vUQ1%ChVnOr;jt%vCoc8=}=#cq1deYm|`+rpIDW6zk^Nx z^Z(*kU$A0W0$)twvw_w{1wv34pm~W_h1X%wkG(Q0;%~2VPAx=*ROy$kAc8a-nv#m) zMk2`tDUA@2caCV73ct+qa`|&2`#tFW>T*hK_-7)muW9T>&pv^=3{o$kuU805DbW1e z7$}tTUi}TlS|I;r30c=u0HI_$-&M452>YEl@y4^jh7&?*R`=eBh9ozCv!5`l%fSD- zU%0#7Le-S{k15r$Mw;5o6r0I7k>N^0wJrDRJtN9}SJWOC>6DyW2UMeQOJoReaARb` zlC6KZX!l9%poR&jpT71L9>a_s4WGQETJYKM{Sa3#?Cz(;h}}10CFuOo4|v#;E~*|p z0P_`FYYDrHJK$AD03ZPab(8%~CJnHkIbmMzaUr>cfZFNIJ?#Io25KN{=tuyo8+O3= z4O`z+(Ec#;^u&5ORH83G$C)JJZI27^5GZ(F{3bx*=*tAjiDkBe%IiJg0;x9o+oOPZ z+PeG}y$)<`bAA0g$%lV`4DO)^&$yV!S~XK|Mf8PZm!@AJ$xIvaK(Mpn4WF&+)7cr| z0vHstvOl_i^1XpnihwSvIsmy5&_Y1i9tn3gY=Y-bOLl)$wI6NRud4G{D{Du_Q|&V? zsy`g7n1D#TXrrxOA#MF{k!{n07RDm;k3((s%infqiQBgCJ@1K$R<7eAH;3-Z*8Jy* z$Y*$wt+GuMy=U8&=!%I*SGu};!Du7EIhFQf?J(VU4q?5o;5A`TLNcIcpee_0UskGn zUS(plGSqH2rmMZn{jba+N4UIOx)a;}BUF7T*>i^G*hBOjJ9ztnTo?N!EJLkOy}e@k z>BI--y#uvUI8JnyfpwbDRGJ-1HfvytRbR6*kQ5&4?qQmnL@A;=4&r$+6_Yf7EVeot zF>rGkMIO^YSPI^EFn^qA%c|R0R-rP$bDx`oL!bl*HVSw{zah)+ziJ02Bp$^H1cdc5 z)^r&zpEu|D9O*g_LK8E7Cb(%#P4-0e_ZGtPcOt5H@steyD6J<{{&t8JO1KQyT|^xz zUA0E3*YL4cdr=Bw+33$u0pP|~#`TA*I{lg9wRvUMO5>f0a*ODb29Wj%X=6lkB-Yo! z9Hom~90Dn!l8j=nYaPN*zl{1e-}2llnd>;GCaH92uj3UG1^5=j=U30jaQ@$vCQW&& zA)HoZ+R7!`{vs6FUMM5Hypr%Q^IIF2TBtcGj?q3xlbPIgbX)YkbtignU(xF`u;7>O zzAdVeZD7w5o`-_I47n4l@+`S4zGNq$cW8+(#>3rv-**SOK15iBElGV8u1Xg!n_u`D z68mz0Y1l9J9f*+(mc7~b*hP;m{c!U|zagE#6n`u|0X!7=FQ)Afe1H@>ZR4f3PR5?h z-pfYuW%m2%+sizieaGU{7OwE|{jjpXe4@2^t2^mSH`At&PVX9C4-FSw%_QO1>TNLt zsYAnny}xLA=I=zg zulpblCdm_D#tYte?;(QwAktkt!e6?Z@K_fOdLMaQs*gvK-wim|Zg)@JT=A*eFmDvc zH(G_A|8X(B8*&yEk0=v9O5oJG&hNzL7{13k0t)6Qx=F5+Cl?~gw>`kXF`Sj2kxGog z>mcne`-*?|K!d=V{vm5j`ZyeNvv#QK{`20^cqzN3`VpYq2?T>Na3?vQRW^>wexT9A z*AK&bCfa8sDw$a@aCSv|Y=#l$DW@-|K|c(^;+~p57XqYeKn0JMWSKaTXpSs?#zH~cFb^j&nQOlkPCG#6tGGi?4ZAJtn z?k=uKF}}s`BHDVR4lEzq-uG6^*NH2gGz8A{a!|!H#QP-$=dCHf#5M19&h>##F2#EumS@-q_JZ z+9E0){gT_mC7vc}5Eio~ONC$D5^MB?t#_xL4p%+V&jUjp*y>@T5jQm|&5&~2NdQ=P z)upL6QOO03jbVCMCcuHmehs!g4tE;oZA3IjD;Lu6O)rS+GH#z30)iY7|?uNB4u0{bcK;QzXu-;z?N=5IK zN=4pSvXP>Trmz5MjzKwH9#}-PN=LiQNh+0d%jdK9^m`7#TZ%Xh>6+^t&$)@4U`L&L zF_>_%GAz2$3oU%q_c_@qvQU%zX%DGE_Dl;v7jZ979M)d$RJPyiK1OmYy((+*)6`>*h!(npvz(rut|7z)<)BO)L4OF z`Nm>-v4L`Nt@HOiH^jJ`F%kNl1P2t9K(9)~UOUrs8E5re{fKoMGV2#xIc3b%HcU|;NJT}m zcKL!X=+^|Rf<|FmVq3YAg5ubaN+ufyA~K}jNtTFdIA1>bs2Fqk$yS4@E>FaTn}M&+$Ro4Apir*AQoA`r7_Cf)_zz>^gQ`=BewTHQ~MU`*>MSlB`xp@u7Yvb>O<;? z@u;#uxZfI8eBbaGeOQtip#o_jFOQVph!4*~7tuO@ zYtE53^b}G})?wI}L?C;}!Y3>X#rSqT4@+_3XCMBq93;F&3;Vc#aV@VXmAIzIy@zlC zW>%`wBiu-g{9obi7EWDo4A9IVy)^acG_g5Fi zm+kL$pJ-!W+R?8&sKN7!`JKHF9DhIu3eg`uL}bFlU@vaRLqCp@N2)<&>ivGdBY)Ch zlhk67exe4sU9`Y57-~q(-_bU5*cZ+8V+it*#`ybT6YT#A=IBs1KJhAFx-P67bR}^= zDUYsK0HSkJS=Cv7)2XLSEKJo%lUj0FZ5{8xwEOj|Nb3KN58I~JX!JMy+(E4MMGsY0 zXzg0hF(c<_8jHyj*G4ao<5rn6+aG3Nm=>{A_zDGZswm@xDAO3x*2Z$wFu5xNFNXIv zy5DfRd?+U?`zPhq{AydvHYPO|^r|#ihfjID+?jYjw@03_r?YM(VJ98ag6N1l(ki_EUUlABWFX zNQ%+{MaWJqb#Hy-U*eAh?kAzSwwG#jcc(0`nNy`M0&Ky}g@Y(I1wE*RsvVBDaE$6d zVR9cfl0K98yPp%4j1)(X+5r8lg8TBaIyrUdV^-^a=p;oB!jq?94UTtK~XpX`9n=$C-U^CfEAq(Jukl)ho5z^46cA@)Be+ zKN4cZQ%FfP;VhD-%CpT_MoniCpRZ@iuQ(daX2|Sn5H62-EEw9Ssu%Zmqj1pOQKLgA zjuu|FJ}s^A7RP@lFQn6KH@?*jf^VxEU1afcQgT$WUq{=z}J$L;bIQp{5(W z&EldGY=n)kk?IamhEgHEx{h327MS_e44qB?KXWSX$C4(gN_K9Xhnz6HSQhOkVO;Et z#NK!>;Xrxw`BsIy8coM_sgh@Uw`|P5n^2PkbRdD&BSr_q$7oRyre$3e^FUL$lmsI- zih7$c=`SpC(;c0OiYU zu=NV6Lk(o3W=#7ipGl-Hiw_Q`40 z0J`{t6eik39vSIxO~~EU6aM2Mz#HQA`+cG4DbWpGhXze($;+t2g-^KK%C z3+p5Cp`4G|YRmZS)8vyehgE;g=<{2|Gwe>_!)vfjVM{<6=`?9oRP7p(XEmuW#gZCi z2Er?Dh8}%PP5ed^CRxN5Z!IVC$B+9kzeA{dExF+QM1ii6*hV+3%J=_{t-an}jg-LV zL!P-(h!jvveD(Os`4A*0UeDDG&Mn<$E8iO->Hhv?rBaAGD`Ke{OCSz%C4_6QJJB8v zwxC;WlLvojC+SylJr;zKQr&>BsTq8K_4yOz3iu^1RGHqy zFE1QGkG9I@L&a(ZZ~N8y&mHRinaGec%F|{2DgE=zIDonHoeAp-Gegq?z3lb?BF2R8 zXPSW5bjOAurK#7k`ei^&o7n0}0dQREcVXRF4)$b^O>ib4R|=Fl_;2`rw||^KPCYCN zf0@#H3Ms!f#GYifqrO4p*xjo>9f~!0?DCbryiq;e>7dp~O3vDN*@|R}>BY=vCUBQ( zM}MThbOv+9=ra>$b|mRobiO z;zyI)E+5$ce4>QJQwq6xNcXsW>ibtO)g_7l=k@{6h}!|$`kElR3U#m;c{}HgDz*=U z1{*_5nIjQGk6e0I%F*SasGCMrkMHXEzBe&9kXtoLTozmr$A`%-LL?eM;k*3>%pt>H z7Q_CSA3^yLKc{}1H2lY7(}Ump-uS|vpWT|09K5DDEaZbS_D+MTJu#3eDA_TjW|H^K z!LvgQo#WP2anf4UciaAxqR89ZLeMP_#n1ZEB4f;+YB^tv_9UwsrA?q*&DM_esF3pA z&2eY-YR_QnT$|KSk!Y9vq$SS$3nnmflt9j6ZaXDh0q$m7s0|EIZY zhmYT=JZ5lMh$f`{ik97-FHj#3F=wWQ4AK)EBS~70kEo=RIx^ROx9tlmUSsp#t;ryo zRoB$vS>9Nc8HEdwSd1&8B9r2~dqI}s5NwAk#5uAs(UL}5GOYZYm4#U2(Oi@%fLNuk;aPNjTkJ-&5k6n^Cs`Lc#6CdwD2;~=+NExa8xtXTl_Hg*=O!wSWD)tX0JNkdkm=9m7>T|xSJuGczO_FQzJ#p} z{mnO`9OadE7YBhRTz?&U#R!<%_HgGP-627U3Q^zZnVN2l=2ZOcQPzq|Vtz5RgsOB@+!h+&%E+PR z^+av@`0(t&#@DsfH#RI|*@G4FLTn$|d5#73|1q|+uq)5lmTgp-0*ZeoY-)1MdQ)7N z^0f$$e0Z6G46?m?_RlJ>;AbfDcwgDj zO4M5GG#3f+VK*yGClKbiZ!-BEM`IPqWu-G^Kb>lSF@2k6i_3# zw`>NNp`7vc1Dsx;uy4=Q{)X-Tj8&%Y8yJhst0Z>A;dm=Hiahq5>ogFH9f=R9p|ws# zmP|UYvvOdZsgReXFzDlrV&rkdiWTy;>7f1KElD@Zl#P2<;YV;)q?j}V6#{l-Z$eZ?qq;1V{_+TLu_k$)Il z8&`hO15DFAin_PL1<}*dj%T@tr81QjgL#;KK7O>(ewwuLlHL=VeEb_e93M;Qpv>#J ze)0$7R(R4CO1;hxX9mZD>s>g>{!deielPm`w4YD{i0eaHhQ)W-3;XU6IlAKlcse<> zfpR!{@kmvqiUDYv6yBOqXZg3ID&aK~TXEA8K@yBpmZemQRso~y)- zufz?c8H}X{si^>TJl~JYfWNlFcSc1Ldz*x{uxx)EbzCngAB?V!j(2P@-sW3r_iUgX z!NY59t@$WtGs{`MY;F47EZ~YrO*bYHJ#T=7*^s6k%@uM_JXPMv*=ROaGH7 z>0l+=H3lw*(Y|bMCJhZ{MR|34`NqGE*%hPqFaOW5$(0BmJJ41#@_&U_UMzWJcW+>jdl26zRq}a*z*8Zs4m5S{A z`F#}=bbFBrv=GGFtu_htUNyEj?GP?kX3^oa0-IP&54R*$UHFsKa^MCZnwq_kebyKYN&)QhE_x{up`Yv2;|QMXp`p5CzqgDp-IB4 z`F8ZpSCHfRC%p)XzN zofL5c8Xkj|c*=wwcK?7GgzHb12^nXl_3cIPL8{U)7mpu04x~1l``ZTlySvw*7ANpP zQ*ay6)!s9%%SLO;gC1|=17iNmtxcm4P2+5ZlR>?%St`GD`B;hH@Q1OoU`szqIEOnK zgFV2%o>6iW5SmfG3VXcGxahJ zF&#(r|LCslV@xYCED#dRv~YS{C}EUD=i&66-qNvu?D$V+^|7(Xe`_JMS5pnnz<;AL zpMWOWG(n&K=->xm2$fH+wS+)OA+bc}BRgo69^|o-aDW)Rz@ce2`87h|v34)tv?O?n zZ12+Q-g&x$(tOYvK$A5-O88@H(3X6pgV02gKavr69~Dm=Xu>9V>rjIqx|4`6;}&bj z-H$=o@qJu2&EW+9v3OZ4u$6O6>p2m=VaPD&c&d{~px{FQ1`E-LJe)-&_!KI&^?~gXg;qP#LWcJ-1k52T~-9 zt1p-j+f%Ijnd7Awm13VwuA2#i3*;Or^F_)o<#hv5cqmf$mmVIN=>P_iTx z#ZUdTB0Xc${M+iseTAk+MRH@*fVhoMXoYeLZg;p?A=Y##y(xJ15HWg7v0USHBJ6JB zdUP$%jfAA6}+d}iK;-Q#Tj(sWd}kX4Sm#rR+{psiKj1fKPzSh zovL*C!@j`%Sx2x_zE|d(zD$^GRD}GgKHN!6Rr+ zLBXTxjkLJ%E3;|;17-4M!K{JdAD1tcZFIkUAMGOk-QGL^q)~HWsX}Su<`vj9FH!m( z+-6%Cl2tmOmdxMjRz-?&3SApAPuLe__=o)I;W(wN3}g&Q7-CqQ9|Q zNeQxUclZya<~H&X3O92xBi^|~fEdr(tg#Da>*`13V-95cBr8_UWP<;4lo_{t$am*` z)|KSn*FhjMu=*xBiE?%Jd$U(rR&BE4mS}&vDIPWIz zV)gFj)0sdG76siLygSNjK5Mj=hg{XXBxN|hz(lJ>Yw+1dq^U~zoE#qr>bWtEZ7df0 zSr9x`Wpg}N<7=GYQsDCQAXR6;buh|k_0-{BL=3SK{~VcffhiGQt^TgBY;F@U>ozpTCXE>4at zOQ_-i1tD#A74?S_)cHf$cKvwSNPdDXuk`OeS+o~o(`@`6ky(rGqFSY%>X~u8@0xEP z6K!m#%&7$hNV4%_i@@oP+xh?Vj33>Mrjo+n@cLR`pPGQa5KH0-MTHF0i0NocodZHl4KF;IY8 zFJI<7;C2sXj*%Z%NWGZK;$3r9t+ETmxwzO{bfjQ0&Lz`KPvtFjsqj*{UDWE$Q=m_) zx#isDm*HQ8N(YnYM-_{!&LgkA}sG=zfaZYEk;o#sq;@6@6!h8Y)AX?+Dei9gzs| zOAk#`Of0b`bvfpqhn?;N=$S_yk{|GUU8QlR>>8tH6JeO5OcgSmBmJaHHiP)&x^Fwn zIF{-Y6F%cMjs$jtz&P843b@!kE<#1#9zIKT9dRPhMBty)8yBqr7GF-W{@Hw20Bfnf zsI;3TzoK^%kw4&Qlq`9TvI=@UvoJ@~HD_5&SY?by;VWOQI4t~pOM%xj(&Q*>gd8HW z9DSt{$pM;U=!`c7ayn*5{olqO%IIQ62TlWaB~2*L4yFk~=&k$QC;coL-+c#Gyiq7% z?bcU}%wgGnzZ!rpJW(vR8s_4@`8Aw=xQv*6ZVa%U=tvjv!*7&^*1fCp&RYipG_kgS zh1cvl#=+-~8H`?Mx9{>w-^a3WBFQ42mKN1WE$<$w6Q)%-HxaEo&i(l`aqgJ4G{Li-!&YfC7ANHw3v7RB&Ly_k$}rzPE+l z>L7RiWM}L4&wS|uMqQqq2M3d!1yEcS8TDi~9?QwuU|F+2Emai5N)kWrbV)DA?k_m` z5j_P`e=p)ET3n^yu*;<&BX_yHj901FP0*py+_2?0lv8iHV zl*qb7HcgmWq69tyv@?IVNCv3?W9ck|s%qOdOos?aBORM=X^@nZMpC*F1f)|!8U*PE zrMtVkOS+}IyWzWe-fxB(Mn`|ZUh9rCj>`lH#TCXP%(wLj(nHfF391_F;czM3I2Avm z3!kDa3cQ}O(j|b42FNcYscZ97c&Q$St4s%`n7kNffu*lJ3f<+GdB*yfW! z?iKe@FonkN_z^vAj(Olh0S8qfKKYXT3>v zx7})qU-J61AAyrhs9=7XZTixFPb7;{KNpbKV)o3 z**g%nm3-9TI-LyK$gUHEpIcAPT+(+)1psjIJ=DQqz4=x-at*dNKGmoQ9kfN69M;QI z8>Oqw`yCfcXO&neGWx6n-LUSzAdr)%7@hGuo`&F?Pn))S@V4hAW3BaK))ZU#&x5N{X^l zF#s-RLsHdckinh|Muu)_TswJ1{uPHdkR+2Gf#Q(cehPH@JNsTgu#=+mCy|S7?G1Ms z-yg(e_*b9qmup&0`-r2Z8so#O-9dvX7pixI$T)CV!^MK}>vdF$A;!~#ypcMbS5Sjj zi^STky_<6_B-Ajk=V#6@1x=f%PceT=1dJ2vcFzJ_R;NDvx0Z8k%roTJK7ZifIoO+^ zDS^GW6!+%;OdO4s-D`SbZZz41X}$MnPx2SrVZP0^z29m4^yP0FN8)V$o$%zi-k87^ ziA`tHjNS6;yi|mKMdC4*)8==dS;ZvPGwQ#oXZ8w9yJLIu7iAR)XqZ)A8T*lkeD>LrhRzHNMZIm%+TAO2a_^&H8joS@5#fAh%waS5rZnFviOY8u&{B><`d!#Ol;%Ae)vtOEIPdT-)*?9|aM z!Eva5=Jd7JYVEw$Ycj`V--|_of8@9t0(k^qOYxQScX#bKP&D2)x)PaTSGtD zh|lVc_w8GTSAZYuip2a+F(q(fFAFF4%E!+G9GeVc2jpYrs>vBE#4>a!7P46draC%g z3E4j}VN-wZvu6lMRm?^C-(yKbG<`GGOlWTL_D#%3q|4Q?>_=xq2=dxtulrvrGH&S@ z>Z`xAbWSP(<#}gE#eXa%=}rf8Qdih{*^2T{XYG`Os|aFRogEq2wG_Uk$EVUxUM=(K z-^}L`3+^4e$F7NYH*Ypf|IFIq-%F`uHDCmaf+>tj?OPH-x1v~3(buRTbM`2)=~&HV zdN}(nFN>)N95!MtmDJ>OHz7rtfs{7;>rq>kUa44 zkjtl|<)j5-xCqn)q4RX0_nvNG`qh~!G}IJs)t{vQICxw8pv6`Bd2;uo5xymD#s6-H zkiF~*S3?TFOg2v|(C>{^?s(Xa<*j}l%vDQ>n>KF&g-rX=w^aKT%h8V+^w)d1D?%!r zW1~;8`3fF`WtVc7@M8}>pIPP-bMr!g_VpSvVqh@VM1(s$xN7-ZN8ai?&2fu*`^!h; z>dpz01RhV{TKBw3RESknbH{Qgb|z*gu(x(QU&Oo&9clr2)6XIPZ}Zi1AX*6#e-vZ# zBJ}wM9QgiwQ@)IVYM;w)b>~xYy(o*a5BrJJyVfw7TvaBp0E04NS$w3m=^IED?&kBU$D^JFNYx0XztwT2mg z-+Kp^aVY&k8JtE{SiDgkk@7OqeQ`5UB4B(c)g)L!fvy!h7Sy^QD0rz~Td$1eUIT@; zVQyTl^J=O3;ck>L;d4sQRJ{D^1CGD!?goKOr28P_zYcHG3Di3ctOQYO3759?` z(WH4KMOe7bzAH;Q62qlw>6^Q#H)v|&hg&kZZ?)7aR*iJnsUyxC7ruDh(MIAe`(*Z# z@w{(r!V;YlgIO81>Fk~m_xHcY_9RK=s&i#ChJe5Y;#BbI5wFB;{B!@tvnQ2A6tCM^ zEl}PjfZu`@J*HpFfQ#924TqYFPF6~hR<W1`KeJy-BX7f(m?~&*L|$R+Dt3wsSr_ zqMP$s71m-D)seUxd?jp%27Wl(Vd-Iz?n52{hjT}k!#ZNPA2OY&#@GrcOi-1R()D(H z!o%-UZ$^XP5e6PBMcg17fY!L~PIMp6B1QHc3A9<4=+^^}!C}W&e-zQ~n3sy@I zMh0cLn!^H<&aIC%M|s&z6=9(J)UMdYN)FYlh4_GB+r*xwys9+!kL+p!TN;7@^uh(| zON-ZC3y^my@A7S50Y?PTC@MZckd@bs!CRa2sVC>Bpw55lp}Z038xZl0zuUO$vsSOW z8>f3XqKQB4n{ZdUXGX(Z55In%acpay7B3Wl{U|~J79hCek#|-4&)wo>6~Q@@|HzNi zwB#@7Qs3A{+ecvYe%9p6KqmGs7miw~&@9WHpB+$``QmE8zH50E;V`C6B%avE#qe3b zEj&&LLeFuq&N?hVf_;a6NgNPZdsviRJ}09q|6}#EG7{9QlS;sy2xP=xYTAJ`Qtp!8 z!mK}L@F?(Ako{F3o>*6dB*@;76R9D?QTlZftOk9g&B8>pZ1!r4 zvA2idRhnNAK1!OiA;nH5ndItuNe)2<9o{%92OUtSEN&DM*o zKJ^Alq>1pXA~KHUN8+b8>%cue7e`bgp4U(KOb7+kn8dB_I!JKLEF@`i%PwTn8B3i8 z{`bpayL%auDoG?-p@?m_RSXTQFxpF7D!G;~o>hyx{c}!d_+Wfn}@o8P&Is1N`Cza45(G^a>PA#lmUXU;YDLUeqx*({?{)9YDze>*;>6ozC?o_`zQ!Nm83OhD zs+wD{UIGlv*y3Jh`hPs000|Zl!ahuc($OJ@X-5+DN{|wx#K%643@S)>_HuF1DN5#) zgPU(?4=mUg{QgXe;y~=6bNu+Vz~cI*A=;L_=g+Y#6zp$Fg)@;oG?F`N3b!aUwZT(A zQH2aL@_*qACX~E%;W1e}@5Xhqa`~jC!zl%Z#hVr+B$80#CnOAi5NpOsedK_R)G#({ zxb49k*^Jh6^I<;rcFnBEB3VSzYcluf-XBO_jg(VV#;d&cg7n!s73KTx~A%wx9EBxM<&_7@R6{SntjXuJg*Y%`d_1p4%Liqb67O5$8(r#WO z7-R-Bm_LY}JLx;Gpx8>ow*P?Any^Q%sYzY`z&HE;TddnHFiRRJp_!Y-fJF$9gw+QE ze}#>rUp##b)&0j3(xaq|ZEJyh$H*hsc|tBhpGg5`=2azvz&go8sTYLm`f>`8#}9=khlRqVW!`6``PsW;&V7$}sO$Gxi0!%w!BHz5 zPB7+2nCzPx2Ya*?J9q+$3{L$B8T$@R)yY>g&X}!V>8GpUR7RoX{DbJDn2g5a^t&FA zJIdRHSqDjx&X0OtF*oav-)Ou0RXHPtrlKjl`7I=CR2e@~LI#dpU`+;qhc6aaW8+(y z#R9@+>Jgxd<|FJU%qp7ajwd)?oJJgME)_M|xI!!!VU7JjDm4B4%pU7Ann`o}_qzU? z@uOR~f9Fyms;^5HOsR-70mUKZo^*ap!HR$wBSxqK`G}{s)n#AfO$ZWR z-gJ!YS~#2M!h+ipe;?u|6E7n1V6ylcp_Gvwx<7!EPPf+{Dm zu{yWUtMVVOP`e^B|8t;0h@*Pw;PL~IWtw9HdRvnvg#ywFV4$k+1Jf=ll*a$NS5L4K-Xv#fd0u!itVco6y@%Y>U{RSh?344 zooX=(g1BhKEdnHoyu7_XH7(I+AzU8^Kj#-*f|z?|^{@h{qR-&(adxd6hAN{OP3i!wOdEmT2W!F}O1=GtLaHedgU!zUi{U}=9k z>Uc$I*PIKQHzsmN>Y($;Yz)-9np^KSYTq)1|6*qB2G{La~ zEDR;p^>nbBp(#Kqm_#!T3LB>URpwQ*3wJAfDCuX_*xWW zR*&B$CabSYM-bhzX%@bGGdt3A0ba%PIWkZDg%#I>s7v$wY)$O=h7`@ed|nbSivd~w z;FBFP5!;*MR}y|_Pa1~_bnmnUQLa?F55_K<8h_QO*Q_Q9MS?Curr!2^&AQT-M)U^u z6#Q_HDzQNSpOm8Va-8$qP8GFKvR3eJnDoxm0#Tu1`h!s=tvw2YxX|}yWI3 z?l8`wjE?b5KE+yJW=tZ#X^15z57Mt!d~Akx)OLPOS)y>;Bf>>a9>@9?y1*0#{OU3W zhh=Jm$ToUk3YiBx85+w1F`SQ{wg|s(I;|#Sxs)qRg*LUq$0sMn%lJiDwcRSN$yI5x zM5S-WIej7 zp`2)Mo2cQB)GRT?+xlSa4JzgLZ2m6~qr4P_z_7GhPvV#FanU%Vqb<%DzaPd?s;beE zlvPmyPr?n|<7>UtO;|wLD-*dBC**@XD7|lgg;F}LS3lLVZ1C&pNPn~=dWj0m^LNcc zG&@Mls8-OgpY;bZZ9mxsa*j$ziETM3m8+HKLr)3+LcrHKS&r{=$wJqKouEz^daN*K z$LD$bg^#Gnf4PYslj)o$g`iMaJV3@QB&56+jiAPO2O}&ea2lMZ-vev{Y9YC?rYNtf zS|AWZKY;Vo|MPbkWw#cyZ<~7^bdbCPJL!ju1(UQqCb^x)W;b4T+8kWcOH>Mxztb3P z+bAejnGt`PU-_$W=t!#Gt6z41_Dy`jHB|;ZQib{5#rYM&;;Ktrj-R3_mufFI${@bL z4b466i2v!BJRTKDst}O4_*Q9+VxhDs{UMAsM#Ga9O?qQQesFwLPbx!txCqhULe`x# zs-vBFAm4j#Ns6(I6AQ)K6IM+wn+YKe^fcG}@s?MVcTqpU=F6qh=V?ALGA*84Of@X9 zAwd3RY0KMNIT^zRU0Du}V9)y&5l_a=g~-3>CDB>yr@pFjZm@T0e{_PDkf;{L8pYgd z|H^$#dD9|Y5o&a*77Pje2?v?)HgsV;XBj0qt;}bhY`$k=Odtn3IB_F;tv(Z#G?Z0wFEUYZs{tlGU{yke(;&KujRFJ}$lWOdT*YY@cF3zJx*@!NpYo61 zVR$pzT(Jtvkdp*^oE-V`^QHzY&{M0;G`_($xzORg$5Cy)lZU{O=g z-d+%g-dx42uQ<)s-D8E8YZ#MwIgwf&LgRuPw!Wpej%D}-e=I~AL@&|qd1WfZriZXo z^3lReio2Hu>)==OB25ywQFuAw7Y0k;%zh#e__dD&J$FCdAo&+~|iQJ`s2D zNTr_&e0cBPrI4YML)+dFqD{zf{&h&UI%+qnJWaSJQxei=61yW^DaTghgxDo1FPTe8 z3*)6A)r&Q5j=BR3_#_VsrN7Y}=I9pS4^0M-+4NyIai@kOn0sJ6w0d6-G? z>Hdbfa}S9R_TpmXw~ty*}Lhcf|>ScU@IXMf$30)z_vMCC1so@^oxy zUGJ$@y6-pmWi!;7X)|u$3A&<))xPQe!GjtMe}mYZtOHxbC7c4 zauB1WoKwF$&0Nm7dVZ1_eE!GI_&b*YiRC!pjCvK5mF@eas&yuHJ2WXj-qVfg&~b8G zy2ak}dBAEpNhTafGgab=M=D~Ypf#Fk)ch7;iX%=Vi-JshrzU?%j^OY1(16jLe**E&R18<2Gb4%q#mJ@gz?eej(%c< zDWFO!7G?f+`pjT~{FSczTXx#)Eqg--j1v4`AP6z$Bab0_3v0M2 z{E9zzkdKmL#)m)wI7}iQnqf6@|S~C}K?${rnj)dONs?JM%H=FGXvzKycu-EYn!}SU}L?wSJmu$LXS7u`DD=TO0 z?b(2!yprk^Kv6a3*zjrgWH`j8m9z~cR56l?_}#`X>dodYX5OC+*uuxuJ_6zr$a z2`L%dG!=smusgRttx|yl?=PW7mIll}+sJMYCr9M78uSM`OK9Kb#7;<&Lg9p24QXE! zpom8TDL($U=QRbhh7!J`b{tg&yLf0fSUdn;GIJDzG%%CZXm;k{TBC3%CiF~-IcR%l z{&Urs2dyEQmN8~UDmG((SL~Ml__9zSr$A)Sb4#!Vqz-S)Pf*m6Q2X77n9X0+Nb8E& zSsijHtILF9m$SkgsaNW?gr9GJ+_(cRBjMsNeu`rk`g;!O#;N98L# z2!Ux*&b5^7WN}K=P*vajLi7aT_kVT$qkC7u^Ii$E@{nIvFU$BEb!X872~>#5;bys` zrX7_!+)sa=jzLFI(aK_tF0636UN^tu`kF7Ms_?$AcHrW!FUJY-Ry_C>JTh(wCJqSi z=c56Du*bkbb#FAVUAzu2G4`z8BaDMJx8*3AY~E2hwg4Cc{h z%JxsgzPehGB7RIdL73DH{T-P>35WdnpMhzk3TNw3D=Yi4f|a+wgO``fG)EJ-Hd*|! zpVY+1CZ-KOK`^0H%9m*|1b(RV|w751~IS54q^;*>$vaQ`D*huf%Le=pc^7)K;>b?dr?8=6!vCUS^D~5Y z!SRO;>((3=9kxzKw(;?kIx9I1om1)X{jSnd8$T(Xxxbd*<0G~?PCsq6iF&Lr3=|OL zBoZMoK@nbR)uXw&aqpq;C&RUNBsR4Dsw&|amXOt8&~5Bup#@k^df!8XzTI7Q@3)On zD|ICE$fy1D|00UmMh44Dq`E_L=_=0091y>#6ZM<4l$C94obX_~9tVVeQq@gRvQ$Mfk9Gp%_>V? zmdw!*#x~e#oovpU>K8(IUAzHKh9G>&_Wuh4*dl>6;r3n1{lyilLcOT0)$D6H><~#tpb8cJ z$8D1V@Zd^Z&Y%i)c$`LQJ5^+WEWFzg{`Kur%*5%4Zh_aytnF`Oajw^0yRU8tkDFv#o-B8VB9R!4W@re_0L1J{-Nqkh=h4w%lcF|89 zUn)cuojS50Czx3JUmrCC!Iu=;q*L&QH+K<+N^m04U&k?t%mR!(f`&ZH9mAOxHpx^Uw;Joj0mF?@`Bwl;- z6CrS^W3oTrV|QY(ZWoq4$QfP890)*_CX#Xv&#mI*wwpz4Z%Kpn1<8BGJ!+yOxJAu; z(G`k+37Z8)aQ`T=*dgdsL+++umnvJ8wOx__)tQPBXh^L4j$yX~9*}xvUcw8TUW8*0 z2&LuW=7lcCSO*1uTJfS!WH>@b(kZCcIxyK`y{*>)ZKj{xin)NsDU0x7T&u25=f`?19O(sEfOM~rR#+j{d_+~t_3}5J!RPa zu43iA;y>a3OQH70+=n^?*9w&Rrm;pcGzO1r3-T2XlBPP8G>#IOH<%^1hV48jSIM{? zmnc1EvT~^>&Cfo)E|D4$<_6L^v1m4tqswy6+wrtqD=B90ohtc@ zJf3{`HC^{BZ0mD!EUKoQ70Yu&mTZXij~5WX6q)zTtV*)G9fv_zKrlam%EltwM8BjN zPw%9`io+ipyFYWKN@E!5O$wXB*^=2zd8??%gI%i{#IHoC4Gv>sS53h&aYQp^^x*AV z@G(v;2ni7YdT8M??4rJ)v z#mm5lK(sB}9?2Qh+b(Lj>lShsSh3RtNuET11+Whfz{XDY3SE%UIM7CWS=TLY6t9w#sOpUntehEG+<|Ljf3_VkEhT}?GIyDF- zv2qoP0to}yK;ZN0t`K(x-=sa|*UI1#Qf<|&n@sueN*LFsYCpQ31TTGE){)V2hf?LV z#)^a}V!y2&lvwq9nSnvUt;g?sTUqHo^(fi7us?8m+o@E$Ky7Nsf}aYtA{AkbEaP0* z@y+=*(09!);=J4P1-g1x`W!kUN3|m{rNSrbciO!K3ilfCFx2F6aiG`d2oxju>by)z z7fYfUHOv96r{{lo5jy}q68SXft@EW&bb6Q}@bE2Up;-22_t4>xmP%!z6;2n$FYj?8 z6xco@4`;h`Mj$ThQ0B0AN|f_ANYGaiYd`$qMJ?OR zFNt4=(o((?M*LHO!}qXuY9yC}`VMPF!+w%NX(qklllT;G_LZv{y$*TmvekYDgTsS= zwWcxi?S?B)Z((*PRC4FXu_k2f;pDd1-;GELpJ;I03+J8&NYHHPGPe|oeM-nIG>D`9 zghO9SRebezZStNE(tGZL-L#l>Rv9pc79sxoA?tn%qQaR4>>VXNtc}SX2VY)&nxN7~ zd5GMhht|PURgVk`0PbePbSH359=6MMx_B9zVSHt9H(qK@0Mvw+HtHLZvavEvXl8pD z`-zTsd?;X8^~KbStiT2Fj#6twS$FqC@qq=VCl&RIA6MMhu^A5eBe%H za(+r7T~&!iePc-*x_Dmta7e26=ZJ*`L&E}#MgVvut zLL?xVU;5{yA!ame$K#rCO(Fz?$vh32KPa^ZUcO!3p}ikY_4CD;JR0qj!h!|aywTXZ z+m45FoCf~rvc8Djn0|+OjTkzZ-LjldOZm2-ocnzh2wPfNlG?mXwl+^3W+@95W_F5C7nuYYs+Go!B{e z9r?zFv?gI$3b66V{yw2M#%>f!TnX6mfn!XgDd`Gq|zm+8Y}FX5Tpc{jiL<@Yk}EJyf{-uHjch7ddu3-6W_QXz~{m}`D3 zy86P>1>t2qc*A$@WP3OX0%8f?z^WLosf2QbBhJ8;(5VBBr?#at!* zV3{y#IQ?d4h|-HFMI{wgknyY0E>w_-3cu!N6r^tJ(vedRcNguxeHk5-(wY$gv|qNt zD=O)rmd}yB-)EdJle1m;G7q0O#AuL1bAIkuE5J+RjdnKcV^&|cNOiXA(x@yL9$-VQ zHBuLeiihT1xIIE`P_=_bGK-M7hkBTw6Y2XF@t_g3Pv;;0OV$w20lK5?zuNy?fXW2* ze>|c_m9@`dXehj-E&3|km04ZvtG%R~CxM>Qc`e1uY`{T!YEhSN(nphyPfb`!-9lIL zS}uGPN5pv>hfR#9XE!IV`6xW!l#xF3P9D0HqO(G}gL2+n$vm$|XoL@{e=S7|W zq%1kS>Q-M3YD56$5+WOI8_7<*kb2FX?X`$BMUwN2aZKi!+w{|gJZVXU+Z#? zNby2R+!JOHL_P=&EjK|^kld2(jKWlSx)u}zx!wHxiO{O%rr2*r?$1tDK06JH2Q2w` z{MRgpJ`UWnBYt#=iV@WF)ju&|lF&G<$}aK0GT~XXBP_ExCI4WQxqrbM$IuwP2SK)srVYj#}tY!Km&>JEw6v!Wr{OV`S$F6z7W2 zgEd)PZNbLtgxvaQy?-}mSFP@}d$yWKwo+=%=w$<#_16B2*6!lpFq9oZ{RypBe0J`Q zspW^D$6<`mFrRG}gwfL@K7NRPnP#xhtqyFe1Wp0p(9z_+Y&==Ro=FGbyU}dc#}Hc@ zT|eFJz=p_Zq!u9t*uej}0 zV4>mW_Z-rLebL#l{>$0NDSw_G03POJ^&SNIdf=_bCy7?Y2*y|SdaWeKCGS4#%@I_~ ztb$hllmdy_8tJiUMYv(em_rh&7hZMcuW#voCyk>A6EzXhaQ7A&q{pZsZ65EjpfrQm z?y|!=y=2wj5b*b!Y5T?`Sn$EAq`FkX=xex$5(q6VO8eG&z03Y)idJZ?XB#5H=~;)F z>i7En-{KH4+o*ame1@+}rDnGO;d{k6#!M>!REl8}x@OYf{M8N|<>%G`?{6BwiEq1; zi~TyQ-F^IYM-okwW7j?)TGDJtAcMDMSpHM*O^fFzKtJ6%^P*!)tCGPBUvN~Q0qhY# zv(s*E@=amUles74|Khem47$UZUyehTNdEeU@8k#jbvb|X-L9jS`DHl-wVvPuQaGdy zp18}8^Ym*=PRtsbU~V7-7!a~GH1wWoiX1$|X3Sf)jUX#Fu*WTviD&JEGDoWI*a0xS zI@k{nMj)Ap!86~Ar>o9M@O+P3!YgjPH#WB`Ce&_X~Z~D&K za4e94+?Z4T#xTTx3C91+x2iFh-eq${8vK9(TqOb4={$n2H<}KbRN89nH>AwZbK6En za$XBUk}0u;t)5iKyJpL1TJ9eZho`KRYPC!ffbh|S8v6S7^i{2F*m@3~Er*M04Y!|b zJ!9Ke0IO;$eS4p6DuNE4XgH8t7o4Ulj1-8UZ$_PfuB=hr!py@+&bdDh4KO#2~Ljsu;x#BE^}S9OlrazG=U%v zi_6a|4eAM3GZ*MJo%B_&{|exv=a{r7VH!nJ2cp8Hn|qawOVqhs9OAK^29gJSuGV=g z#OqfX);w(RRNgD|N1?S6(mr&aTX}I8dFUh|ih*Xsoavy&dnrlyrPxX`EN_-bts;~? zvF?v|e<)3qZUo=7f|1xHQ9%;vhn$Az$ zi=GCPC*wI+k6-`Ur*MgeAnVLT;=Jvqh!)@tjV1j&(Cu78!Mi`ng90vCqJM=44L?Tt z%g)@)4kW&o5BRh-4#OXhJG+ZyabOjG;${+|PX9s0ArDT}qSe^DVDIL^AUv*CNq1~y zee}r4(BR#SE?aD)U`<2^vUDavZ-X2T2ZuP#Cn}IF3f=m3wVUb)g5D0Wk2r7SQIm2c zLut`|Ktz-?d~pV;PYzj1jr)ISV}I%eGxv;N|4%m}A8ppg)OjkU&C<0q+eSarpF>?>Iy)kIu5L2gzM>B=ayVFSxAUu^re`C!@;;fZ!XqHUK|<#a86| zu(8Mujv5NMNbE9Au~9R<&kcV{KJ2{xNi}8lh7A{rQNBXIgg9_(%vW$)1^yn#N~7o% z-co%Oc=FKpiI}E}AJ*;B%kPID14JAZcx!Vk%nKwoTP#SP4Tu~6&5j0oxe&9DCUfB` zn9TaY7@(C1VVWSCN3KS}G~TxGqDoZ_0%%`3#Y|5v-afd-oSQlZsnd(bIOW|uV4Pm> zKVexU$&=yl7Qc2`iA>eDYljFvt-3O5M(}6g`f&fFqkPX=7Td;F`(``Kwt_DCa#=9EdzsEkQb~3crtrg6G}h~3Ae8>1(^{-x7 z)sY~n>HXb>?n`A<{M_zlhsnMk#N;3}ya>&4x$J!n*Yp`$lT^VmGI)P@hOQ;iEdp%^ z6Cu*tbrnH4gW>9JUzWnrlX52Jk8(S)glF2fQP$D@`bXs;Lfq{q9$=%QHu6vW%)!Px z2>Kqzv$eY^ae!)sO_v6bqIMBqf1u#7Xg)p`~q59HOi6-iq=jaV+S_7F3V9afU z6RqXD_c3b`i8jns)9U?6b+6`gR~(j`Am!>`cga(NCOjJF!l~qxmOjj(kCkU(xAMBp zd_HpAkkiofXpMJN(8&waEMxResUHB$8~o0UxDcp|m;lLaYqa0+Hp+wj=7my2 zm#};S_WZXj%})5GHo}?>6wyvgc3HNInhq=pVyBOKSr_YGZF-;as>xnW)hOGJ`Z`## zWUtVWcI)C72OKZCPL{tLsm_TS3sGK}6B@o{lukg% zGbSH<3LlPB;?;`x_QZ-0H+oxGsC<*C2;x5;sMIko9jNGNCTvK;#Do5OyT82)vF)Bq z3?brMO$#FiTLpBTe7*C5+!gy_k6pP9eMvFxeu?$QcxHx<8j+CTaBB4GK*Buc{Ol)l zED;;lf&-F2#U-hT&&!{(wy4?nA5Lu$XU`tcCZUTdE8qt0t?H~yAD@2gfYrwK~Rh9*;&o34FTxrUjoC2m$Zw%;wHEch{r$o z_C~s#Hrcj%cGR;cI4tA+hZZ9(2>u9T{`5xfS8;dkHNNZhqUfIEHksq`KTDrCK1K*3 z6W@^wDO|$MPs%qbko9XpOKSBS>_r~yK3~y4lx^%^HiX^_)*5c5yB*i=x&g7(uy+GW zoEq-+X%!A=Zfm+{$=8*Em$g7@p15D9hgC&%x&?b*ozHsD;?e z6O;XMcuscb0yAX~Io(+skZu)8bQj+kYo_h|-z|MD)l_+4)L$`pj?b3NZl>Aw$mr}J zoM5#q=4qGhIQELyt3GP0@w{*U5Iun&`uhA6)59ha%Jopqxr=6yWH=n1)vJ(et?Ole zqG^CyU5URg0hosC^ZsAVE8$w(AR(GnJ~tRg%sDm@LJ{q`Uca6sCAc1uB{KEgiGUmO z^2X;9RKkPc2jk0_OmLn6s3{hDk~pMgjR=>guQ?Cbg>_rFZ?Escg;SuHw)y-QQT_R^ z=EkSh0H=uE=lBZ`F(t!=v{E0>PS5Kn)cC|y2o}xVCJ<}Y->rC z4~vik9_h`1N!DiWYm2ZgAUQZbaXc+o>a7fn>iP|1ETw@pAdox$bl~?gQDj`3)ZFtG zbkcstc1Q;t3JUws(@~`lQEi9%cGu|$XYhLmO-wvlyHy9x`(aJM69;o~k8XDtv|R@& zUvxMC_z-s$*P6UF&Q0Brk-dEO=_-Iy#Qq{x43G6fQu%)+=A~ij;EKp7ft?t`fJ@oC zqfUzcQcpdcbC;?&{c?=i7pIG>=Y0q?0& z1g;|rj+^O6@a~$Kc);3gR;02X>_D7MOekWcd_KIbg?h4O>p$>N2l)XswIKxok;)5b z*QLGzJ5XqT8na9GI$1r5pPDfEUW9^awZOZ_OJi}<&Ei1~m+lmU-@pQd<| z+#0O7lWx0Dm+IWz6Ng4O(iLNi6fOJuF?WCE zJTO0h|0nZvJXI8Pf>BDu_up6y&|sD%TI1Z87i9h2|E7Ro4un@L*=6zWInAU{5OwGF zRBB2)yj#7mRR;4)jB4S)oZ^CBys5zw2v7fQ2PgP_A*{awcQEMF&f{QxzF}0-&lFE# zM$Z?DJ4go1-n_eNg8ZXl6NV>?o%BtPZ#?S>oYc^CQU6$Uh@Q-pc8p1Mws;{YBwB1r z4q{0;B}_D8ED&}qR{s0Y3uP+-vk~gxe!8 zSZkCnGkaeojYub>t2JCs|BvqP!2&3OY=MJn! z&LYoqDHVm%s2vJ}?w_AH3Z78N02TG6tZv24n0tq(u)1LXdWt_t>NfbJ;WRr=+6+|yB^OS0zDF+58C_YAZvpfot~aY8KRT>@+LYe5$Qnq7wkP zBEt$rnMT7TKU9Zltr0>0I`VvK{~Jrfq!Kc42)6#+!O+M|G9fIGutwvDnk9Ozx39k}4t9bQ6yOOXJJY1EKP<>g|IT zag)|k>zQa2#4gvw{#xjWEc4sfkI7SI1J9n9uS%conS8Ly{#5Z>Y1>}I552e9OZZtB zSYs8a>6}HmCtw!4x(37leWA@g3W{su?D4xloUClc$udLK?WiDW>%VEoCIaCZcf2EloX~X%g4;P z@Yfmrb$D{ri<2UCEvS|fnA1a$&U+V9}pVfOgTj=CG_Zc-64Tz=jYtzJR#rgWzQ4VtEcrfV(qJ4l$$nn7Se?{I32Uc z)_>_G>_;Z?N!yx##)V(?m&r@+zvBW z3RA@rQNVn6D^J6}J9;|kPKS*K*k80a%KVszvCxYWvV|hJ>~jj>*L_s6}nE+v7S0;X)jaJpQ-QcBbX z1qT0o6i45-F%2{oQ!5%V+pspXae>x?{C3O51Rn-hlAWd&kBu~~adf4}l>{1#4xr0b z`U8KmG=s)i8x#2S1_?Y4&M1_AVQBe(Y~hMMjfMP`64?345I~0$caM9`R?hDt|4wLS zbr|rZc6Mos2IjrcbwQELd6x{D35GrIm}p$|Nb5gJMo+EaOqilc?3@nUE~Zl{I_`ID$n%5Ui`{qm{} zIkN))`pClWb}FNOuZ}VX`v%Zy)#{19Rb(pbHwi*#VzLL!1#9!j`UjRVRtS0lJ2YNV zf?CQx}I#n%}Vhz zT(C2?mEyLZ8&#=bIA*GEiL z@_ZbopB78uTEG;Ja>>NEkvvBF7mhDPpC6ksCjH@^QR;5qQh%Tc| zt~8vT{}*2Hu1rVMcP7_?un&P$Pr*^0{JqZ;E#3V>_Mb&!)$(^ODz%!feP730eqcVZ zJ9;9#86*H%;Z{Md^y0z!zz5f|7AT@fPuQAiuRgVvujC8i;Gd_Se2v-iBII{=)qoRQ z?ofs9IslW>^Ve#xK14g7PT@-+2&1CGAS0^*z6JlV6sei7^LN0<xOVemW5i=@Bp+PrHMI+DB71A1@az}BUi(k*G$fB8#eg=cbl<2*79rx~i( z?2fogBWi|myiCT7P-qt56MDo_-dkhpe)7qh569_#!#1HMzgzRSBHYNC!j-5mL%=D6 zv~Z#<*(fLEw_Fr(uZCptV5e!NwfJ6wc?g>wt9fUE)Nn2&DY8tc$xuzxeUHdALnx9F znDANPwXt~^^^QE})u&fmtnawG_DXbgC@Y5Db_aG5ve7_Pav0jW_9Lb_cQT5Bc;R#w zGuO{YNQavG(|&>CU&k%96X3>>h8>k~^OES^JxOmzG2USQsS4i^tHc5ar3ZMzKZlVq zI}aNP@8k_Y;w7ic{Lhv}E{VH;8Er7P^aCTZLOMH5da6hy8RLXq?rqRmhd^R2JOF|o zuEnKU-^2rHV!fRw@}lw{ob|H)DlqYp5nSa$zPRwy9^M*9%Aqe_?z0TGHteuMXx%Rq z&u9B$efXDx$j$eE>R;as$u{D@EB)!NsWi!5y3k9>#poNEWp}jO^CIXSb10AJhT}U4 z4p%X4-jbKT>*BSrV=NY)rCz%UMRJqSwPE+Pe!FqS@1CVW7j`!{Ov+wIC&?HQp)!7t zu9|Lm& zvRGPiY|Yp2NlmBJoD?D2Il{@owbUGH6i$Y`=nIqc;jTrID7HdL+v4J@_YWb9(DR)2 zMi{*rp5`qi=CvoprdRNzgS0}s7gRfn*y>m7TB($-{$Y2H)S8_YG4f@q$$)(|3o9&e zL~4+Ju`Q(&I4J8~+=|g_<@1A`*y=vky(e8opr6&K_zDEW_+1yR(2_vEsz&htn!e{m zZooXv<8rPK^85w|FE-F?iNpA5u{1Qx`WX89Ze7o$qX4Q<)(_ReQdBa8t_^EG(W`51 zvpeavJNwXy|LPlZIS%y`!o%Equ@O83hi5hXfQP!GT;j@YQK$r?zmr!WQVYS2LTrA0 zz?oM?%nJZ%8BX_p?Y!AgjFbj%OdW1*UGR@hRK8FMwcSPYgXad#OQLW#BE(-Kh&mq+ z&62$?bcGGv(Kcw)xH7glo|5uwQ17+T`}Zlp6=QvLdHoSni{+(ML|Zr9L4&+-yDi z4D{m~cT{8DSMU^k*W>2r3@TnBJl}wm^R=;%u4l5w^;QR^@rR*0|-g<4fk*%jPIuz_3CeMjTmIoGy{k`lKHbr{g){fg0ibS?Q4l|S# zbtQXb0psrO&Y;+yvfgJDG|l~cdp8BEq(h#QzVlV+5)6B#hmARv>NjwqkDH-sJ|4H6 zJ_BH+k@ z>S{R9h-@9Q<@G>n@cfC9Fcs%)Rg#2HgjX%yl^Ny$0b+S;l?1#`gg^Q(Uji9-J^qZlsu zPGoLO=aN&^ATwN>a{GNJ%esyh40qFGOJz%awSIv)oPM3)P~3$rAmW`#$7>koi$#$R zIgbz6ld;w~(;%ERN3uwcGXAtIPj zef&K&y6bl#Hz)fsGl$4^tHk=tf!+SN+XlajPR_@qbkQ*{uGD$1?4#xQM&Cw@>j01k zlELJl4)ovz{PuvUO&Y!E%j>MgF6EvA8TeSN=lO?uVIt_eg&bJA>Al~!59B|Oh&}m% zpTsxo))!kfUp=0WuGw*Lzhd{FFSq2XC9joB?=J>j4hrhoU$lN2Am5{}sGNQ{;WONc z_EJWdl(dd5RQ9rsv=l>)r0de2JWlO)r2P8%t+0!*ky=8h`N9q>cb`_0kcVMJ70E=R z>cc$(YNgK})A|dpo$1-R8hfKb#FoKsfe?uB>D()3UFAh3bHYrn^I?kA{wk%e{j#sh zaCD3iNy03#bXS=NUC=wC>SgZ!OT)!!#90Gl_)dMC^3}|Qz<|mIDCWrZ7fj>qqx;fv z$^!1SRUmHij~$2GDGcSVl3by3-cNW##mwmf{J~4?j^bZn=rH>~C&6yE#`Z5J6ohPU zZ8?~1^8B|mCOQ_`^Io#_KazXC6plKHga>jack>HzFufiu{Lp!sMpLs<%4jTJxU+7V zPI85ugAlKW<53)wq}6tuHEn;SNGt7Lg4w( zNQhD;_inKYWxbwNN{wtu80WPJS=wt>2i;wDJp2ug`qq7Or8bRGi8U<@O$Loqb=;v# zcwUzSPm5-fCYxG|L}*Az$Y4Ql+NA)$`lmh$t*ESYEojw(7_#%MK`^~GKUR<<9jHQ?2DC@#z^|Dbbe>OTR&t?GMbr= z0y2`G*l5@kbf&zvy$dn!f`fx~QTwIc;VPt6p#25ZL9*uNp!In=f&cDE(*5e`t-Xx*_Xd$jH)}M^ z^u&ET^H|P=`r#Y!XYeJiG7)}bj54xJr=!j9yJEr27;0i%t4|Id%vV_CrkL+;#9#z~ zn4`#i)BW$8&kVN7grOjC*Z*zBYuSxw^)~g99*Ryk&f6uH9*KoV>*@4m&bYGNX}p8s zBaEPp`hc8%B7Fs2f4X?Sei9l37TomXwzeFH-VR!q8}r4BkX=D%UL|=cf zG$a^2Ke=7?C_X>uhC=^%Nj%)y`3Bed9L26IEa0^}7-5hVzEbxEKY9!B(`~(u6M?|y z{;V@p*(mFEjDJtK;T;xTgp;sh!A`L)-EJA{Aa33t30^MMIsAo&kb@38E3Ol^40JLj%d^ z?`kql+?j`y6{F{;pB(R<_oY+Mo5|?)hV2#8p9EixG9TuhRxh2Jz{dt4{99t#D&fwT zs4?qK3xN<)fpKhujlr0~s5m^SSb0+iy^){CKQEqF0pp?^7$?$3!u8tBNIf(j zYZ|`_zPqo_=)qwxqML+71DWEI;Rs7++mlkt{;Z%ZM4!%k>(f+*6~4e)2t1L-Rj=P4 z9qthK>q3mK*Kg?q)dMSB%o*ElgIBq9*;`VO7sA}tb&}1xkZB^4#v1B^7g<{TFG9Ud z(7U(%k3lre2O9dlWrEJ!H3NTG>qmb;&?-G1&|SN%`P9dA55$Dt=!r(4Q4befi&^%n z&Pg6EF3Vg$4j?3<#`kjBWWKc7T?Sl`C<`nWk-@J{?;p%Jc1PIEiA08Os1$>fGukO0 zo_uIuO+cw)>wk)nZ7pxF-!qqxX+vI}i-@)#r0Fu04YSV8Zk&aXa+Y_G2(%}oNlszA@HEVbtF;mMO6oe(bsD#^dz;*tp1KlBlqos=b56+!iW z@AFLY#Rm#>t81{A8WJIHSrRh8D7L)J9G@REk$@_)(ZV$HmIRN=1TdL6IQ?o(qJelT zf;I{(*}A%ZZe|wHbFX*+IX@!OGvbP~F&Ioh)yLbT2i@8D-q;Ck-2pp6pvxQACM|6$ zvcT&8b6_{=Roz{xT6u@*Tx>>B=t=V_bXL^+@&Y7Bev!CZBv5+2e)c26LhCh^T2p0D z9!gR-6Xys4D`N96CeT>PdZ%tSx(Y#k7029kPLmkGD1jx0SbGaP#*6 z?TwfzhDHG=)_jd1nLCQa^F6IEdJ(DyHv?nVOUm4~vpiUxj{Kw7FQu7R<54iA9d)TY z6kJ{4JS9P=&!Vlm@FP26Ie9WgOq3X(HsG&3ki1P`d&Mwld#IZj-#UKH!uxl5dZA8qHdf+ z;7p}hpS@5@?I|D45@a1%>EiC)B16&mI*HM4;}i<&Dhl40&W)i}Nq8GSDy)T}ylr~5 z%lCv2>FrC0JVZNeMn&5{>w!kQlSs%m1lrvXQoWaD4u-MD-9RcHWE0K{EYrfus_=5Vnf7b)&iaD>KoPjpJBIL@cXCzQFGZOSx)283ufR7AF|JJBz6-4PIIEaWj3-KCiPR(8C4 z#eG<1hQ5`2s-qHz!rP06XJxH$vEK?6qs*%@>){6uj{I?^6gvKU?KVNp!(na2d)%Z( zJPDaw!}PrfK6FP^h+!t30E=Cy(!@`42$w=}CJ|lVDU-_+Uax-YJ9vx#Iv;l!$(q|_ zowIf3_U%4)4U%SwlWw8jUqh_BGJu<2lE9jgTYX@Bvs~O7jCH}CQ6s~93UmwnOf>(s z3qdh5Y0WcUnX)Cv&?4r*e6i3`qeb0vWWmRSt_dAdf!;15uE0GRUF3VW{fCS!N=TQR zn#vyTECT22Wx?F)2L7gEmef^SH07d}9XQP^uibfWHJm3pL7E{O6V2Q?aw-1`3-{w~ zXW`UfBX7XLTZT>#wo#zPJUWU3CU;XirMvH=n%!mX=z#7;T{k)+liCl|8`nDV4ZeFQ zge%KL3Aq2B=z|9Oey zwLXNKS0{Ylid1ViQNe(66dfxv?>?;fSd>e{5#>BuYTwxccYaNI!xKgf3#XHZ8C(UU zZM3B{{7=S(#O2@`17`SSwsjO^Ag_YFX=T4UuC!A(d}-#mZF`FKlM$nA4?pt309y-J zWiWJe+4NSF{xb8*BdxuKtu7K+Q|@0i{DX>UH5Wl7=p@A1C*JAqaAU{aC1JXlnp@^3&=`I1 z-fMcFi6!E`m5bf~yR5fTkI&2fw=c^py{Pk+sLZY2>7IGD$E9jrUQcH%m+sEs1C~DI z6~+5fLvT3dRZeTABv0m-aic^bqc3H7)f_Nui$voezymF1?aL0b-4qfLm7FeyD$YGY zFVc*x%d%SJylV${xk(i!<5DNHCSL@#t2Pv@=l&{iRGRE)ay=NQPU)te+7p$Tec%Hw z%Z@$p!Bc);{&En4|1v8Y;k#7?X=+rtZzZ(wSdc}sI~V@To>w%z;aQ>#Yfwi(ZyLq& zdsv&Q?GDH)@idu3mq*N<-ASFkzh^S?c79gj_b^i@rUDBt@ABKqt;znL_{4p0jc}=@ z!eT^u)`jXNzyiyNr`0R&=C&v_dJm6em?iOV9NsAK%L@D>mlCwXe-t53ZM4;jRhCV$ z+bVOo>_U~wil9?#q!e zz^K{ui9gHxgqKY`x%oAEbI8I0%uMMxum37Ryqt9fBhYl`mu}%*omkdyk zPh(4g0cUhGb5$r@vxm?74NB{cJYqx1Jo3slISpMiQQVoiShRjA|rw`yd0e zFVV`>q8e<>FTzhk`N8e?Tq!n!e9-$xory7iJ63B(l}qIFVIJLa zQ6-m{k4^G^A<}Kb4}Xz2eUqUQ&;6xv9J4_sVUHzYh{aI|NFQp^Ipn|TU{h+EzHI-; z65x?Of_1)u zpK)*V{`yt#$8v5#hBz~-=JWQOOZ)-QSSy$MTIbubrtXUr7#*qLbX1BLQBAYQ7`?vV zb>9JFEI2U^sl!&Zdg$XxF=+1gaB8!+(gsUeMt4wzyRcJ{JMJK5{(d{c#I$|jUJK018#GxW_oDPwDBcYnf$r)NKxOJ z__d&)M4t6|jOOqk#u2o~u}HMF<4SqrbJD#J67jto52lsqfYEQ{?H;S}?R4WE1QAJH zdw2b@4bcV86s~8o@CY+@xD@CTc6R})#v>at-7)|ph=DWcQ_$E zm1KesdKk%dfASr{$7CV*BM?nwsDbvlPaABL~;QExbRyxggm{$}= zegWx^zjeDUv0M9zsjc@KiD4uP_h*?cUZx3efOduqZsb3iD=t}K3Ok7%EZmDV*ZdKh zdabtC!JS=HKEa1-&{wKrJ}HvQTnn3J_LK+gC_qB}gTE`rMGH0OgtckBHLaguh^?W5 z-gt+Bd|5^L59HWh5o**J%UgZkOPC+A8R;Iy5=gT+Kk}!Xi=4W9{?LLI%;+9a*A@iR zrLOzZyf(IqcZ|Pj@=o4W88qc*hJPL-?Mjb+p0^426nq~|9|_oc`ud*r-OIBYB4FI2 zG|oRXm&{GH;Sdgts96CjD@S4+IhtdK#HA9vG2CTfJ$rwp&{&^b(r6*>ISB*7a zGzo-?YbHc_^ZsM2UvmqF1$F%sx0n~FWPD%3tauVa?ioU!r%;?z+DHs)=~Q>tG&no*%PDJ7$tj5*Ip&aq5_4GT$(LEya) z&n4SG_8IR2vR8FIXGfZOmCoYK<$K&@;kmK4GqK061(&m#TYSk(J?$VZ$dSV|8JUD=&1|aQx@c=-3c?>49q*+DQ zDzQe>2h>yH4+Hb+vWzz)c6CY4xE{6;LgGX{Xd4M&IoLMXIxIb zht-eyEX{6En1h_DUNS`aZ;m8AAWqTj(*oLD$L}#F5t^Ew9`^Jw35xj2;31rgGrOV& zrd?jq1yn#xX0uNuMVq)6PLRjA4dNE3`V}i00qh3zMHqOb0oD?3k2oWd{$cr&0rcP; zb}j8S0xrkro{i!_Vs2Ri_mUTtIQzVpmdKF+GoIxBVQ{yx98nk+i4 zx`YU{yRQ+VBe9fMOj+~-vvaDZ@8XQ<{@bEXlcbipTs&t9Zc+n8S96|76QWscI8;1uaFCyfX#Fz)ai{PEe zO0qjg(f(*oHn3kPg}GSA*-um#QmYdi=C4FmPBi|UNBwAc`pHHb9d&8dZG5}MH%@gv zbMDJqmS@DNRwOG|SNpNirn=jC`FdN+!o~v65#ShV#^n%B=;3t2{m$zNzmvt^C@ESS zDVr((vT=+|zk^9rIcIJ1AFRt2ym<2DWHD_$J*k7drVzc)ns6dJ`t7z0Ay>lwwx>~` zK)RggOkQXvDPP352gX&Tez-d#qIEjHpTb3-ZgzTuwlc4$I|d~uE1=Ah!W5br8!EZh zERoZa)Z+6?~TPju{OQm6Dq2tRMn)`eAV1A2W{NiZn{@E1!L(y|OBdebDKtqni4$wUid4R0qP#&NaGHT1<^)^Bj$3`WG@hd7`lgFkrCe zkLT4Y-#BKUm(BQtz?`}xCuqQc+ZyNVsxlvp?t*w(^a$WG#qQ!K*tH(^FV`=EB9k^S-((>o5!JUCNs&{m0Xte za%>=4&$4BP*8-wP-@qrG<9%)(_i{N2N2bem*#YHo7|E|@z56-WIMFxDHxXKzb;byO zBd8du-MB2Foa$4PN`t`36i0>4r?kHgr^71F#O=bCUpSjoL;@Ha1O==4dK*3S^2dX6 zkSi_Nz+M{@^r`u@JS^sy9qc?LJXr_Uz3O`mj^wSB@Uw`Vz#&dI^BJm>QyFOdX6a|d zsM-6XhnpN!fszuJ`mfl5geT^0Klox2AE|smD1T(ker28gfVk5bF^WVMnjs%c>4C+2CTnk51@)5AqIcdVbazIDxvr z{-e&`>tkzyStXsAvfNq6aHEV5rTJ!(LRG*P{&Zd0jHPu&Q-dyJg07s8=HbU2!S%7| z_j`d9YKeXn3G6+IzuEMHYngCk(KC$DLqZtGsfos^t(6OJ{-by!Hy}grAq$E^d=ziK z&lG{u2JYKGe2a6Y| z_fzNRPi0jL&|2^(yOaX`m8!l*Ptq-uPN_>xJW;JAAS(WGS#{_9McZ6jR;5$#OZoFV zWd5~Y?QS~B8EAqLJl^$2g(H5C_iro|{$$V=u)wr#NS+O-aTv7W8ys%y95Hgbaw)dg zg=`sR>~2f%@*}(vpHw`(v#EdCKPmBeAgQ&~;Sa9-P*)oZ5^cJI7z=P6kv@3Ml08Tmv7Mfx%7 z#hiikZB^#NHIL`4dQ>mryqwDmo1ryYl1RuS33TW@JeFSMe!zQ24g_P7C@o}==hEo? zQWtr-1W+*b;p^eT5p?zq6|T5bF0#pKm5pB_9%K|%Bh_#2_8WF^UI$A$!32wazRV?b z_b11F*4Slb#SdQxvj@S2Z0bxx?dR3W?INL_D{u?{#+Q`6CBZlvPr1w^_J^*C(xAJw zGPrhcc|Ty?j{WJ)u)xLX#flh=NY<&9#+39WC>E=8O!$8h-GB6Nz3L~$QE*+>5LNCZ zR#?-Tq7J>IyN7GtY&9jd+aNIXs;DZDms~8Ge(e~7Cj7a?OanfKgg5D6^0&C%GMSa) zY^=X_@gs+bsFaaiT{O2X>Se5&ueRBg5G_!X?lXojFWyeKvwZ)dpz{HR3`teeVyP|R zxS=BSU0nwgx5Q`RzDAc>+rv*&bA#ZiI^z)RW(5-k-V}D}XNY*LB2nJ{o|pMk2KP6Y z6R!GqH|XB-oKy#`*5jrenb-dUz@#_~almW&&0-~y-If=tIUMjbo|kM`1>NNXNnQ6L z+c6A-64uIzI&AoAx${x9Dte-zfxSN>C>7b*n+piRg(GE#z9Kf?^2qX)NN3H_PiBK= zcj&qZ(#l>4=3sy3AeX+`t~HH8bm=*!%a~JZ{V#o5Sg)-5ZB)fgC^DGm$0rN)VMpt^ z4fDYqdOjfhcnq3Je<95>J~flvC%wgmBlp!@K(gVaJL|$SBwK7lY?aKh!c)fX{T3BC z&Kd%3V;*)>F!O*`B3-N!knd;tD6J69yC2MB*sT$5tFG>M0;%k9#DVwR-gUCB}mj+ecHA$LaYf1uO!J5TE&Z4;>vB zDO1=Sba|>$jbY(YdjLMwYvFB6!JMMKrz$A+cHzVH;x`fX@WHDAM}VkfVn$8o_w3mP z>hiU8fus`0UmBFh2M!URZ$<#v@S2BjHk1GDGM5k;S4i|lBraWGjF<|( z^PAr>X9dUkvec(W@P}3MfDlEaf?6c`zL9+v6)m;W?}xMHHU*|WgSmX=E?v>B@@2(Z zD=H+DY*vkxZ})ry%gghM zVy3S205-bPm3P^2b}o2;69#6Sn(nDW-5&;s!>)GrUa!U=kJg3VG#V%V`HFg#LOu;y zrSy@y#@09vV$Z^iywB9dR=JxD-!ekU1%Dc76qEqnF?BX33R14%?U!xr{%8MCMGAAI z=Ty2Ab`G_1HGsQDL@yT?wg1eSQikA5rT#Hu5MKjzX`z2VaceA$IkZpP&*%S^0{!N(?%t< z2@vYk3?#FwHHIEZwGI%GoQ^nw%%Y5d;A{^+@>2{*EFN!=7d+ShxVf(`bW(cDb7Ci; z&czgD{&O#ugKCX7`-*%R%N!{w7meemO zwy{lcDR`?JC5mXBJ?gyqaTE-+6Mpk+4bky(TC%INK!}IqFG6!l{urrfMlv$%5O124 zy{VVDl(ebZKOD(yh!EWF`Qv_`#^9JdY3 z;HXRl4Fyb_kF657tz64?tG}4rov9Ej&wig0=R#F+mrw$R+SMMygSt1gWl!unG85mo zmzIC~esBRwJ@0zjk2nZ`4X^`kWwc+NqoH(o0}wQG<@|+1k>APp`BGK`0kWQ!sP1H3 z{Z0Qi&dDS5oRf#O^mylbhNvoB-ocxh`pt(0xNIWCN>!?ItO8hLbN}CDp^x$EB6{B_ zaK351<%AVs$X3FhEWSfY?Ij>qLyRP|ndhqd-{}UX;%@W9$E;mQ$rkN|##(yNZ=f9+>p)HJg9sf%7&esgLG zt|^tNT3p(!aU5RxT}^~I!xW&ERA z9qkw0m0b#)Njee|s(%?~bdcTq!a2&x2)zaCwhHhBv9ZZ^I6%y;K%<&@DS#m>5={J> zt#(C{&mV{i&apf~*+j4(EB%8iF;|y+ zj-j^-$Lr3c5w(7=iUQpw_t2S$1^nOv4WSpV^_$d+@Jk#Zn5BGoD1R%ZGI=5MFcsvL;`Ryx*?mJd>cCgAJ$GyfhPft>2= z*DlyGR<#3Cl<`#kmQUoci|dHQ4fdu;hy&fJpQWqy4kw!b=@&>d#_IBVHgVkoTg+_i zO`~tw$|H};BZEBd=UMcO&=qe}`6pA1pxLD>J`Ua6-PwQ4&`m;dh~T`^URGC+cTy!t z%S!1c1i_j-@Tlf&s`2ZNRD6V}16Q%>ZTi5r8RSmCNp4JeCQE@P)R<*re(9hKoNU1F4M;txxCST3>DX%i0r|dq{Pi!kHCWzq?kyDL zaN|4p^Qjo%?D4FNS=~qXF@SC<)+NFJ_4l7)e{8qUCji6Gsy7EWNn3y7q`UVi+5D-f z_C>cOu~D4H&SAAHSIid(`k0}m<3g90fbbOst6|p@$MVS`ehj3h=T>neo!Kqg?#5gD`bC# zZB;J$A+%)lPdk#T8KzN=e3dvRa>wyV&o;>kds6B$uNLCIFpmL9ZtRD)&DN*^GMtFC z0e|QV(B#yBy0>TE;=3UMK?QU}S!cJ1X;x@(`orBHgRm@TERd8AU&=h6wV8HplHwVM zwc%zQ94HUPtz?D!i>9!q)Z?eY2@!iTp2|!<7AA*TQGCEV9}+m>jki)>(fQOje+n$g z^}$M5#-Bt0=*J2dx?Ye~S=L(QbvRh@KyGzkGQ*?Oi+A*=NLv0;qOP%}V8C~qkGDGW z%5{}!YeHTv3CXS)8n}Uj4E0z`@XCJnR4wkYTRVD`t&i2pDLfg|+gKA?faFq}pxCmK zro|%p729ms8BJA{;FA;euaG+@_YLXe4QG@x!7KHzI(({wF!BLd8E@fyCmas8SP7Xs zj2K-w$sQ4vVT>7ujd0~`ty?(I{f^*W=5VSROP#D%`Z@C%rRUXmyw}wgUdkDzb(m;n zk>65Z9sAaPBQVFgs{yVQsaH)bVvQ;(z_)FRRlgGr*`bqkSXY|ZLy6ikY!f1zWno{d zVM#Hx>T`5QhXIrvQY_|wKUcXaYnA7)KA+ttIg=%LKYqy|ef?m%ak$Ed0?SFZxQH65 zraR4V3Og$~*Hy!iP8#$YIE|7VzmQNzH7IGV5LpO$jzP65OIU^qSizmz++km;xsG9G z{VTM91lNHopCKu)j|+e_{Bu^0?nAjWdr^GwfD$4=5qCC(L%Wxttkk)27QZ|azx>w` zM-b<{nwRLEOi}Ub`OGKy%>@ev>pGMT(Up(QLk?u0qGc7AV*##foQ7B-YMF?*20#i< zf)?ztamEbN<1ss+x}%buI2De_uiB>az#xoLC!j9y@xtlO9OenMf@438CIA9pk5m8Q z_v8Ctc*}ED8u{uX#E^cHfUzw~@_bLUOSK6HDHg89n`8;E3k`lBlTu%<(oVnhE%MZn z6XQ{A7J16kdu~oM-voXB0+)I$WsR4Av54=88(e4{mLTR&sK^dk3c>RMBWSNfWyn`F zC{WRO#zHW_C*^v2b;cJxeLFJQ6$N3$I)sD7FqMHJ<9iR0RurRjpOrtHwQ0tSRI$Ct zNis$|HIAVET?Sll6@Hg9;*YhVn(0Y6F&Pyye8HW45z}v=RoK;YX+ViMtw|~|)9+sK!LOd^>fr4!-MaJG25YvqkfY}zv!Tr63@(2L7H8o!5BP4KGg9sqppsSRh2~-Ak z0JODyg)hM623q$_RRh#pi?0>Go;&5qbe5}ox%?}_)Y6SAG)s;kAXA$KL^HY|0#x#`|FSrv=}aQqBdK84L5P`CdO9VE=DQp# zNUuogLcMa6!^fW1#oUSa(+>FOgxU8H{MGZR5rn&U#BT{2tBP!|kHtF*AILc(Q}0X- z$8J$GE=)Fu@K1k=4V%Ay$nWoD`5V*)Ve7nmjMcL%&4sN($PST2SoJyJ^?ek>ZLFwG z(kH6_^2OM}=X!4#PE&>hR+~&yLk@$E7bh&{snz2!S4Oq4d-uV-5%Tjt*z>c#L3PZ1 zoRhJj9jeVFjp)Z=GyZakD<$Y_eEvCl!*6U%W(~w6&LJvTAXHt79;{O8B+SoVzz-8| z@X16b3Y}i<9?F{zsD=&(aD=M#Np~MjNh_uv=8l6=dorm>|FQa@q$|XGGopWy5xGo6 zRLjF_IF+R?AvF?vQ=lqvdCihZw@)wjt3Z_)TQt}a$2@4B9Y}=LWJre*^n=09BK^$8 zSG2bexjWfR#gB8xaN2Z-ROeeYSoV|=`?`qiOnTC4gC5?q`>Lxs+R6)9tCbN2)YucV z7-iI2sAAI0#^>!h{_K*bq0&+K(SXwV5|<5a!8J7N%oIFn;rMH|UAvP&M2Pcbxn!d; z>buPx)tGh~+8B$uc2n5$JoWgQkj#~ohRKLQRJe<6^=={BiDgNJ*7L*$5Mn!O%qv6C zr=}u&JY`QZ>6yLjkUEY0H{WY8i)({q{wL%5J-<(fDoThe3oHD!ax%bu7*|Dk8k+JJ z|M@D99X{F=1CMH4qs<30?kCvbB2y?DNZ@cALu9D*8#2IfLwv9 z6;EtA8qdm~gyUvqx{#mLsxJ;TiGL>xAC3HjN4O?Y=yvCPMTTft0zVyV+#18`*;LWp z)G;;|mH^QZ7>}JpT|D(+exDQH!(Er*1wSdLoLxU}gR}7XhMAK1aT;A(HnxFUo4>`e z^wZ3)ofWI6^68o`;jE@ch1lb~27N`;eyDy*BQX!SfYHsK_V99wTnDYc@(sj1?F zv=K1na@G%`qN2y&X?p5z@w;t18vGm-pL8}fHhrR^9VTMD`KGr$H?X)P$pcL?=o#BJ z+hG090NMeueHC_*dRdu89Zo+cVu@G2FXDMaDYIDM^f$+fVKjPtzZea$O}o1sX%GQ! zfJiw(wx@0Sf+rnA@=&8lq(z$PzqZtw zPmI`0_!hZG$N5-Kfj=x_uw|uMuE_q*$AVEK7iAC0{#{(XqROKNfxmr@h7C|}TC(-N z&9a(D156|bTyVC)u?fDrssw0&%1ZWe1|8rbag|59FQj>H%yfgDMqm?bRC(J~AbKBk z92GS5=K~)Vo*I5NO5Xz0oI=L|(xhPy@x<`Bkux{V`$y{?R5S?Vv2x!7aEOs@kia28461b?TL2IqUrvhVVBj`m*easw_~)};L^Nl!9` z-(k8sxkln(18UN-8c0T3y?3WrJ8zD)Ed$owJZixI9eRB_n}a3y%~-7``ew!QlUUJc zRxI&!)%2c44+PQrd(ML+9*nM|lj9MD2c4PXoXg3kMkUmhN@Ix+{F#r1S)V~$l7lrT z*~onc4q!(I4)$jt=h!ixgU zSHMVbF^YmbiW|z&(Q9uI&dM8{iv@Vj%0RI&YqB^h6^!4qItWG`;5AttfZ2akK*K?O z%qf@UzrdO(IjC!-Jdv^vad^`O@%e1B*`{pLju&)cF!?R2q&0g0psIoiJ`Qha8Ueyu zi%82I(1fhG;>cDJuAJ{`0x%&r?lpq15~BN#48C^~Syl2^<1Dt$oLq4yB1N+^ZEdAV z+~Kjw;gD8sAF^&yttu$T0@4dxy3nZ9=I}9Rd9jxB`7B*pFq2Z%Kp>Md2cMU5!6xq{ z=Ae3d34yeYIc3ms_KW*4i?eyAKiq){O*o<=FeBNA~ge<uyxEzV z#QwzZALi#0`C?2qWvUBC*f5HpDpe6%bj+&?tv+GwbhvV|-geUOxv#mhCR8`$Fp-pn zl2OAI#sxWrX}=R!(}UeXj~r%PgO7`@x?>J|`f!1ZHfKoOf?^(I6u;bs*E0Vn(4h=) zF;e=Li2GG9ugZQbxG){NbXJsy)>;Ecko%U$GRO%xntf@K!MCy-!Wss=(BkW-0>_~b zP{CHNt#T!N+L2AS{C?;7T8EmK7_H(u?zQb#NB)|^!w5QkjZ1G20391;ULKBLUNLX+>#)3Rz68yjBbd`WX>x>_HxI7$F^Yts_Cd=nGs`872(KP* zs9E!zL87ZL=fN4S=5tMyX{kCVW_d|!ozKRfZC-SvgGYQ`@6^BF+YS2+uJLys|6ySW zMGn=3OdH;*b!JW;aO86|P{TmbSdr(jAi<$Wv%D-k$k=x1vCr~QbK@Vi!Ix-8X*8wl zf_##kX8EZdCc1hsA)5Y&yPOFugQ$1wrlLVjrl=2XtAvxEwxZ9id*W|J@Ili+B0u4Y zWw#TIu8sQubVL%#a)EPd9wW!g{Mf&LOb3uIBimT&JYUNUcY_4_CpAdZ+RnRb-f?j- zorwQGiq0`C(msshlWXH<8=Ko~+na4;+iYxZ(`MVYU0ZE-6E@qn-siop`8MC?ndgsl ze&^g9fiuwJP{$j`ynl6A;x#4%#N8xyMa<_**_-n!N1WfNKkiM^>3V*No>x9N>PN-` z7tYlaU;0^KC>pSB%)=VHCQVLMsp7Qb>E4YIO_tRMXENe3ihJ8@;uRMcLY?D(Xo1LhbQ?!Os}<`c9^Hz$AsOd!+EsUGEcY$*2hn5zjehZPA~2$Or~2YWdD$ zD+ZmagF%MjDwmgA zXNBsTobP{Ayt2sD+`@#-qi{vh7_1Zkp*8fkq^ed@BJgx|$e&wr4gb)TB3lK2N~27P zG&z~_^({X;5Iaz7Q}bUjrlcA67EKYe!uRTx%H@^4E62`1i-xwXn7)-$ObNBeK=d=$EUnq7c8)*^>I2h@P{BB;B}0UaC5-LITxl z?8R=L4*iZv0YS@?#Gl~+P0OlgI0WsJuO*}>AcI& z@u1gnSfaoW%xv(#r}|gP^Ab~sX6K+v8?MPKD!f$l?mADmMan{=BqWsT0;DDc!3pd*D;-~fC1^P z;uf$|{xRP_X~UqVag*vEe$EJ-s70R+9z4Q`IEfkst;N+-lOUT~mz{%U{QV zX00^Uc}wMQ{#b8}k_(X!`el=45hk3Volx7Wr)|f?0Wk@&Oi^3j)vUkdKlaq1NT><1 zt26)derdn3;HCfd+3&9Pv3=XOM6FoVxP$478H_wPtc!jAM4S?R;f`&faGt7!FwRa9 z&H_Xc-e*SKN8pIC5+LcUMWeB#fiZn~!cdVtEn$b_HHT8N!zqOK!=rL_d)_EpZL*J! zx9khWCLAerzL9v?aYdPpLwqxdOt<$d2EBqvPE|FvK&6mhxxuP zbP<#y=;!Y>qfM)n@LqU$$PXv6B&K$B?Xhm!cVyrx>b@R9S>n=~b)?7a>Xy_480706 z(bw-*SM5*?m=3|MI@~U9=Nk6JV>$aeNh@%AJwi=XTM^snXG@+@1eR2_JxFaih4wjdXc4?5PpODIS8BD6n%rv4 z$JGK^&sRXl_s)2=EB!X3_`%8^$V7!<{hXlk^jZ0q?`S-px|LmZWB1VQYD#a^3VSZQ zMK9u8tAkvGQpOJ?%!>@gugHcH$uOg7ar9;a^4O7MJQy}t+PXZ{44Om*TG`}9PAt+0 zOc(;^k$4b;8dsrcJHxJs8%raq5!9b-og%nfzYO-fZ5@UW0(S8WtX(#q8xNO7!Z;6ivg+(?&Xt--n<45Wa9&ecn2}fa-Z7U+ zb0-RWOe21NAQ>iwJ>_PYm0|EZYg>y0NaUo;Xb7AqB%7e?iG^W&_n7HU~ z21|M;u%~|()W6Kr<%54_e?LG~{FD#vLm-R^L7CsAEuVlVA`I~Px z2xSZ08Dfk+8v2J6zZ)VoR|G@BCD4hH+6P)!;Qs(;&2ec~HfU5mu`hygPb;}vy9cKL zD{jJd$Q+Cguv{v2`rJ8sN4$pM~Q1XNF2SVPvu(Z^G$&5bUugrf7X^(pgn;8e`OPs znp8acPRbq~YHw@ZWB%~yY{5E^2A7@QL};X-A70btj^n*rG0mJ5CI>b$n$UY--w79N zTZ2GvGH(!XjrnFJ5G&SXjbP6_)BoHgNZg=|q2A?FvM|qAy}Q@*pijKKA+YC}XIuGn zl2h{bu;DaQGMRO}_xI#I>a-5A;X(^5_ylawRrY}sc~(Bclcp*f7=dI==7`QiIM$aX zLDnh#4NpMJ%DJUn*3!AEFPWDl!v=}B+y(fg3v3ahqJp+PQ?e7so(dH#`?t*g?f zczcD;>GU5?JW|@fI50wsZ-oKB_&`6;y0YuVs~pVqQ~HEIuG(yOm&faYsBdx~#|6od zQu-#Fao)k8!EW_MVQ2x`BpC@5(0vdy^RXR4s|^AH%80h}!`+THzKU$SUw!Q3^0`VF zL?ZLQ8rw!qxK>YB4u_4o@vIZuQe;Mv2iP7|&ZYtM=Ac`xK52w5ifKNnmwod|tHtdC zp`-1&se6{pW(#P!+kX5~+RD22Q6tTQSb}t40F$RE_Iv&-c=l_pm z)ab!6L-B!L?bIG;jJ6)9!c&+;pd;CBp>?Gbhi;TJa%`yYi@W_&J&O0@PcSICX6-fm z?H_}^)4lMeQ?*6-0a1IUZb7En;g*Tt;y4hsA(>{ARFN=7%zlcD7!B<``5`KpU0Fkl zg{2x&?Bg^_xN2w~RaR&SO!Jky0K}^OOoedk%ucxp_sRdrNJ=A5#t-g{+9P~t?i`o! z1O08!1^s>oczRKoK3|1WyUO1rL%h+ttI?;H;U+8pf&e0GH_Fi%kTP{vFpw(7?PB%pqjFrOkX=kM_7ppB- zd?R9j^Jd`N!j#@4a|k;7a@A&i1}CBr9z)S5l7tExmYNS#2Y+G&yOdsA|A7o_4xcQi z%R=UWJ*jZj7t?4Ss#&+ zj|(su6*a+1xUXB*F^kVuGH?Nj@u%hn!E&0cwI7sFa7r4B>kcS{V-}m6GK6#ad+k++ z?|Zhvzdp$lzN#AoIxmaIMQr@3|8f{rVgMb>KK(kw@d>i2yveS0TCjPPxfIc69)^Z@1|Z}_L&itL zm7*-QpV{wtA;jNImXBG??PMHAx2Atjyk+rZpK*pYm<# zu1T`HvK_{b@$c>IHn(t!C6BUz2r}FQ^Af~nl=^99IJ0^X8*y*phWD=@bVlSzpr*ZwZYBM4y#^ld+_RQ2>!s%d@AF)phf0nSn#RLF1 zEqoUz+NWa^KBFd1s4HX} zbH#Rx;z88j;~c80I_T{{)gA=*Vh*zHJlzbG*(^H7I4sIu;Lz+LR|gsEan{zT|1YPsH!!UcJ*) zi4DT^=SD>GN=3n0^>BZ!9j?yP%*T-$jLUjmNgDXfYEx=B^l6?=fZyLZs!!BfxUH_U zw9Krd{LUd?941kC0&dVXnhY8pD+Pi|@Jqn&y!IveZjQ!?`)0Bno1cVNWg0EUViab= ze`%(bPv{i@Fy+`w*)FyMOLrf;ISlzH+9;~Ni%~|5I6QUx3wL}}6{~PqJzyk;6;N>M zBZRRbWHc7-|J@!2azoXWdS%cb8oB)?!<4^#eQfg^=&>QT0{XhRs`u-lx|R|~1q#nt zZhT%F;fPuX`zlRpDcKIhQU19D=clP}e|9}K5lOcdgZAM? zy|@^vmrI;1x^a#f-l;5C6^ch6u4Ch=lqdc$SGI}GIVyfR5{tBX#c?DGi`&sZ6b#z8 zZDEk3>D4>>kbqqHCW_3#rt`KpJgc=#*!|mSTyA(!-U8c4pqbwDydSsce!`UB#U@y& z+fsnw_~5Cl^pn`Q?aRS8ScE?b8UvP&g5`}zu<)|MDyFRDHV)1;`GxLd*w@pYMO zVl=tvzgCzB3uQC%4|BaT(}%}ZGdX`bvMQAB9E&zRE+AI<-32D(rAm`hcS$xuX`p~s z85Nn!lWNcCqykRLcj(~4SZ^)mHt&EH@so-ub;tkjX;@n*m6JIt{_TYY8o?-On$VnJj`Ac@<>pp6nKakrwO z(j}()2Xv;F?ZeM;4g#o@LO4n0XFcn=EySt2tMRt4@5k%No!`AFx@BR76ohr(63>N+ ziB)TfaOL&RD_SYxA^3FjPwgVEJKU@Gl^xPwVoKNzM@Ph>xxS|V1oDG{yk})I2lqSek{eJ$+GeP zA!6QKLYSsLgc5*lDxfAUMYR_9p&KLBDV@5}(sPQTG?%>&S)J(w6j|2v1SE4J04Oft zp=#u^kVW@QG3!eO90aYJR5z_C*#I4AtRB>xqCd3a~ z6?Y6YX`>e?ptJtl~ zL%I)2{48dZWC?38TL=VvA%+KK=k$ zxlMYbw}d3K>t5(kb!b=g1dBQJrhqPM&Ga1_sYva;zwJ6k6rqA4a-++c zHItKvFTTK*eXJ~xA*(=pa`-07j6ucIQt_a-Z~!V{_V{0frMk`9u2*M-ZRRNpC<%o| znZsFx=rx2PsFn=S^8UQyM;q@kl%m>*`^ugU*F;`%ig@K2D1m!x6zpzr$Q?w)iuRt^ zf98oO7;V2~H&BTNMbYAowgGQFKo}k8{(llKo-TT`r;H?bS6T4PsIFg?mns@N_+))k zT!7>$CF&OM_`Usio&M0Z6F;v|x-*c<0eFO2ml3{W4voB*V0HK?>^W2%@=C7N_XfPD zGvv>__!M>q>H{muxBzlsRfagHhci@S+kpSn@EQ4Osl7e9B<6PN-=QqG2gLcBdf!h- zS(2heC}G)I-vM?z-IiQiJ@_{9U*nhKwrL5usNdH>4y|sY?z;-!3nb^=P;{5dkl^|w z?=9T_IqzciovIrR^loW*e|G)_2vVxH)^vgiAhtb+Gm7E{n7|*--cdm8?1k?pGio&z zOPoZC72E$~j%jkx`E{a#D;Wp=_NZKK8pH7FOW01Y@~e~KpgGO%+|sJS;QBqC-%hi7 z;WbK0C>tTk-%C;Vc#1dc$rv-d5v?6^aJLTQk2uimO5){zv zV9|yCS<#C&KP;l?Z;Gx;3U{Mfr^crxaAp2u_Ee_MZMZcfBstb8gP%74Qm6xdzy-ln*`7;=e%AM#e=+ z9E96AyLxfUfvsY0t_UMC6;@pSYBR+orn-?$*z;F;s|*M7P%o9C1Vxw{$raOZDNeHH z{;0r0Li6psudY>~pI^=+ga}0FNzTIx_V`p&N26b0fCe`kLTX=O)p{lijmDCgei@3N zl^i}RQhIOuh`iVO<4mgYb0N(cX%SskZPBlM-SaLiZ8Pktkcu#%|jMrk3Eku4(OG1Jr5 zE(R^(T)Ww?r&-7SgRHOY0H$}*j<7hdv{r0;Ib^F2+Zz<7ZXu44*(q`1EX5)U0r-PB zepe}RMhc1Jn}wMEv~{y|e8Bb8^Hlzcwapgax6{@Z9)SI;x|o3Q!PTCrcJ>(?4Qs*Z z?-u>{mk_}rC(e(jW_xxCIcOMso6cr`;yqf)j|NS{TYsi}h%5nn^;7GLZ6fdVIP`6v z$jZIhtiNo(S@C3bZ=?2(WOmzr|NRj2mwliXu_pE0!i z8rRjK6XshVkUZ~DN)Qr?%y(R>!46KLIQ&shQlD&7w^zr)4sk+YT>9GI>qwQe3LazD z+ZcLg4OA=V3&3?pIsKmXnDIC8CvSY+Uo8|KlXfy_@S7H6} z4^Cxij@%ZI_;ul0Pu4x1_!Oc%;`s|)YAd>SEZfufMSROQRFXTF{GqNkHr*;oZ6mc z8_)N%LH1bpj9rTn_#b*BsKD6(?jdX2v}Qxx-fGsJ>hNI&KpSK1>0gZ6v~tF9$#OY& z3pkt-RS=Nv~?;~S5Dk5<@ao2^UA{#|DJ-e+v+f`(){uVeYe{`zql8aO%b`2SM= zB2Jn+X{ucw{MRv)wq>wx&{bd0{rHg%+NzWzh{)1SUA5PhXVqrc`N=s1fWab zfzj+O%SzsA4}>6kY+7~0sr5FAF8*X55urvdy~gx+-HVl8nhQQra)FWBg!o4#14^Kb z?{D^9L-)Fj1>XDf)bG97fykMU=~r1y><|xF*r9nV&AkPF1I(G+XTEIwFMMu#(z{Qy zh`z5gV~Z2s(X_#`6Asnouio*0%Ocq08b&awr#u!dzSy&-t7kv-C5}i-3Z!rnq4Q*9 zp2ai2I#cc3`AB#drgm$Nrgme>KL}ugUv}aiwV8_NnIe792B%D4Z}2opun*f=kKaN= z(Edg8c+tnnWrx3x#1(>G|X2TjkK1i$byL_O|DnYse zMVL4;&=7nHfcm62TB{(Rt0zIfBYLSJFilfaQ|E>6#lXdb=_+USiAg$j^-28Hfg>Rt z*tO0+qa?>K-E=r6nh!b{&2GIj&2YUiMt%IpJmQdF@APyq={C3w1t0h721p&*tv6%% z>a_hn0BJ=?Bbee9JsL)|M-5*~%&D#UUv5Vq3lI>ro}_bjKbRe;eeIpWe9Q3)xFh-4 ztgKNI@D99dxYyQ+{l+uQ6fmE`~~95}JUceED~6^j;BxKog=dC@UW9Ho)cuF47$ z9C>Xel(b|Qt!9j2QAhEdM3N2I5t$RpI!TmBCF-GlMl0mmO~9^{OkYPBarDKZYwzz> zqvxvQ@XKMpc!bE+ViLN$3VxStR?5yYO2Q1gf`op^7d*1e`l=|Y{8Vb@xWkYg>jdhH ztMCpDD}urZ+OxAnqYjNj-O4;`o1aF9_~{z*Z8(oE$YMB;NLc|&1-$sVocOtQ)Y4+E zUu8*hdGoV@<%3*=Bria5+F@KvSr0*6Oz`{KOh20xoJDhNJUYr4MeX47Ui~H=3!K0Z-am8sUi0<<9%phbH7iQ+ezKIoj>X>ug2K z)%49;p>slFg#O4Sn51McsD`?;Kz>(NHnitT{Atl&v~*D;h2q(vgYNl4_7cx#=E%`8 z_|s%2#+x}#y`@yWkE_4X$4>R9{Hzo-GEyrmXyoXXPlaFfXg|Zt4@-cdwZ{ghq1*Z& zt@&h^6mxAH@=|9@h;d+k)+Yy1Pyt^uaiezw13-Z&G57Z`p`v8p+mEP&(YRyS&evKP z5LcTW2`y!RPF%4~(Cst77Z~E3Oi7L#;Zj@kL9znm!b_s4~v~sva=Nd|Z zq4NS*hoJn3a;o!inh{7h!H)Vey(O`HkgtM7tBwe8NOn^8^!F6^0UZx+mk}4l)Vi`q zem{_46PyXgM0=|Uw(1hfUxp|tHxtXU3>g61uWx1P6fdwHw#7d9VXb_$16$M=)2(q} z&T{meyol1TIYXF1bgW5NL;3i5d}?xX-_cUr`^@I{svS9rr>q4`;B%bB@p?B$3$#Ee z3^Bd6;LB(DoX$Aw^%SQ|J6ELxkpo$>pB^h1Fou$Vo%rY)Z70G5ZnpRG_O^C#$hm2H z^6`@-?Q6lkap}DPwtP(Vg~@^nL(fNk4Ni4qt8#5jEWt z7tTcVe^cl5y?6giC5v3y2OW_^%+RBSgrCCvyutQ~r(!y06g4jiLqun>5nO(|D}QvD zdnPN`Q4{u{2UgJuwh2+j1R-J0zx}Fe677zxVg5Kuo1rxc4K@C8Qq`iOtNY|ISkEB% zeifS_A4OJFSV#TWunt_lNd<#WcR9-W zKS&{dmb^dkq*VJ$v!5PhhpA>3bh{O@(0;6?N3y*~+SvqJPEDrAeIZK88?c1unn%;^ zVqIyqp+Y)aj`|2!x;*hF2lU6GWFY3`|NI9R@aS+_2DJz>ct3_-@qso2EWjo1@uk+D zMIfc(cX0|H_G;)n_F{g%_=?z!3{~KKao{)-{&;ug3SY|madR-`{B{SPdRobs>@{QJ zz0d_IEa-&_8W1CjLKYVReGRoG2UuZK0SgK^`VT_!<2QpOIh$wxUP4@cmnWTjvHpMh z5}??i7^=;Hyg1Hcl}?v4ke#U77d#)N#bB9KrD|xp-Cx85{z2 zKu_N@$Kf%-1l*a$xLr?0h0f7=ubm?(%d)loIx1|`S3XRlPWV>nk0(tI6uj<<$a?-v z#txbYo*}~gcsK?$@#~a(C z4}(oB_!%&~5G8IMSlqv8+|Jh@7Tc|M)ztO8uL!2|nF1N&_`8VHpS6ch!fpMkyXT@ z575F#E_g=xLa+P>1P})oi<}iF@`=)PFaEUL^X?f`be=wiYocEbeJ?_MsB+bY{ z2AZ{dp=c(uuz;j5PX2ASHAk_`cXnSQCX3P4=r9|~Xqf_H_~*HZ7MX!_tTtL{`$u{R zb7#G0hX3hV~LHN%=5jBB>2z%P?PsPcP1<6ib!^s+fPt1r)ATzN%<6MU*aQ$h%6`6 zKV5Z$T|wUYyl24$utS(eB1h1oLWW(30q?+R*fG}|UNV_UWz!L%ET$Y=5HYGaqj}8G z$B*RWWlo6=cPd$LqblOa=OEg()73frNDySrhvc&_659QG_~<;a;T7-Wjt8ZLF>TQB zg%{>#C}~=Vvo1Uuw%0*^ZJh&2DLXU)>W3Fv%&yGuP+ekFcAKzZ zoTz~r7l|fDYsgm}UZ%FVudG2=vwQ^j|Mc?e1WBs3i!ukXHg!0m;1o@YQd$NyFx&0M z+fjcwXXK!sq7)!5fgP^1Nun+X3-GQJ{DzIifLe^UF-n65CTZKk+YM^V6+-?U9#a8X zBhQ(Sy>~#_)brf&+PP4|7}JX^g7-k0d<<_mWZf9|-fvzL8aU}MFt?s> z)a$=L>B2oda-qhLCUZLJlJkB%U*lIh+&3I^1{DloGb72bfo1j%UxTJL9jd50Z5h}6 zKNt(OErbzX^73p%z}_>3H@_LgRYR10fp^_;?Azy$8wyohM+|N0J-QRqv%FFi5i!i? z(O9t=JY{U7kA%(z3JZudS0Yw^tWt$~HSZ)CNlYx*x&y(uFS; zBl%wdBH(dOw;X_LKe&JIlVr;|k{!uA5?Voiw|%&|XLPolT?k_b{O!r4FE~Gn%vjEo zetOA^K^D+5KljKZJm2DxcO>vZPK0vWum46zZ-e0l9h;z~{}2TP!adoUM-q94z}ijuFqA5L(MgC@Lan2JoN)YcgH3pvolc}oxmh6{HEN39Ufc+RO|bb# zE3)G9c-qj_X(q<_J{Ut-Z4}sjl+Zw#mTB0WoaiK5RcG!^1sV(KxNn@B!QGR;SQ?Lx zU^o>*b$7^m5f%}1WgeN-%UxaOH$8a4c*AcJIW~{S+sc%B+w(0x*tC+R-f(&qm&-bvy?HZ!E*34H%D)YL=hqh_V0D1SPv4#xVr~XrX;%X`h`) zzrp%_ZNK1BLl7Pc#+gjwd=F8s`ot{N5}2fDs%8$EC?fkfQ)g^&Dx=>Ysq-Ez8~!Ic zI*A3_QUw01guR~Z9`t4Fs|&kitF^cD5i4joBqyu#?^2QAr;3yPe+s-z)n`VQPFiIQ zZClXGdE7_upJ$;c%tE(;<^ruNOegl}@$}y<3*6dAI>zd2vq>)Y-$SMMP_*bXEFTY- z&08iN88WgBW)-fV`0E|&WwPPo(P*S57-Z1R+v{M6llJX~Ibfrca})?u z%ho)N`VI#xk4~!h&90`TXO^ivMXJFph`u~ACE+O_x7!Y2G1dcX)ZwTnYosySl(x_Q zGVy6-rDk_L{F8-Z-i<4$HKg?W=T*lp&VVs!1^D&1dIjh=^ZMM$SmA@|e{k0XKOTUE zKAkey>7Egb!&pmKn+uei8#LWjxQ4bL=|UwIrpV^zXSB$n%Pjxz}h|$06n>HTY=Zo!OnWSZ*=>cs@misT3L{Jjun# ze;D>`%_&U{NNdSh)xmjR57Ro%$4vpI6H}aviOK$=o2CPIEKw2XxODa@LAN6ON$w-_ zBoN=<+cL^F!w0KotTeW_{dsKe8CA{8zHT7`jjsGwFU6)y{kY`wZJEL99`-S@^PC>? z%ry!L?bd1-EYH`&raZcQg%@9dC@Pu5^1L68&9i1>1zl%vZr5+ctl3vuGbQ9_j|}XT z(9zGWEvQ*Nbo*SD36KEyhg&5A6v!#pPUrKn$3dp7)YVE!>UmgKom+v8F!Jp8g3tN08`zIq&#`83!uic!mR_>#7V7 zB4LJOXSkyaoMiArX0sOtw<=e{p*Mi*EChVu=4`mWylK6t{+U5a;yF?p!8{ms_~actPH{G0z;DmdVDqI_<$B@m?KX$ zv?dr%C}%2RLSud1&I>jGEig(GvbOTEEybajPH$+0H#OLj&JIC~D3I$sM95R%bu{b8 zfR0tA$|M9ClMT{bFmP4>pOtb{cf|_}QRAhPlhH+HpP2Hrv%CR7pB{Fw>Ji88HK2jk zl1qux4tzvsi29r$-}zi8H97O{%6(0Delm=WO;Y-JAn1IWygN)OpsE?Z7L!eSzA%qu z^nQ+~UUczA)2BgCtPcgx3$U)f_k)ZNLM-k!)V2fyJgra-0kH900tUet30UxUUg)$wT@8(z>rJ z+3;YlmozFCE_w={6x0v)z99X!`UOhxcbnaF+pe$R0^voqZGYmiY{1c(Y^-BJgWtTF z=<>@x2cbdsCt1V}lA|G}tex_Jm}pe`wP1m@sCnaB>nHTv^h_?cXr!>Jed@6^D3vxb zu?YygTBn9#Y%ZJx`fTrUy!I6!Oe&pd@`sq{(t^Js&O{*;q(w+4DQSN6Ltt^lJgR4X z>s6MB2QnORkmk8^xDM$|v_1#sTg{i9^jrP#YNRou)2Mta%>D{zNs`{knFJczBviG8 zBU~s*m)$2i5wO+g$!dM*^nR<&2kNk!H&4K1(^ZXc{$!-uOgn=+^;h>PcAHmXT}6EC zE+~C880AaA_E?IxCL7BgrsW3S2Q9Q#e z)?8sq%TE%G85fC(8;VqiKqG7Lm+h5FZXGuY!naH8umzyk*vLt?c3hXokco2iW@F*v zExd-(1(_G0tky$R&QHwL)j1JIX-X|aQI`qTZEsmi#{PrSpoQ#jmA&8p`Qs1%-xe%v z4NBJ9zhHsf`-e)13$U>%J1VCO3L`*NM+zB{+QW@GA$}wOY2y;D14?O6?Pm&b;wIXBwYl1PN`%N&SP)A>cX=u0YQ7JQ$xVc#gyO{eDd#`U;@J|{e> z&1GtB7?_%}M|75w3Mg)qJ=*Ve+v=+({9p2v3OlR6sX_bkur?8Aq%Un_UI`pF?e;@AI6Q9&a6r9k9~D{73&aa*GFvoM#GN#MG(Lr z-+}=;9*-Hys10y5w-&f+wl=!Gtt>3OzaiCf<+00PBPwKEy?NEq$QaHRGHMuDIoRum z7nk-lLK$&av1{lg19Ss&|FdM$1V=0_KuZ9GJ9%@v`4P}uoc8mZSGGV@R>s;^bGht+ z(0SQba&vFs+$+soj^mU6RLNt191?{&=0~KRuKrlgdp|&BDznd;!fds(;Py0X52UAt zQ`)Wslhq(lx#|C_wzcu)e0sWC4cszhe{4bzWtU$%nnQjtxi3Y-SS{ILQVmtvPvjAU z7h%B8Xh0NZO3By)p~06^yi0iY0C6{`-&{!#Ooy6rCbTs9<%2G&1 zaLE|zTM`v7Ig|7bS`&u8?>w-w;Sj_mO^-|6nEsyL^3hc{K-^m>$KRFl12+9Naq{UH~S4%Q?}dREIhW;>`YxB77Yq)!fXPYwcD_8s20jK0Rfge-*h`i`>GF(ic_ zbH})FUI}cOSmX{AQ?X1{P#~izI*(UMw&&f6KwCZ_I^r%v2znC#brX9rEI+xv*jQln zx-s)Lb`sWHS~vb8Yx0WuMHNV+@4s5<9QVKOF>m~7A|POX{zt3{uZ`hUJWG(4FR4wg zqCfv*_SZv+K#4-P(2<)HW%ncg*CSk(xquwIQbPtdly6Mo*HH%?UbPe|+ICe1 ze~OCYznC84rmn}gFWnYY0A)~RJfg#AZ&$OA+)}fn`aqQRP0p<2a(TeojUD&(U-M<4 zpDa-Bc%e_ShfELz3>Mn~mQjGHk7K9e0Tw#Tfa<9Bp3)@jie`EI8g9pFNMzgJ;J2`+saU zQl^PLZwtB}b3`c`7=5N`7@vBJftax)k8#1*32CM$Ev7hNKKWQNTjJmN^x`9m;L_6f zjrvM-6p%=754T%r-x0B^!!?feFOkuCX7FxewX z$H;KTIc3_3P6=VpKiAQ;;p$is4;_DlRoYcQ)9%CcP4Gr*0uUyWxwsq;mzYg_otYY% z4gjWpF@M1j#;9#uG;+321T3iO6gQxn|H>|B@TW*5P!|ORaTk-dsxu#PnXqgL=6mQL z59%weDj|FFypU5!&3XCVsQuLWK=}~9l0YBJo`g9FM5&Su3k=XhzrEV$1K-Tyc-P7m zZK6c=UBQGyBo9p2l}wOTCju>8QI&h>bTc9Oe~~Lp)ZmaqXXpHS(7D-4gJDxxt2(KX zkk$8yKyzRin9R%(EzJ!e8w-j}NJ#)WRK08)q&h0mCYBEx-#YPa%k%;k`y# z#6SzFbw8EdlK9vxc=lqvtSTq@skutT=RCV4B{AQaUt7S(iEeCn9#h2gp!YT^Xk@im zNb|Z$0uCDEp!kPCLW{y@zf>1OF}R#93A&OGU!!76r#jlbskHZhm8+xn49>(~-rN^C z?h14Zzk|SbR-0lq8zY9kTRhiPUOgz5`tO@{Utt@V0NIqxjN$bL886UvffvA)fzdC2 zlFHR*fGB`V|Ndd^#8KfQI9f!E2b3JWaCj`)aYOI{G@`e~HnkxdpvN!dW1e73C{ z6=)hOvBv@IK_uPx(4qbQ|cUrvoij#RB6wMCgFWo2INxRCi43mD^}y24GDZ~1*w>u!9_ z*)oKaXnVZ$e*y z%w&!k3MQF-1Pp$3mi*}ySKaYyR5;eYFXQK|FCyORQL=}z}du0-i z%$g$b%HokXlpSGb*%j5>=H@!~&(}8|tj4t%+acCnY<= z7fp!ehST@y&bynl<^&>U@0TO|%#B*Wdaon>@9`)BaZ!VL-Sd?w0l9gO2haG~Jcir6 zY{fSEt@9`W+Agr{1HF#2mhAuv#VY2Q&v+NYI9hp@@Bd1`l9-&1kW9+s71e2?|l8Q;p=QPI~Y4SxQnAOZ1@*- zhPwssX?r!sC&td8h1>W*TKUOiC;dZ$pZULyu2?^{i~&-?Y#9^oM@nsU^su=J?Wov( zZXWO74c|k~XQ>8$=gOX4NOoJfZb#O!24CunW#at<_h9R228HqxkWCPNQ(uS_oin<@ zTdP3FXH6XK6&Ll`+4)d)SUJ3=@@(;JF>>MI{g^bxK-x6HIU9`Ohpc2jHZiE8KRerJ zyYZx{+St2_?I98O@y^MgMrgU%Qg1U*;f1^+(2UC#1@^wEL;fCFjVe;GsbDhj7&pCo z8uV_ty35J7pw#Z4VM`9m$qIJ=SIbQkIl+EyuURkj{VIKb1>w$KK^4W)K0opLym6?9 ze_6r83yd}PO&{^QRtq;+E2cfXJsI7!qu91JJ(MAC`&f%JVlrF886-VibkSCTL~=pr z**#)c#s`d&?m;WpfYc59ZV5~IeGV7XURNHye9FAr(v?44E zu=TKiRe7Wnr>-9)(+3MVkAa~87zuFqoFO;hBY{t?3fh>) zm)Gmk2$XKcCh5|QYpv8$Vx8JzB0qmJDw1m%m%l?YK9G;v95nZn0T+GrB80}ek{|rV z)X}WEiDj-bmaB^GZUpG{j36;irTcUjYCE7cv;KY?e#b_1S_NnSt!8-$&afw8@j3Ff zI+4*lvnVPK{Uv3NpYE8gErB>?&NQ6~Q{YK2amjM@X|%H^-ogCYw)jH1&&&3D#qQbb zJ5w=pw}tP;T(zsus@Xw{@{PUNUDP=VF+IkdQ`}rPO{lREuJdX{5g`a<_UuJk?cO%$hmLK^jiAhpf=$MA^_{)Am%Z)xpXn_@nX`e7Q0`azyT!w~GTzGs*t zXQC9VtWZn`zYtmb`#x1jP>gYVj2om!>v=3K6hkk!*k1!b`b0_xpcM8)FW91+;|0Nt zXz=4&NM;HdW{cOXpk!J>u^lmor4b;(@Hfe6@iw~8S^u)$9>>4F{mUFOH|^Hr(>FU! zlX2DOEgMOau&b_D^e((D_BT8;MO zoebD~bCVVpC9^-Pz}(4KddGK_f`88PT4}0;o89bdqAM`J7+nPhamdn&T_eonMQ-ti zzGk`a-qlsrz1FU%gLRVhgr7JHE_L{VX~Fh+qm zGN`yOlymB_Cs6vJ67N|fi5KLeFEv+efh$WnqGE4Vk|5nj$fzh_>-zOe@!LyR>`gg! zR?vD}S^|sHu`kH|=jU!2=8kTTe*Z3KzMhA!g#QtPR|bU;{W6`;|2H^XXX%iTQ+&Dinc(H$7820=w+BW`4^Veq5B6w7D`j8Lo~e&Z!@$`#bK+FrqKcwq zQl+--!A^4^5LQ+U7~zij(xy@^a zMF>ii#Sz|QZ9A>beGzcQd2%K4xr8_`I}~>>4vV|H zyZih8yaYnB2_Izl-Xk+}<{UfO!}9-#+^V9TmLzLFUvvPx&A3IJZ5T}FlX9o$akEP0 ze(#9-dPCO=&8zeoCos!y0VM^=($7pIh!^t0;>V2+U%St5&-Wg$7gbki`Q~f|-=u*Y(%acE-_%ne;9v@LIj*(elp5#u3bk@^ z=_SbE+H^X8XhV|w^axu@1SEv*gv<|gi1f&-eLh+f+VqnM*IV}Xt zYq0^ugGq$))4Pr6putEQIXflS_lD+I_XQ2}8L)KJxu3_To|f5&YW$sumP~DYgj@JN zh)2FZS~706u}2iSyBs}US^ni)Z8oqS@r}-iv*{gRA44rR_osLk)m7I>GfIF`VvaQe zzq=!!mKu{W9}9+2r<{T=g3`Hx;wpps(b@4DS6l4dO3C2HaLjRSJ`$J*d*RBZ}=YfAq%1!3+v0-I8fdHu88 zp$>QKILeJJmOQ?=WYZaHxU!17bnB$FKL!V^@s1!ssKJs+(oRndiaJUh0VPKxfJA9O zrf%{&=q0J1A*m83Fd-Eh{EMHhk0VWL{8ZBl`0M5g>|D#!Bnc{bjOLx>t1~$tFvH_jRR3FCCM$D6g`dwTNY!9N0-Jm;{~?HRx(7U z^EpRa<9(6RQcxa>?Fy7!l%)8OPeVWD|ML<*O{L=dsh%KM`BQKmQ>No4%y)deUk0;s z;xRQL>)IPI3XU*6n`z7(6WdFgX&N!(hm@v=>pun*K#JxKDo&M`*%Y1BNjOW zo9zV8G#v}IZFLaCuR01{Va3WgM_*zJr6KN+2h0a9pmo8;t1MLKnkH6uI)l=@9+_uw za8y#!cdue=n98G4AG0jL^tw{@1B|ywaxmt3@Y3wXIqC|>lk^@V?`(q$28i5@>8FEy zc=Ko}Ks%|iE383?HZz101VDKv*Vpi#nS2o$Eu1kfYMpdu9UfA24f zwGgld7uvB7U#T0N-54f*N4s04eme%|!vcj5Zc;ugVNGpaT)jkNHi9pwyj|_Jm+am9 z@8(x{&XUskM}Yi1eAPT!HSxAXl#?6@9*w}-|5)E(tXx2+33yr>zg1B<{5TFf(k>Go znDMpOvkZ-(w5<;MDNLXpBRN@~0pMIskHe}WWLN1oKm(~)1k!@2uI>N2|28jhyb4Wk z7MojW%^uGH)+UpYwyh91?C5lo9n`VAi-Ci0UpR1XrD%yh8EDBf%B0W};ILeL_!!bU z__Nzs)Im{gM-yq$3dcKxBwSv>UA=eD8J3RSBYZ%){-aLtv?T2P4-WJ~Cu}#q?v3-0 zTWhY=J@_mHjaZEy3S0u(6oOvufiOp4_jc6N6=cBUu__vy75rr)KTu^QG>pjpNc;P- zrcVD>h^M*Tu|nrptAko~u*twjM@H0aOVvtCa$KcEB7!sx zp~zIW^cqgq9ACc?An@2p^i)JQeR!P^Yxi>ho%@2{cj;<*Q6iP&zP(9DZ*;F5QAeZy?6tynIC^z?y!Q4#lAi9xnY_b&-_ogqC&oC<{Yq_l8o1%Mn1 z{DoK^#;51Fpn(E&d*b-O+nxHJd3rKv?pb%YdrpQH+q)8%fWjSmdK?c_){+2 zeOp(z3{fET;^zL_&h@3Dg195NXZu`{@9 zn~!L0kxYHvNI#0f_?b3+c;~*9MKC)1=h!$hB06AwHrwxQV~gheQi3O-ol{nUJc&v7 zwsNUHpMZsmJN?>5T7vkSNA2(p#WDb!mD9CWa()79qruK#^rDMXL`Z1peKfkW4Vi-P zs|Igw1CgDeXPuNHJjUP7kGA#xav!6zL zrPOTo=ESgn{mv>&k*293Q}cYYZ@0uHbzi|y=aNDmQ*QrDD}x*mDz_>$@I3_+L)3O= z^7&K{2c3E%X3J#^Z;a?+R!a#X2Di9UV}oWhb`G&Q<5r$wM5BxsO~@pAbsi6IBW;9HVw`<$wmcXSSP= zOvNNar^RdsC%8VnWKmmfJK~=cmgH+xT)VBh>OOv9R>F-Kj?@=#9IR$!98R5Btt5(( zfzz9-vi$_}>D{Il3$=Ux-#WUHa_f=@=tfrxA+ak~%onaFhMZYoc|2bgAaL3Ut1yKG_in#AiUntvROG=vufH0!-)y+o z>{(w{0vKWH@_C?sp`UU*Z|uf=mug*D?|-eSp5FR+&LO|d zP=RqA5?NA0uUtHRzl>p+n&9@CE#l#aNFLmjBOBmhpAH;RwD&}$G{A)5H0Eyb4BP3- zVkd-{Z48F>a|~J81yJt2ld4;FKXft}%=u&OKf@)aJ_qM<;#$W`4AyapGU4Nh-7&Ne z`wnZ#FYSCCxg(p#Y&nJRhQ`RxWn^)i^EQm3FtW(7?5f-RnCQkgqWpn24(2P=*&xi2 zl~?LS1B?eP3hMKh>=k6D^U>SNn5%bqyD)Of=da9DaKD`HCI-#qFAbO~q@f1T+08F< z?vabb1SFlD;LV{YcWdH6qdV(|mQK_nvJ-4&P50!>Trhk&C2b(664GOviNAv7`l*F@ z!Ff%9c@pTyQ*<0Ln2ce3ahx-9rN!;4kEcCG#>7e|(uE(rhkB7xA0&mu7bVBa)K_#Eq zsw!mZwfT9xP)Yyh=B8dF*q@V%3&wqh)JJGb2~<}YV{V^4vOo9k-Q7%JUU&dF7hTDV zS6_#8Oc`=p4+G7OFFB{AH}IwV_EvMZW)!P?_k-n`?-Re9610YIPikI@3JV6a08bM9 zkuEfkE)lY-H;Dty$ETV7FUs)-@} zE}BDV%CW$!yYE$S%;rp0Lrr5&HG{w7`lUSV9NSAZ`arXfJOzRmWzOernriUyNVkcP zNDg;$auV2MGwPmbs}SC$O(JMuH%QwFZ( zN_%DjdRsCKY080efG&9OI^RfnOXVN)`z=*Em;57sue;Nomos1A1+RycV$p1Qtt3nc^#>(cAMZtJP9b9rC zf8m;1z1DbmI$xli(3WlLbm^lpogoJCpxBbXCv7Q@qYSvX%uvsfb$Gq*L4g(N; zEG0IV>5N5cpKZfR-_z<{dstLsRaKS$j}rRu()HyeW#qS++_wgr7_z{Zxkp+%OIE0B=u=e`#CQeSV&U?@*=RHL~tQ}`u*~5Ro zO4!N+F-uMiRw#X5Ht$p;wqfMu3o8#dbXnZx%l~~g)>0Sa^d%S1{wiByu;?V4@C~!V z`Q;MZOW+|*q9^^3MP=@!@%)+2-NgFjOZ}Lt$e{Rpzxe5RnDGT7!?#&iD0(~{Y@;Ad zE}LeZgSM4|Do1o|?DW5nIT4wC%k*{lyUi8Ob9!#TG2mclXBVJDq^>e#t}8d-qT*oH zihf;--L`tG^DNk^+x*un`+7}yb{?6;GA@!@GXR}ZpG&?)%0srE9 zJl`e9()MqAd;7Th_0>l)owut(FM+swYisMDasHMh8D??@i$!X1fn{w&!_?|3G>TXN z=!rEM`^LvH`=f}rx`R+7qN9^|VGl9v zj6@D50?`dqC)Q^h!3QoJGKR*uCsGDDDx!UEWQ{TAO_V}Hf)jM9hvO5%WU&7m)wlkS zY`MO<{=E&F=r}5N{=`Mh;K$;K$PScVPX#2O>(?9aouDg|u$n6N`k{B4c8HyVDH6Sm z(u5sE^|n_~fwRA^CyQZ6@(K!{Y8NNDsxG758%SO{@-0z{$-ZZlLU&?#eIHJ?yiX6N zbcw>$Z149DAD0#Z6J1kac*{1ou&~hTXZ!B1*=)IvG$%m@G2l=a?dpu{6~{pIR%C>Ld>qx;4)l>x8d zh;>o{UNZD|_3}F@3v!(E4~0zkvr9t*6;i08bAP(tC&{f5q{;yPEhPY)`~Kvlpsq{$ zO*4k0%W>n})cvmhFuIhWwJ%Hn8U$L|>&3?S4Tw<^3o?X%q^i;ftr-Zf@Z&JJOiwG{ zwOGU+cwWD$OU-51Xw9TfH(5z;;S0Zw;J+TH_47J9R+p&ylEXDuOf4^u?2e`_)LG-M ztgPI7*9q7MVlG4G^oT@!yj}Il@=a_2%i))$4%3&%n=*rrOhZ-~Mw~4mAY9+v#K_ag z5e=pmQ~{r8>LMCqfLOiV$`J6u$kN26^FzWULNI`MR}%<(GXR`e-C~NjP#uo8Cai1< zN_#7-u#Jt4Y79S0>F5!Ir!%%cce6*NzCGF2hlSleQwdmGR(WIk=7BF}vXyJ;IA56V zz1#gQ^0tON89I*wH#8I1JPrj7gxR|-S})h?O8h2^#qQhedqmpa-(EvaW>m$bCF`&m zA0ym{jM)>jtA=oVY$JW_)|S-|K_E2*Ooft&fF1F<_^vI+4o4<9PPjJj_0_uPq3Dy{ zo;Qc6*NX=8smK2Q{wD7S_B0-Q=7rhnve-v$J#2=h*cFHx-3AykQSAI^(u`-H;xIU%>z)wq%Ks2HuO`L)h^uG;NPpWAj(wJ!P0yG*YoadlN6njygR6p^GH zD?`QWc})vk@HD-|H*I-qYlfq_N`q@hxOXsiEhpTrXRCT{AW+H7+Tm^Ug+XC_aigc< z939yv2TC=+?b7aMZ@A53ZLwh+a5&$B|fMr@VN0>@la3v9vtBm(; z2-O4h!^l_D;*JP@Rx3cd)3t_17vA@>WUV(j$L;jKSV_I>nL78?4>s^Y;&xMS(36JU zk>oWVWYqYAU3OHWFM1QR*a6n7UF73+nvo)L1krS87x_fd?GK1NTZ?*$&lT7sur_Cg^~n& zk)YJ=enyM4e(Q2E)abPz7vpL~N8?u^4m59A>gn!yp{GKxWq*G^xuK#%ol{|}3z5{s z#U;MDSUIh`JSV?+?QF08=`=S#-*m7)_sA2-Ga65oDlslN2z?22?TRp6?3QCm%n1aK zKutg$moAMq`n_n@_a#f6X4 zCP#Zfbq4G&tx4M=D+PU{;*w|v7q3LDAqwL}7Z*ymmAmF^Espbv$ zEvpc~mg8~gR1U1gelW}RO~uMqp^+I)X?730f&L_N2>GkIRFfdq-usSg?kwM3G|Gu> ze=V&7%gKp}t`)bnQ6Tao1>sB-)PcF}S4Xgw1iRvtgtf+T{t|R=u>O~zpYG12b!cD) zb(UZ-%SvD7iv6~_*BhPQP1BKYPNA}c^5W$c6=UUTkl}VGrK3qjq67@6YK6)c-)5R# zW1PB(_Ouh4?GfIsDw}Iopqnv$41eThrV4+mn`!CcnWS-W`ei)GI-Ku5_wB>U;k$ zgXk!2U2ZI6$E(s{^E!bJIDZxKNN_M&T@^P>g09jmBDd=Z^%ZvXtk2Gza6)iD5GL-^ zzf%%KCJH8j*i+qf+^KkbPJp<9O9d>SF_xE>hGE|e zb|y0EB#z#P=q$i|<#|0)6$j&G1rK_b=u>x_PPSr)!llTYx#lE*^YKVXDq686LS~pC zV(EnNZa#>9mhtsHEuYRCPvzgvn@q)jrOJWOdT7T1g)J5Yv6E|Or=9j<1mzXIn)`Vj zZ@ERxRAN+G4kG*^=pp&7y)Dd)g#vg8GK{0stx{~I7i&%&we>ax@D01Ejdki#W-*SB9 z#E`mx=&se`%2cS7wL1_)soUffWWpY5y9AUkMtGdu+|_2I1VG>#U97WCsv{!rFZYl_ zFpGF=#*@x)0?H>&eP7Kn3Fl5mSue%HDd5CSPUpeB^!4>6Cnp!R#(jCa3{#lV(qc5% z=Q{hnmPhUq9$8!w{yBk}k7;Kz9JiZu)L+Jrfx0SzQ}~Dx2om4q$m2OwuuD#flW)*u zi%+whg3rg}td@cKK)sTFaW20&ZQ3KbJy~kVDSn*+$m#hu zFP;|H6N(H)4ne^PQ>}Y%VYHqzJ;Xd) zO>ma8!h*y~gfa9~xEtWdxxRTA7h7YV7qJ)2lEJl=WQrse6p!(O0{yz^@;40_Ta&8R z$Mb`TK_I=zaUS)}UxbkbGUgenaJ+YRHu-GZrWQE^tPtIu-;L%HGf$~Wo7c(D(N0vS z?DU&y!NJ+M7@|>I@t;;EA#GF{0QdlPa$|7N#S5Kra~c!68y_EcfV_8t3B;_?L#*I#NQ5O@SBvrWg`7AYE*r}f zlT1UDUi@njgp#GOzXPOLt}|DDKtMo3?w?=;rny;Iox(4h`1JW8Bp9LcuIh=_G@K=1 zWvaJn&cEl;4Xy|4bxEh6Tug9b4mPxR{(7==c5m@E`dhy zrZ_$#@rNPEJG{sO{Kx{$sSo=1yk`4$=+)*D3=-HP@c&&BAgqX5TiY&3HoR+4oHENooSlw*#C9K;+JgK{GWD9bp@Ew-Dn2S*cNOkwN)!1fja><{5>#@bsZ}xglb#KG8i|UAz+-SX2 z(k$|q%Nq=)ORkUJ!mg*wgM}h5mcq{)@8=@lP?iZa3dUfMnpF`*Gx&G@+9W(0*iWc@ zIw61mlRYL4s9osu7hlVD8Zdf_ew%EAc?I4fJ{bz?XOZbu@>Z}vzt<0RF?A$XnVWAf zIG`t)=jv0Q@Xf>e$C$a55YEgj>4*!WJHqg@9xXv2ebV5GKl3@@r7!Q$h8x0TmZpH6 zx~i2Mo%le{^mq?Gu>gJ6FpLov>suLn`7K zU>tNCYPmL*e^INw_-5!tC&~z|H@=gnqDrI$O6T+mi|jaMBry#QT++Au{)hX15k-6Z zGcNui!hp0jm~}R_Mcjh!kbzu9Lq4Eq$AK zdld3MGCJg#c+)AOI;Ce#fm`}OmQYiH*ReMCS>$2R)IQ0r#>qL0e98}!0S>BB%mDvW zW+iBwm3EYvz`4Y{NKg!88m5T(+7<=-6Lh!gWiM+|0}4%j#*o~oyE<1Vm8Uwyhnd6D z=-xqge-XS^N(@W;htg+@5NQQ%AkI6*X#`zozgmsbB5} z1t&ng2~HH;bS!MpX0gc zh*x1Mcs^C%*@b|TgO#5u3Ev>QJx+go%TDtvKS*E)w&uhBwOxY0Ndy2bQ=sdg@%Ua- z4=(=k@{WkNa`F2N`k&H}^uYo56G5Uj<(us{;2(OvdVf+<48MRL9zS$HHj*IW4na3a zvBB#vR#@xayZVGjl~e8RnNcd!IsKqd6Ps2Mzei6P07-q4_xo0b&5;bXNsAnmtshwvooqvDXX4 zRq9DG;`&goRG^MPXGC8Ny(9c_xU6C1fdbPq+i>0@(vmfE(jX%pqKeRmO4)8pUIXy% z)%4ah@wvPNDN~@LBp6*UlGXVUA#3{D=u|~Ib5pK+dP#Wdt21CC%$7Apb?Di2m+Lc& zLTpJskx{VTk!Y}81Pa2t{DqIX6CbNgZ13!lr$QfF zH`OIUCkiFkjnL}Ysc`7ZnvQzIUsH%tXz>-}bUx`5m1A;~iO(C8j$0RJrpXuiy0 zuns&A->@tgDM@yknJ?V4@zi*Ub}308knWb9$DVgU)Bx-vA0p4BDt$qjPB)A7n0z1HLz^!}Q^E5j07+a-#Vd?>MJ-qm)l zcx;d1!{`XV-3yy5@j4IJ>rIRL)Ysj!2w)`20z$0tO!Et6s-id^Ytbd2o`Kg1K2sPY z%LDoK>26)*2dvLi>3R17R)99xeFKnSj=p)OOc1EdYt#kN1FctMHJYAdV38*337d;| z!Vm?HY<&@A*IS!NK|z5U`qN~wPcLk0wAwu9EqqNXgD~FjeX89D^LsTKH-Vi~bBVc! zP&fO}s?#N$IN=w)EIu*0($TZJ!EU8ht(0eVed9(DL{7LPpo)2@GFN^(qT3BGV6wtW2*^Fbeg% zVCdGC)6FmN&^da+s! zHcbi{rNa`0X^r+ju$40LfMqNFli+?6h2dv`3$J)K-P0-#%pl)4wH=U*P6=Fpf|^Kf zEPh(Y!znUz^uLE;1Fv71vxkdL^<0k@w&xt*6kmK;wP%EPrLeCEdKiRMu*Ks|=C&;? zXh#o|70ps2%q>t@lzI6HvOXb|JEO)}KWP-tm}gKMSq1g{f+K1Fj{bh7J@~BMsos!; zpO0@4x8q*wzpkFdbDvyW8wW4R{+nH9N=-#iiK|5!5LR#i*f^sE^_nqe_D_g0av@kK zNvw_!K)iHzX8mT?!CVWcgeuxFEE&OWk7|!LizP|Os@;wWRlZg-32H>gDkWQ7cyFng z#|z^_1}}>}&#x@Y&er&EQKdPapD0k6x;AlqVr}ZVVYsF^~GeWJAcQ< z5Y6K+)X7+6gRnxl@CNZ4ve&FHOGP|z-RzF&*`C-_&?-A#`F&sJd`AJiRP}4BwzQ+O z322|7%u1!02eQ=x70+WYx$S_)TA-%jrFJ^)n*9?0RV|d{+*qN5^)eRPKcoBpu(3pv zEc2UCsZg-;pdE_1^H)=ps2|hj~VD3B%g07xkU6pvp5&?-Z|{C?cX`e;vWq;H5lt@ zxKXVeJ&eMv%)n#*@tr=ux^f7aOnq2ztFpox&s5ujIVe>Ao3#iz{c6C5L*sUvYTxdV zg}*?<^nI5y{g2-x>@JE$&fl{~CEt=Bv@29(0+d*>lHi?_SEGQQB~JF3XjtS?ZB_%I=IfQi+Ec(S8V;_x%h|^;BRcqJEZ3ZIO?}>j_z2b0&jM4ZRCkeHHYG8 zYDTOE&Gbusg&O|T!_AqGGmSzcOmKll?K306*txU;U$@?p0FtUvs~a~Wm`Kx)K+f3m zoH@I~g9I_T*m`)izO>QDw;j!|ukQ;`?TFP!!7)e2v)rWM4hL7!_mUkg>v9H@yP%r> z)1&m)XI07hiU0<4-*R7k?sz15eOe=3Kj2~h%{&?EL=*y`1FWp9ou!rSLytE{3oULe zLPA2OL8A7b>}(MIfTVGgNC+tr{jYL6@T4Di8Ykeq*e9sh*_TgIdTG@~@Y|8`Impz1 zU7@soIPMY?zIp`VepZ1`f#=#9xsH(40S{^;ncjP$?R-S?R1-P*BYkspv(Gb&NAWG# za#lU2-$GgH$k?*ZCUoecnMQMsc*DTk0yoRuW_a_+$lisD6+dA6xz9U5$rQ9Lpl!3% zSIyYEdI;5PQa4Sc9Aw-PE`k-EbmE;R-5QMBYMlgjp~%Eu}ceWrYckTG+7wh z9UoW)MxKB>@|enq62c#jmw6LZ=2)C7<&c#~Tf5!f>u&dxF8^I;=5gWqgZxv)TQD)V z`jd9jCJ6IWzj~$gXH7*-N92zUlo?8}f2yiJWQ}Qjtv3^3Hh;{m`%x6n%B?p}QVV4g zXMXf8H6zeBO$`|G)h3$Ww?e*ndOQBmez`3BdPo?8hZmU;ancmwcX8pk>hokvKuD<7 zU`GsKvIV83;SRjIH&>5l>wOTQ{aaxgpZwZ!ai}Uyk1BC9{kB7~$uWfB2E>&EmsG>Q zwIopBteJr3D@+(;Or_0#uX&p=Wv#A_CPhb_<03xt38j*mGD+mggSk@bh)h`n2qat- z@ZWr*oe((T$kxA!@O4#`MsAgC#Vd1lj1s%es&^X}mw77afQy$PN##bZ70Bv!A@{&$ zzz5)43uqq`UsnH`RI4SR2DN$0=B-wjrT$|^@1eDY*Swj9ggNGK&wur2A;sUYK8tVw zjM*8#8xW^pYKXUg=S0=b^!xSRGu2Qfguv^IxeM>mO2@lTLUV!Ot~)%;%VJ0Rb+xTT zI7JM4M8gk*5xrU7C$!NkO<}=*3b$Xp`BR@QQfY1ZQtH%>y6WmO{RH#MiZZgT-wnGa zan%es%5j0{6F^Ah7It=KE-tl(4?$w4f*%F2>0_%7fqFk-7J*Bn$XN|3d3-x0l-*G< zy7($C`eYqizVf`ogK;^1gezlOR-ICkA|Jf5Vf5w87x$}Co(s=5PA;yA$w_g0dlp+; z+yA(%$w}oOs7Hiwa}azIl6Em-khrK415jWCUG7Yb+)KkD({^I`u3zZdbf`HBWztoh z2m@~D;5_qQpNe2(HnLy+?+}Cbh9srsiCz`+zK3v)r~l~h(7d+R34Xd6h>^h19}>iW zd8zJ%&Gh8w1cw`^9G!dL;_RZ?C~fjb6R<7BZIjYicQH83)0a-ujk4-ytozjGzPt8y zy6OGZh3G;@T$_-x;+-eDKd~CRDEuv;98nUfPf-$X54u^2IsDwg!_ZXkt5%zFop2x- zGYmR^@Sgdhi%&V|O0C|eBC8;uZ<{H|2Q?tx-z$H$ESQ3ZU8hyz5C5E&4{Ypu-{P6T z!Jhf;+pURf1!Jdq31j|mjYyFu$3mi|mV_enf^+@^EDR#jT~ral9+r0B{??G$DID=R zF2 zQD7By|BX`y;!aaTMhFxw zW)RpU1*WUAC0weP1;*^|?wqgpzi}$`9Nlc*Jz3h>6#xnfC{z(h=fFYfJG;Y1Lr9{r z`jIeTDy-Y;9wV2;?0B&$RZvi1CyMAt^QQ%1cZ*@@)ClZtLa|f$;qTGVYes}DwA6di z{Jzo#_HWS@MZ4y0FZK7kyMM<%O5Ho$7uU~te`2!-yR_tPP7B3-|Nbfi`+GXRTx|VH zLg==vR;vEk2qeyHU=Qs@HxOgDFK78um&*1Q^2M8_;ceMm&)Ow&clC?U%f;yPb_-8c ziI6JKvola5m=vMBBl)r0`UwSdW-?@c?)5vzfLwTrp|n!p!F^8mPlbwC8*b%=wwV>guLvUD z-{W~dIOwTq*M78VD7$z+#M?lOtEZER=4YSDDMJO$x*}0Bm1u8iAyk+`0Xsl%l`c9f zy)z(sM$Ov(Wd}$##SK4aPRM5=QWl}xd^gHk)UO(Qv$?s&)!!?iVUwRepvkjs!O{B2 zfLjZoxlgl>b5Uxo-rHCPz8fFyGYF_MM-t8WckJn?0nzeY1_T8lhhd%lb4a2QdsqPy zzee$0bbo+lDxgy8-|E`B0Psg7gn;{(SFMnrzzat=P=36`;h(?L+|1eW0X;;OW(07J z0hkGZu4z)_V-*X{J4lx;sDaz6fm%B=^?Ecd%8wd=edE1oO0zzJ-O540WkJJ@Kw71fJQVsJj(|9m0QMolrX)2d+; z7GY&OKnNg;LJinbL#^|0DW^i(=7qK{u=d7d)7KEo*85+mO0#9uKWr}bJYR$-@$toK zrvKV^!oDr$f77Ll&X&*!uu^HotXuUL?|f9BIiOTu)LWn4q3vf;tmZepfCeGk^iyy1 zAR`Kv9idE3d|Yp}BxA_mP-6bZAr0m-V90GDJST8Ztg?T6AC)Kfk0%Jz#nn}Pxj;AC zVad_sX&DcIE7L9xP~;`*7;UW2r)IFW>lMn6b(cl}&2@&b*4eaU>BgP7ik|ng_T&sm zV#=w$#5szuP;}h>@?MY7egC#D{VZ#{Ndnj7){rzQxX>&e1{E=Gw>rS2>)F*)oA1>L zU-F@{X{XZ$`R9LDq`{V{H5h*BJ)(0rT8RD?M>UJoe1#IP?EQ{^8N=mi0!+2?leSG@AYl8JqRs%7IuVn7jMVYv`4$Mv5iNqxD~nYrh#Brwch-Ad+n`9-TGZ;Dh{vk*I0J;)Pc(* z-&d4?Em@j^Dc%anDY#(feG8QF*$)LqN-XNs5`s;V(no?hd5`RfPSA8d6^a77z(0kB zP6GcD0cC~2hoU?t**+)0K)foi_o2&DUx+&p6Z3Mv7D3_mHn7PW0()0xX=rY4(Pgfc zL71E_q#XTfpaMsaZOF(Rx=T%;aAdK`2C1*GH9cBX_u2j7#ph+3E>RflaWqY4&aA}B zoDy0_VSQGnt%Ej}(h@0%|u}t!r^VM*Y)lOfN=Mq77P1CA*jiRmmXEJT2 zm&#zt*^Oh(SdGVm`;7(UD2zV*2vb=d=Gn5(Rr4EqK7RCt78qdIKgGqxCJ#ZOA7Q6b zN@x^(?{>-JiYe-LPFBv_g&d5(D)@&KsB(_DRz|Bn9T91OgK2;r6G^MPi1zxs4L*+; z!tQVUf~HnW_MVK=eCXDVcJB)GV}&-FPg{xEhQ2A1ar~%5Un2A?+qw*r=y?VfMHJez z*F875`#iN9BSv8UEkW+~QA@Mmcksk3xFq_br4#C+&jjp!vd5OEnx0RxcUZ!(PbZ>l zk!9rTU3jJYw*~-W7K`9K5U%Yj(Vy3<`Yo+4M4n%c+>9>`}C+G4uSaRg^c8xH&57={m z*=FsyP-(!OZCO2*QC)d^XZsd*L9oLCqUY2d;!ux|&~Q7rj{VL%^dD3`FhHpAOMo5}0~Ol?oTr>i(KpvzMYb{#KWOf9JK z(56(g5jIGabuEzVGS0n;Qn|oyC3@#q95MR&)hgXQ(<2z**QtGgEV5?sdPeq*+QtwYJOyFX{R1 zeANE(hGghJRy#5d=4)e2D+%|I&C~Ciw`?4an4&a@6jUbOOd0ixYh3*GXNXJ%VJ7kj zO5+_{{}zR?^?bLem3qhH2m6OE@8cW8wPU$TAtN9BnahfRepJNC<#h@&uo-u_ z)x#t8!o;#PKA+X#(AnDBIusW4$Ctk+X_aKd>vR7Ffz@wqV7FwI!l+<%af*N!r69!9 zzde-wLvcap@*70qrrZv_i`d#s5`mo+GiW$&Tm;$t%lc%a6VkH9uM}UWp>_u z{fp|Ro%afO;S78Ip<*-iHWc4(?jrj*o+mV-&TpF>U-wwnhEH$uA=Nz8TBRlRzP;`) zRgCzcUTRQ9JXOtb9E>3)Cek&+NQAO3=&I$+7O0Z$q)8So^Rp zaJnsq!w3q(}#Lprk1-Wap%T?dzdDtx9wU#XN>?`qwQj_LgUiGgb9S z!f>ux?1k#!GEB_tlze-}&Npx8j73|Dt{6&bUWav1PfyRM4BPClMVsyHssHv+W-ATG zx&jcbg%gAR>J6$c?k2R;0Z-gz!MLtz5cpSk3%NR<<<>`oTqS+sVX=N>bHb_JDrFpD{EXGQ@Pz-4EX!FQ z5Ko^i=P#|w!+n_ghiyBTZTq{P($sPCVPmXGA59FDT{yv5Fg3^5CiOMO^1lGVonXS4 zN|8|~lgFs5VLUeCtf!%0hxYD|Xv;ry0v8@cttpa?+Z$V(L%W<7I`<3#5P|>S=G;@u zQWb$gmo^rAd>f6+$spRdn-pRFHazM?EqqvaVMI}Y91_lob{EwDs|#PH+ZR`XCH#Sv zHDP0>ozCYh1=Yp^`FCylf>WRt&|-EaV2Uf;^0<|d`Zcfs+JiqPY7%q%mZ-*ZzdqM! zY9aO~Xx4+@oXk~fN(A0tkxa>7TXG}Lj>m7&f2J|DusWXNLULC%spJEVlJDF3MIl(c zA8TwMF4A?AoE~f87Gum+?S8wZ#;Z`QTCCQ~6m|z7h*#kBb-3f6Ew0p^f8haueT&-v z4qkGzy1J+%8v*En>qk@|I8BRLK z4+E_?TvU(8cUb9-yhEhEJ7hm3;_B9Xg9}dM>i;^SeR+1iX(>e5n~kFl;0c+dC4Gp( zq1$>AigyPkrt%x0*TYIb899LS!^_~p8%a@QG+h0IVC(omuTMwTc!Y!-fG&YZ*gF}J zz{1zq3_)@SW2T9`EBg8(2|WO(ag<5RAWU~b5~BVt$jZB$T)?*lxLqSH zqJ(ZYi*K=6M`CR0Yx5br2= zra#)Snf)_1iC+uJiTX0~>0kbrZWzMIvUpyMeI)O0YDV4EpdR`aqqt1d8oMgRnmsqP z?Y4Yt|F4}AwCmZqe4JNAv8^T#tfqdD!~j!<^52q+W_$CWt|uIK@RGso#7Z1&85Aia zSW0FCi_8aQR(h$}Pj$pxZxG#^!=a|a9Jtz)ho8c6Qrm2*57}e6TWl@_;`$U~EJ92` zlhRXmWMyJ24LceG67yYkXQMScpMV8@oD5ZoYsKj2qJ&S(?<@e? zqGiQv?MYu-TU&-E&ZI_*=JV%+v$MVBCg+-{pQ%Xj8!ypDE6$%2E&Xi+;u|?I&Vp)@ zoU+uR&(qZV^^ugE?dvDIbh$xm)hw3`r=KF8!@rHZ#<{)WzGMnSJ>S+h&FN|&YSrqF zyu9+YB-uZC{pmw1D!E9;E1nW8GL;K&b?!*=();B^E%v|(N1m*KrE%hu6qEN6ZGnHU zhNiFvA*5P=b|3JZzgeu!dG-|SwD03L+g0KCtTc6y^2_-x7>()iGD=~OF#wUdo`Xs# zC}kry<%q0f`x}n_*&&4*Pb}rdJkAkXn%525+rNmKDcVsy=Fr7GAs*+XVY$StF%N!G zO~V|YZvN=n6v5Wg@2;kND)j3ndYcD~z!-pKc&%xi%%X{Hn#m%?cY*nOxmj0LoURC_ z+|lJ|;b^f=>&?3~fcLl;q#^G>%(jGkA(5})N1VAi03jh7LIjfM_BLjkqGGUUj4=&- z#Vvm$p|hOHj(iu>!s9w0My z>Z)%_q`o?7$muE!*BRWgD~=H6 zB%+Sb+l70lD}i216KKQ-%}5G8;5^=|m81bh>gl8=_F}Zl7M}R%)yj{0k>~ra_mgRA z0t0!0TezPeuHW1f$6jZ1kCztPtNS&7rcc@nG7KzY^=DYKRiuin)=kUd;#Y0qov{UYp8rIZL{u^MaDS=;NvevW|U%!KruJd_V#`=1n68T=dFhoQ} z885jie7o00Ee8kJ1v_B?>}|!i5FNFCWfGH4{YM|-B^sP?$J1rLC=#KefdQlmi;sY9 zo=AON>3X3L+Uy8kpGRL619ip7%zjukcRmArd9z%cne*apV*KTZk2zJrcaG4(N>A>q zu*&ea8Gdlc!AM0+!{vze1R@UMXbrN^!|={Bq4>w=L;UliCkw!b!*7AefA_T8B)7L+ zeOP?YGDx<`|4z?tYqTsnnKC}oB(*i`B8W#HrkeTL7u)EQ3&Vh6)&AZ6Lr5{`t=hw* z=4-Vw>qgNscY3~_fmXKT(2XM)?!ks}0Ctr#>sG$1VgAGKJ@^6BiqYqHSZL&G4~E=l z?k>2aac3zSEWnmh{S2BcQo3xqv+p=@hN`WRWgE(^uZ+jPNoQ*V3U3$x@*HL0pHup z()jpScCE_?@0t`CE`@7~*TsMJy2X+(!{Zajh2*>)Vy^)9;`1`5Z`52Qlz4hG?)9cm z(MDV|{7=5*5B~YY-{$bD?|Z*1RKHbKw!s5RQP?!2GpqdwUE=JikOqoO{{OLbmQiuE zQ4+?21Pz4X5d6d49fDhMcgUc@-5r9vLkJdZaCi5?g1fuBZ?n7S%pBww15M9;>sCD# zO_<}!Oa}`71~IA3ZpYj)cpH-Sx?K|*e#ExM;>Hgh%BKJn)tAT*Kpw%~UcM^6v9G-@jk7rv8??n$tM~i6mEzO79fD={@q=0qpIq7hzR4D&T$!qSH^^=!S`?Ps>EVWp zjFWXJmbAhHro~mVyMTq)bkX*Q5_QYNjOOglgq% zeb~)teLO5JNYiE8^y|Y75m8aWa$R+&et!aToxeXcqh53G!_^)h0YS#efI!Rm%F@Ob zNr)6KYtjdag2ee~RSD5J^3F+T!ByP6H5P6>Ec(xyGxn2uDHW#O*HNinU{EGQ_73x) z_`_U)K}EM4#o);I)VGN*UV2mZx@}c+B6f^c7-9$q{{^Z93^Ys~NB}M3-Q!1iB#ma7 z|G*MStqN%9y=U?et^NfHHrh)lb~#MxM*ic8;ej`E>CG7Y)8~ zG!VI`c%%BhJv#-kh9=NO(%tc>`39A(BH4NKK*0zm-JZ4m`c%csg$^!VbWMs%)kD}G z)?$}Og$pTst*~-DSm~>1a#5ufviqs!GpyJ3Mw(XjurOjdJ; z`S1Hng%u6%Uym{hgcTw|_qet(rCX_5!evosWeiUzb5oO8!D9Zm4Rn6Vv&4UT zgBtqW12v(Kc-eAs#Uj5sKxKEgw+_3bX#tGvVq#)mTLf$C{s_dso0{Bjn*itQXhcQp z=#niFnM(hEYfX;S<>lqbJ}%sZKSq)nfWXv;IcH!Ifr5rMH8(d9jEvK`JS(-EM*uRj~KwVRN!0wNq;92S*Z^8DVR zu`FlrpY#q{qD395O3$@a_bNq6j?xKh$dOp7-s)qh#*|u6*r_+cW5=SO;V6a^aS)|> z-tN5;vA%p(KKQ`Ud$R>~?w)vYR{B0D4>@5{X$W6SAetG<6vL-38!B6u9U1?`m~!S2 z`FGQO=MdsmwE-3ki+5_qw=3A*f3SZ&+FRY^Ltw;IWO)9~C7+O;O-$^z4qb1(pls|% zA2g?vzMDSwgU9!kAK0&%%kfvhW6aLpTdY##_OO#8 zT`-J$BKluo(`=LQhrn*l&Uv4gUgkBAf(p}4R2TN?YVVcSrF0RJQsTxax(Y&47Ir}# z8&};_1u<)>8?3otR${N+OswB5zau035advUIC1J+R+>UXXjwBZtXpW+c+6;EL1eie z+xgWW&;?21HnLrK&*o(si?Uu}C8Z@t6z}zD9(G5(y)HsQ_q|&>!(bIOq;D$m-y|@` zJ5}*FEhx=3AX4om{X(NF5gf(~Xn>&8Rb`P$Cb?w%t!KE7PFCkuuC{6FcV%k$d0iI2 z>@d>DWQX0$|3HjU>RtwjBI6--&(|GKDXn{3LeT?7{dsmOCaa;+setjyY;NW+*>Y1y zl2(4rr;DC;XFDUgC;~myq`W86ipM7W?f#%4)&whn5#CX5wSicGG3qHGMGHbu73&8l zX7-q~kNLi~a6QbHdbc_n8B1W4)~|TB=>rD%0rD9BfbqR8AiDbDk+t5&alI4zeK$=O zhX_m^rmWKZ#MDVLNo|sz9v+QvuTK`1B@9O*)9gSLW5X_WEQ8AtCbR=xD(PX9TTS=E z@vk-14xF8QR*pqj)nX-%*?l^AjAmp+QP*OJ&q_keMtA3HIMhngvnaPrgVNJlBW|$; zKW3wh9_L}=&P;yF-jx3^+92Mm6It&7ne-@aR(pi#+=5l%JvzfQ90yJgC%I(={v{ix zGPpl1Z!%?uCz-{a{A344pW}5Wg{g7))48`Tc~|82ofsB3n@v?gW*W5=kICp>^&+jx z@e@7sJS8RkvvD<)OcqpiiJae25A-^RkzR`Bre+buxROZiiR2stq``x&9pGJkCgXp9@T_LKMaYT0mAYdp&cwKTdjFSv@vk680DqqA0J#Ru4&ZN@Csk*{Ekz zgu>@~bysrf_Oh9q)EwSYYTkyHeA7%UKTbF1BKX!9rjPInNCE#ZNXB9*}_2q3G zgbwg<6gZtyB-9F2m0l7Hj=|jCk;Zs=#vGK`sgp1#MMsYv?7$< zH?KE}z^$Q@>VKD?MAvUT4o*&XRz1(Mob`2*`+%I58_;`(oGsln=taijO96PKU0t~V z>n~HOdO7V;Cph^NYWrqj8OFYHK;anghffs4z7SE}}Q z4|=9*cMc5m?i~a6f%$fNGenIz8IIQv<8#^u5i~4VBeog`ic~|M>KgO)@!Xqa9X&bn zL6sbNm1sgKsIh#Xmv)^G_L_oH1_BOR&l=~i)QybGkkk**NTMl_J5=I0#b2%deR=+R zu!r7H-l`y+1hXwvQKQvv$$lP`y}Os8Dol|U9GS?3*gG?xf&N5pP$$4x>Tj@dv_I0=1Bqz zIw00tSX4wOq5JG3SKq`q5qO#EW5c3yRy5av0(5CBaQzFZ}EY zMbsx@w=!mih_u~vU3rKz>d51~ArZejiTPQ-`RAI(ei20bPRYr~%gZzhPNY%1`BIVC0X?W|}2<|90wbY1+^HY*CD>Lud!bo0b6Zh~?yO9L- zmfXPfe00QCvzlb3B>>9y5@eUp;Ly(xLWbSSJR`}GT-F|?U`BM(>zPQxtXu<4t;`DB zdXf{UH%tPbsq`wUQ26-})mD{IA+Mho`&aLMN9;O%I@^4EUCx=DSk%4r`CFBHE>lgo z1NR^G{vL-R2tBe-wNOLH&3!7d0-oqoBW5NR$tZPFaDtfK(_ye|zB)%~G>l8|-av-; z`Gx0jPKWrW%+OBUBI|7s2EbOB1?!Ex=j)oCk3RB(QVWOjVgzMa)3)cUOgDI!kTO@Rsk_u%kUvl=3B(@}(f@y?672z+|Z@$CcH!-q0Cp@csFO zg|;1{lr)t2a2A_J9l!M#{QE^2!F~{JR{z4cv4t~c$JC}PT?i5so8y04_{+t@r>aRK z@XSu<_%I#C*B0_8+I&!Qu(K|o>u3I|fLON4u9N4Py36(~bkIj++iqocCpo+i2jx@RMp#{WK zi~Uq$)cKk+WV|0%iEiMDrMIF7Xe^-Mk5?B#Fl8R=E{xCX!V3;Sdf@f+sYt8Ag{Xzg zdEBjGkN;C&NNeJQVr6EaUjS0LHppMf(Emmj_3o^j4UNXgn76ATN2p(=BFosAR;vcu zAW|*wqe~NJ=E8$i-&|AJpRHz72C2dsXHR$Y_&F%OIcDdq-)pkm`vr9@QaX;Qw}luC zQ6l)FK8xw1>_IR0t?=zf!a=U4Wc}N!4`Jm(pSPzwo@__(-+r?~1r?GyDj8}(*2V?b z{bv|t1-46L2ELoDJC#&^Fp8eU&BO~~(7WQ}=oZ{Z6!Wcpeww84da}8nIH@Da^R+O` zN-qSCR9RVB@BP1eEiRLjlS(YSB;nug2PFkXK_F@bG{RJD=&~U25jz*xRWFtz23jca zmZ0Y(p&N~ZGUOg3T(SOL2`SvT{$H_iQ!KdWo??Ndz1w#zpV=Apu6-cc$-3F*N)qc+ zHe!MMf0aQ~(K?@Kj3_?#B+TtYp`5oAB&}(0v!gQWtieKeF5UuTYJ3tL={K4Bi zx`6kA;Qi;z?Z-S4!<6-@tG*K7m7&Nkte&V+*Dk-aT1|JrUTqaUt)Aj@?XsgrG-zvtgSRe6a7i}Ypt0V4kU^}rgeW;v>!noxtS z!I26!L4Ixb%R;NlwiYjsRj)<|rMR+7vg-K#VCX_dG_s(OPe7Y;P*~aF*X8Nx3YOaS zi!^<7R2v5N+PbfLICN?KGWmo3@tVabF0_FOb#^u&$Zu$~Mr40x_MnM>u2XQ}+-!Jd zEb~JDpZohE{uUnR@Gq&vSTSoF(v3b}Y$>FGNofCRBZE6lx$fe?G=$0fjhR4)>>i|2 zc-3qFBjvOA8>QI_J(;H@qS=3Hnq1kV=a2;veSW9xxwR%KGBv${$lzGz+0XuPYU7zX z(3RIF-z(}*jF%XTBl|SjA;D>pFyA52P#trTJW>nky(3ITgHzDG~7qFwp5484Ez}ih%29eoaly zVI)Vz+z2qmcb~4b@Hp*b6e(mGdw4VpACK={P0r5`0vY|Lllmn9GK1an;a_(cJX0#; zpI|cgtYRkfB2gaim454(qgmI_pO_B_Gc3gOqV!G4i$w(?v+kY)U(~me}Yx5 z-is9))=0NT}zqS}KF-z85#! zC~w*(=ma`D-rX!sIsVe^!KyS=2$J1wIiN+?k#@2rJ=uM6Vf4Faom+8bue%cdiTrQAgZqB_uWA_)* zB5xp)0xxjcbj;_r-XB4^KhdI~=Vt}pcy|!p67AN{ue*=b!<{HGL#^qhIg=>_ znSY($tlL`rHao%x#6a`i?w;}qcK%$b?C*Yt10N+QN;8>)nwQKMTGJZ9Goi5!Z$NqIq8!V9C+(NrI zUkv{xB5*Igs?W_rm!CGbwcQgqb4P#w?vQD`Is30di$<`li3vGi`tMvfD7ipC&pe1{ zul+UoCKHx6>#N*+xKMn=%$rLH#TF@FAg!MnWW#Z|`q`)%t>TB5m;K_nP#gZo6AfUe zqFad)T_hiECXfl)k8I{uiI!MYqM0E^#dnsD`Dq`zw%H{dA|Pn>8c$K6t)-SyENyiD zYj#l918V?@nM^KTH0?!DSG#K8iOo8hroP3#ewgBD`SY$Qo*j0ymG)sK7WA?uahT`? zJ%jf4W-V^}pE}1rtN>k?3=Fq&`i||tU^=1A$QmAkty(;F=NqW{9wAGj=j8o775yA7 zYJFXw$%8#-rDJ{)p9`D6=t0#>JQi2hsLgnTZM@0b}m zIXU`Fal=EqaSwBYZ#049L9R9dc^Zi&BOkvO^eTYD0MY~reh&fKRI3@PJb?!bESJJi z0!F~?N`_RV+q+iC}b7o9rd4Ee=shU-%gE`D>L-9}29ag4l zG$8G(S})>C&i)}$MFi{6jjeu>(TrxG_dIdi}cpJwlhl1Vx_GD z6o6kbF(E7_))RlnLDG}H9k%<2VM^h9j0LJ)TnHKyk>5c#W|^u-QzXXF8`q~z>Tc=h zk@=z*?aRsI&B~7$9SN0 zQ;ZB^nHEl-WuF|zay;uA=fXD|So1I0QS2!5x=p`bVYtvOd(Qb6LX4T)y}jraO^i-y z%tx^T4ZfJRMkERy7YPYUIVN&VFSuI+H79w<$zjl%uO% zwi+}@MIbF;J){R|efR;E{fKhPdZu)(Z(jwfn#>fcRK4+ht$tXgN5FXqz$sZ+TG9?m0D!6#1D`Zdj(7cUZxwMlqSMviQ%X2|KaRCN z#8?ND5ax7ny5Yq}%ktuzoJVa%<}?Z)-QKX<9QUPC2LM{beVfy2dsM`DyMGoVJ4$|# zi8r|}?yqWR=UhaEg}**{LR*`U^BVq8lGEIt_CcUE?w(u~4P5*T{rJfoS;bj))OUK( zc>7|#Jg?qM#1bYnf2w>|dH6b0 za(H_~)NGcUys=$Rv}IjAd#aI8&=eETeoRd)jvg`)?5)%nwPCdv7Wug(Bwb6 zJPekD_#7o1XO%)6SxfuLMwFJeZ;zUTAvb;Tqup_Il|>rjPa~f$=tMf%dJ3*S(^>jgrMTcbOXf3H%4MHJ4~l{I05*X0>Do%AhV0->|OZq>>mO5&{ujRYpfTVXncj zzNpFZBYDDW&d-H!EsR38H#nw>UZZ%M9cHtv1sNYWd)5wDo?BO9Y+2IKH2l%3zvYX` zup#$%(BmgKWH;?%IxB#&;kOYCuiDQer=0rX?NaISNfQ71rK7l`piWPiqqtjq^we6y z`(fe=yEMyQ)y~)b2!_XhCdLmiQ&0vEJl=@%khfX?YYF(2MY7|Pf0?+WI^c-zz%}le zW2-ri!+`Vm1?flRnU@lCQ-0{lugc5;tZOlq`^ShWUD(%W0DCp7fgk=s?XD4EG7-CP ze@f37i7?S)aIk^ri&K}_}dk;QcU&6 zl&Nk}>tJ?9e$Z@Mh=tPX6KTE%mF3xharl#guG_Wk)1hU7yUK&IpK1SQXE+@IT8Src z`4Ba2Ouw`twFb!U4{+2^5~&KKW`F(xE^k2o@bK`^toeZ&6&2;yrVr5e3N0WK#{jT! z?e(^S$K_bFYwzD702XVbG=qwh3d(tV$QjtX8pD5Hu>LYq4LCUfTex!Z=SlNKbN1oh zUN~TsI5@DVUN}DH962Gh(~~Ak+8MOiLAmd*kzA-ONpfAQ3vSc#K+>RrXel7PziCj6 z6#W7(RR#Bd-1OyP*W1f`+r=3wWb-;N%5nGGWFP$sv)U0ZRxF*Oud8_m7=Sc zL4l7PfHl0}UDNo5Kf0G6u$?d4-(yH(k9S4E7|C7BwcrmMT1ZxB?8h=Y)0<1$f83-N zhY6>H%gOn;%#P-lrB9$NezJU-cT$69uC*_xvMP@eFrJ?tj%E&QGYJjA^@7;}<~!@X z(;jRj7pJ6_9=UF#OvFOJPD1c%Re!Z?V+K8!w2>4X8g<~l4)1r3*}fDVS=SZ1seXY- z&keDk+4tW|j?>zKX6uO1GEn(J99Kbn{WoEZG&&(0WR=0{KGwJC80TG>yaoDnUjzcx z$C+;?s)=w|Wmujz?IIh-i-o|&R;eKh+=f$=pAF?D!EAUEj}Dl6 z)kR?2+J)|W-*XuG7KZ*hlUL&7%VX)*2JdB9 zVF~SGiP*n6yp=ZiS4x*GPdl`L{>GB;P%xBo#b?S{8YRl{Vu8zIvG&)kKnC;6oU4}K z1e{F^7bXcIInNgcw{d4mYNqJ;D#BJaJUlb2w~7GR@oFNpEWGtnrq-S`x~+WHh4hoe zOxpWG`HV*3u%uaMsit zJ3FBO3ZE)%-7y|4m<}&ThFLHP5cKG3xk8(4&pe118^UL@#yBKt8AfR6p#BRoe1X`Q zt33;dMxj1;pS@7&oG$l(-Uf0eTsPU($pm7Q==QX&o0}GAj@XpzC@}H3-IQi7L%m8U zy8m_Mjejt$cP&MM*%C?v-63#ExC+~ z!5KA!%}k&^aNPOa3X=pghN?<8Og745?E4ks5=|`ut5&-V`J37DrmIfTKMr12o|GHy zZyo2Cj@c*QP;GMs{V)u1_tldbxx_Nej5gy%Oq5gQ%;D`<@>q2!YfU$;UA|a|TWa4p zn#P3Jg`xPVXvb3D)OU}5)Z5xRFbb%?UVJFJ{c7OQf?O!0JojLgmqA@UR|NYt@T>fR z`@c9hv*4OEkHLX=bPhn9Ozf)ykoDd7m%65SYLajV7^z}qP>~9)>~EouV$;mbNGdcOX^@$% zS#!CCG=nE<6Bq0+3cIz|S$O>d7x4Fm^ao%7S82?;|u<(~2KIL;(v6+xl|5 z^r73oDL&hBX510DRRfDA1_lP}a+3AeyN=Kvrq*usjz^;C4)?IQh?o2X8r_lZF}y})^~7$iPvBh;cET`i z(cW=YSd)5g`ga9?8$Do;-;DfC#nBP0U4afjv2rQ%+2PY+*l1>0fHvs<$q%=95q)l# zL)1ViI6r{&nk&FskEF8aK=lsCgHoPuWP^U>iX1H$xnH z^D}=->a4&)6SAvH`k@3UZEU1|+14r#F5)k* z9b#vo7kv_+)&vc>^YbaG@nj`THLgX?KC}2%xMJS9U1`4|k)=_P)PxR$-(oXOGdRZV zYe*GQCU&1BkU_^#8OujZrat0VEDYCwP%tT%=gEf6)7ar=#%~VBH8Hl1NUW7ic!!ao zFdF`uC00@(jhJyCux2|PWYjk?@7Vba|M+hMbF7h~+7SYs`sSWIf^VlgG_RUoRm={0 zEV{q-k8ndp&B>j{yR8KGjc0=~8ty_CW{LC3w{to6wX#E?oylMNyG(>Vx1L`jY)JvA z#E>a6HI68vho|QPu+-$>E$RCd(RUAVZSVP~x|7H?#va=&TnHlOwm^P8Rbxg~>*{(q3+n)NstBvq;}}!O?S(x>vT#r}cS6@rO7tB^)@V=u zZY3h%wC+4A*UQ*A-{^UVu>mkpz#*qBBbtlxo@bvMr-?^LLjw#Qc#H<^qkwiPeTSkq zr`6_h6JN*g0Fw!9yOWc@)Y~k<|2<;TU}P2)gaCJT0M3Piiux&L02BjaQGlkQoDOG4 zh`zp<4Igo;<2+x_B4~0Q_weA|t%Vt;u?5lXJ4n&EZx!$HJa?Dg2SP7u+)T_)_W`50 zxxtK>iYHx{RH`sV(A?R;(cQ*{$AnXsGhh8>%~HcUFC$h@o*YUH^Sok4mjqlqFWNh=*RXP1`K z%L!zUX_q}Df(e_dg9x|mxmggO=ElAq+w8z)DU5}G(uU|FiJi*s{(Q<*4;WW1fG;;n z>Pi|}o(i7QF-PitP}(P8Dx+f*qfOdO17&wr(*xsWT*dG*WNMmkM=5_`A+3?jfn%i%2Pa#`MKP)xvy#KQ) zmv0!C8D#K5Ug^AKf+m`-8Ix*?F~K6`N`-Up4;nQUJ)<0tE^s(9)7#Vv-x=206Qy*x zQv-<2I*gNveM50@LfjnDjBunC3Z8>Kk6(mbD}JumXEXEh29{Y|=FaFKuC^lPD!3Lyk%fnyePSFN8UoCsuScvV@jWK1&h^se)~b+eUA)lT3Rhc9Tq4m z4F5I{&~pI*R6$FNr?gTZ0df!wzVC$kTW35tiZMb6I3lK<5)+ zgEV96O~*zDf~~mgqo^Dp$OV1mSI+LkJaAxYlMd}dWf{b(E_5H27pHBrK23$}pTFqU z@<(`J_dKcGQIfo|FN-6C999r6ffxMFRDuf>Ic>3hRlv|li1cG2{Ukfem?UbKL)m1v z3AY9?%W(+_>4^y1pHMa$(5?>9m-``gV@}_8Ar*=7Ys6ODQj2B9bI)<3GxmkOgd(GQ z&u&x&6u+e-Kc*x~!YW2_EroW|V4mXU;Gh2P{IJ9ACA7QYim650WH4^&!??vTO3R7j zLt_svyD$jpiZRBOxfqVP4)m>J#v}tQVyn=4RRi(<0j|p*>yo*9Qx@e5z`|J z+^+s%XA5~{C*Vj*|0qi*n{G1q_4MQec(S0Q+47MoWBLI}p+}|m>jEbG%WY{Or2IY- zMMo!>X^gONad1>w&Xkz(^;-_Qe!RZDt+rhg1OWZO<*nQ76izM~&CJa$#ZO$p!`A6c zIjQ-p2rYBFKy0tcallgWdGIG^g#}Y3R-g}h%xYV($sWA4#$*9GSMogD4vxCZr{Y>! zi7&0o=ksW-_96u*6*O1}+F-D}sIYB<19R(i#Uckp4EUu1BW59Bss|W@jN>fyajCKS znu|_-lW-?m8M(FseRukvS*F#kBIdW~=XpyR4{jBqm1#dzvMcTl7khX{zLkm-2si6O z@HLeU8Pz&}Z-S((*#&3Ux|MZrrzY;N>RGZ8)pGGvVTG`zFEtXR^(zA$C%p!C%C1?z zww4uR>=5?{77zsQz$#Y{q;=@6M+G5!_3tw}Z6ELwoZzDKC0zY%(V}wi&0f!V{W(}y z?@XwWZj=q-yb{rR^lDXqP6m;mx#1%_6GG*0!@5k`Kk^Sl+rh#u@0w_>_=LcZ2}b?M z=}+Em(krr-rl;c}sN>-=a&)5@2}jCkrwL8niLc(aF7}~x*ny?dh_7ZvkppqNQT7`U z`z8AgrBeyLWAxgcQI}f^fsK#vgVX+7La9eC z3f+jw4w+%Fdz08fG)Fez0|7bX=j)X)A#XGuHC}hNR${^t#%JO_DQQdk;ex%jKYQ7F z-_%|8XUfnHnl;1OhpPSqHuX}`a`EAmGRm)xxXt~rEpwOm?GH=U48a!%6yrp^ zIYzwl>$a{Q_74yL08AP0r&|`lYz8=Rczm9@0UK+L4N|GNj8tJwtKB)hZC2xGo9FDs zhU?i6`MJ#Ix0i13uBEw)aUW|EK}E)rl5BL$E?>L|j1=C&zwMu8q=p(x6ZEAKpbi}f>;z;{ z4sj{AFNM}Pph-}u-AT1m-EqW5&464s2qhGKl{o3ZI=jVGM!ZZ%}bmUwfHLNAg; ztU9l`$AWxabBbV3X3u)Fak=Okt#gHnL{3=a z{xZY+W#)c0%TB>lZfKV?^aTCo9}o~&Oemo=_u|_ zk9YC_{ETh8bE=$@DSej0)s!rg{llf%yNCxk2Ax*SU|U}wkFE+|CDom$noVAg&qSy9 zTfOOAcxA7>e2XtK>s9}~EQeu&wO3F)HF{o3rdcr+cqNW@?iKg;`8LP9!*n<5KI4?r7C+Yn6k%fq7|rk}hoH;8(PyAKSvA?`_qmgJosm2vWt}#jPDnw1lNsJ_u@{nv5}5rE(1^THYH!6b zMamno%h)s`O6l@MA7nGWK&VV6A6O-~bJX^UV64hMSbaiz-O7VNXbYum)L-9Bu);N# z#oO@&HMrBn?BTC~?#yjW3szZ;u`aWi<5sH8RqblG#V5lnOc|2P;ywmba&Ee3uMzXD ziYR>r&+dXaUsB<2-)cq-(z7-xVWhVeI9)bu>=;H(>{%`B*`^A~6~kmYys(zcv|1j{ zpBMeHeG7lb47*8_)i(Vh{9GMdCC)(p{#wz@?Lai~?dH;qOfWF2+~>B!a=mJ7Y7KXD6G^BXk6f0^TH|$kg4Xv%s&E@FYz>z=7IdX>=pCo{_Q5Z9aNP8HKh`B z%+&+Qd%16tunsyn4rjFU^X*;`zi_xnxgIwd77XzYOz{?Of4(eJUaO=iU3YSkbWU*h z8ey)HJPx@e1Vg~}1BiH%moBdGtGP)U1hGcYu@)o0@}D+`&5j-~8tT)sNIB zV>8!`ei#AKg-&lG6{%O@t7yj}WXDNCl&N0yIpec{Ag<03R*WiDx z&cJkFa(B8?rr(xs$L%#!@si2B7xQ)>10)mQuUbI-0omEbs?v&6C5TMdY8kZy7IsNV z1i&k5d~-O%&d#ojb7#eI|KjsrDgks<08{YRNyFMM@cdzIUAF11k48f&w#D*##|5}& z(x3$|$X%=38T)pv4Z*B)TKrj0|onZHIR(!!!>!?s;@u3}p;~@w0)O^Dl zEYhd{Ofo`FczwAM+HmD~){zkFd&-l1)h7k#%S}wm;3U_;NvfJ^QSHp}SeqP?Iu}q_ zuF1FHveHLR#QH#cE{cJZ6!;&(3dI<>FLfgW;JH227X_}RSUsSY+M1!=(y~N#r9`>d zUFy6Y9FNOYOR8(^V#IL@?M7Y-d84}9Bqrgmmq*O3f(K+cN2=^2xI*cpBej6D9yuppg^ldg1wHu%Jp!Y`RSLqR z1#0?oU7`P-wZ+Dy{8*VqbGxVA8Y?1n7Q=emg^E=&f%k6i0SvLqUe4RSAn=A4p-4iW zJo>o|ILRc**l+eC0Vg9#9UTII&T0x=TR_>9F5AsEkW$MS8oJ~#5uGz%X(u)?d8oH& zp3C1m)pH~0iEMXNzqtYj(ZvnXUv~d@9YqQx%)VTbd1TnnHjvFVlqma$8Qiqrrqhni zCdmZJ%&GqH-zvG)$YW__&9!_&DB4x6)C;dA`jY+=PY|65u*9yF9geldeQmotAzhyC zpXf@+&r2f7ccJa+1EI4{c|;3a!Ty+tIk@}dDaRfY{$pR}Tn^}G=CpE@9q5CYRwY;f zlXseVaC&DH>gvklyleLDlyjU6wf5! znpm{PFH4rCH9T58ji4IThR7XBhMTpp!QU-|hFg!1`%Eox^mm&g zG}}Is#>Q(Y8SCNfr-#h_yYQ6nhGt?wgJ_%f{i8&LF$7@UkmVK8eGYPg>}>a za;x_lv!D_4yNwY+!C=2ssCwkET_Z=n5*8xuJ+7a)%G6H>8Om#r3*B{j^Lq{O0)BrC z$DAo<`Z+qEfB0*S~gtR&3rIXgV_c$xS}a@^c^)v5t5y z+Y5rq(jsE>`m@)rf9}S9*;q4Uvhz&pzr5*J@nG88S|zS>+mH#_+Tu(x=A_YqI2X_a z(osr}Y$*TRxKvHA=wK6-?KG7Hg;Ceno@WCJwGDc*8YS2f+Z<(uy_jPpsu)K>^hH0x z;PG5=)`ja5WZ<6ARfYR=GGAT>DC*f5PNG9WL3wBLP5|9gz^E}_X#@*2%fSU|?0Esc zet_yhTZn+Llwq;j>apr=UMTVejtXkl#uIeF$)`pHRHT$`Q%*=pL^>9_b9$A!h$36f#9s2B;Pr(hjxX)Z zDBb2Ld00gpOksjjIhy-MQ6xs)@`4M;7AdEktH#PARwItO8T;@n-1KO{Q0RI1%!6%l9>IO9NalLzn%ald0? z$Hln!#pl@7Do{;rLILg?zvDT*Bm{Mmi@oVt!dI{`_s>mn*{{bG0)$NqZXU#j@{lMZ z=Fh=&N_DNeAARUiE3$+6=0v7HT8{1GTc3QRs-fK~K~a{8CJ};|#0Z3}`JN2Jw<#BV z9pOKlYL)PfUVa>JRmBMY3=`nP1VD?U72Dp>)ScN!@yU1qiu&((%4GbP6e&@BH}%?b zaAzW#fsR1`&$H(&;xA-n8X)>+Oa&eIP-Xq-A94^Kc&uoJDYZ48GO?B)HDjQf9+Rqh zi#OYOoCk&atiOQW#WghXIj$;_$(lH*YxrUIG0fI|P=Y4d`Iv27ZkndYEu z-|2DDGE^_jrX2QDldh~)a85&Y6as~v_A5Ou#;kifL;1+X94VIU@=~jnhGN$&Gf%SX#a3>ogdfGof z)oH2$emX&E% zsg`xNz$$8}%wnYCcKmWxNy2nSq*;OpAKo$9iDy<-SfAY@{5&PWpa=_&7^ttJ_(#iHIURLHord+SYe_X^v9%fOy@ z{;>BxjICR;oYZBox7uqhX*2TtDsqw^R0+EekFL{GR#4A~!W$pM)6-g3heMx|4tZl~ zP9A{%PS@m+h?iCNgRU=Bnf%#cR=mC?e9D>ce=p;oztU8|SDi#eR2_}fgPOxT-HBtl zMiH=qTEM6kNugKB_EX$QWF#)Kw>WZR?~~wKZo8f5naK8=$IkI(qk?ZS{i~g~ z9hb9 zphNbeJmT_rd2E!0m`Nb|gOOnL6M&e5jyg@A?@~G^zF0ec)NAXD`hTz(%5AW*QlN*H zGm_1xiX8pQl?)?XU?Usn+IFO8Jzu%ejMZ4CLJW*MR#scNp~S{O31})^HSQl(5sJcq`7-45kXeob^-C^n`523sVlGx-sd>D9 z#16SxK9IeL3Qy!MUO98okiQL6Wa6mYrfvsf2mlCZk?Oi#eB42bMLmheIuSK$KM(mQn(5cwsxSjr5Z z;i_qrb-cq9nVAFTn?A%?RF~BFKi!rYEj7EaHusM(Iw6Omc8h*xW_RZGzz1;}7+;e> zIk>`X{h5CyebSR-7@4shiWQJ8czZk-|ua`W`GvbWrCj zk6e9&b}ZhdjzWA}SQ;eJE_JUE=x18caGTF=WeglP;8+az^!m{Jx!d_ZQK0efi}yeL zU01dvycustT=0;11)W;F3>&x-}_2>OQl>xCYafB_IoZPW!v>@8XVx_ z2XL9WT*?ED@RCqAK2e+B_r33)2m)=MQN?;#f~ zE-u0MLv2~ly{l**1cwrb)mZ1EvfG6+&MXn=W33!@5g={apkSHX^v-?mLba&VBvgdmrY3?`IC@?6db;zXen(-r~1}wL+{wTj=HKzQKNh^PdeWKj_t` zcY~mzMCxf;IaXy5Qs;F(&|oBSc!1Ys2uGLV()GLw{11%FF%Efv_h7AtqrmhkUcqU1|}67nAr9dPXfQC?=gzNAAgv)7u)#1x_P zWy`5&ATr8!qKC65FpP~&ptE(LN($C;%5%ENmkq6mAPbYyevJ~Sh^J3_dU}w=1rpw; zK#PtyWU!teJxw{6tM+7(uMIvaRZJhHALc$K@{NGN#L$Gce6H-g-x4Ni7>Q5^H*#lk z+`diaE|V??kBcyy5U7}6{IA>!hJaVs4n=6-Y32tU&76nXxSHI(gi9tu76)ClhURp!nAlAZ{E^L>_N3d_yY+c&QSp1|?dYpY$Q zIp8CFr+nhghZauflV@ZL&G*wJhD{WetcE6p9s9)|S+U9BtbEQNqklx`Sv%8ZV62^e zJ_`xR6nG%=gY@HaniSOsQ@39Z5wa=}ba=z1cp5{FwviKT8J87=QY12lHEGgXZdiCQ!t>sD2muTcvq{NFQjYVOFM^iyi%lEV~?k zKBK)zWwTEi=Mu21y;ZaO0u9LE+y%n{g8R%o_BWc{k|vtq3VXIQZ?*%3OeJf`4loBj zW~%vPcz%BC`!8`cLGqEAgQH1Z^si9?@K^=jrjh{bpifg>VgTsA*Nvd??jcfLO45>mf60`IBIITLDBKtNya=K1a`F5lSD`A55lTGJ0} zN>@>gTYbbooHS4G0C95cV-oF`dP~CfL(OwCzJpc)gnLkk*JIiY_2CzaH8!#rFC&i* zqCwWmodaM80|Fo5+H3um5IbNF3~YG-Wy9tsH89x%u8|ZK#`mQfX)8WTC`4TScVpT? z>8?KxDvL*e)V7^MyJSQu2bMqiCh3RWvW34my&jw#kb0z4kRDnrs#~Wycno;Z!>p#N z_1$wg90vwIcw%MG$H-lh7Z*7e=XWjxnT>R6aT zA65f7pI^-Tqto{NbUB3Jmut*!71-V&j84AQ**`V8l^bGr4ro(Ij9Pxm!u6y91OCl| z6mGZ6S7S_FV9P`So`8E>35`>j6T&_&Fjx~WhCSA`^$G) zyg%Nkev(Q!-RSvsUv1+mI`HuN9y5<}_i*Xc_^mp&vh`BKo|)9i57uEwGfB z2`0D0A@_LVDAe|BYH9Bo0oq8Q#SXB&$8=JF0ljyk20&!Du|FzJ1!`ZsIQf6)EhZ+f zpx_`7Xb)(9|BGO3hzOiBz$hQ@wZIymv8J8aEO-bK$TX<9#2UqW@xr;u6l{6YRl~9= zC8_s#J^fH3iuN#}Y&>)z>MxGJhnFP$tAp^<8V8SWvIaL#_9jv&XZOjHl3+K+ChZap z-m}Rac{d~H6{sq1;&83wyU=zfW!mk>UF5I!qEObK@N5;ARmxFeTzCaSqAn^8zc0%y z@mZrzIdF%zI7+?rN}fo2UJSXQ)~{L0>KGZMV`AmGlfZyyTx?EY?P{4oaXOzCf{}sIG=b#ZE9(N0Cv! zAv)CGQVpDGUu*0d?4ITxr$>gbtA*h*8uzY*HhfZu5^l8lUxBPMzq^yItw^e_8iU6< zeG>G3GoT3lm#cmraP9}xe!eE4U~krbqON;FGT-c_`sP@xRIVF=7E9}--)Yh$X*KX~ zLd$aQrar#_>xu}kA*ZC3xQF)yESV|ku6JJc;c=Z#f;Yk2KY z=l6+ZZF_LlIcsyLe)bi4&J%Ej+%Mx*>|MniNh3CL2l;X_W32W;HNo#S?((1@|) zLk*E`sLQ7-j%v`-KsXyML-Ww?wGPs~Wr^+qUlmP8o>^wYwd2G^AGfdDMk1>{CSPRE@b;x+qek0C)$@fU+7^r%rf z%?_9Pf*@DjTbA;H-CUToYsGY;g*5-ua4+xu>IN(OSHR{zSE=0r7y~~6GayC;IQgdw$TESFb}=8|Ni&9 zjvn2ZpczZ04@~pB2cLHWa`6~&;&<}Sb0df-=ryNX*ON$NB$~E?EshZ(qG(G9L4M=S z;IHMWZ=JTG-I=c1grhhw8OZ!B4`4;Bfbe4qmaQiqQxj$Ka2oocd7iq$%Y;;JoKW}l zSiLsEWH|7z)%WXZS-WyoNzmQ39;`7z=aaUlC6D)h9nW7nBZB^rSN~*+(iseJ;wlk? zKKY`(eN_|f+9wpdqj5bJK#@v`(hETY~Gx~VQC9>h7e4pPHaxrQ-gJBL;CptO4 z`B@9Nz1k&y+axeOTpi&bl%L=#1n(%-s8~Vz54bMJEG(Y4B_y8zbUBjx-)f3+mBE7I zgg~Fi=BPKnU{ovNI}0;98%3GbtebF`H=Cqq9egcAA(fV-eMfcdmwm9F&J6obH(AjN z*plK|G^EOW;v_cW*_Ph4<67clmh7sm7D+0Gi}6Zw3QE&_DO-B9q1yh}Fw<$@2Fou5 zDARp7?6?_2OmtTtlqR)|(LN7wf+_ zGMuNgwE7u|IJqmsn0xLRtp`uPN#c{jo){vP zBhrAXFkw1%X`TjWweR|3%5gFnlbZSNpK(J5n+XFSH(rz_pCWJ) zB8{*ONq7Y`Vw_U~{M4`geZ){OR$li6GIGf&G~%Th3E{Az3pzB`)x&dI5ogOLCZrU# ztk^Nd!!6mRO#GH{#KOtoZ*t6@m2s?bbvbKgFkFdSC0A@v-A5FQ8Q~7iH3>a-1>^0K zRAo_l$){ftq$3%Jj^{{;wKWqt+cY8-U%JbY%@JKR_#QK!`JDe+x?cRGgPPIS%f$J^C{60OA{$P<>D-gO=KEgj}xml)RiCd3Hn$WZw0n=C>7%t zFa3?m=h<8E`}n>N1U-G;4tn75T>F(^$vz&l0WtA`mF(en7tIM#8JwZ#Bh=tjU0~EL zKj-m4mnm-o>H>?zYWroqg|**<+SP#N1o?5S7#$zn?-_lL{f;fZQ0KN6P0TVw`GIQF zRB-6heqp|%9-p_yY=kAh)%M4=@FCjzF79C2+>2Y<<@VJ^gN?Uw%tdm!2j?;;170>* z|JnV+Ul?u%gm6vTZM>P;xu05Yx4HWVKAjcZkG01R6Ka=PCv^)4qav? zg9mZ(09k9&^%@nrr|AWw_1;PEVBrk?Qr!yy^7jZI>dXtSPPqNBF>^?Y%H@b5)A z6JY$j9BO}9>4nbx+sh5j-iXbYtWe;4y);vD$PW%8Pq@^uU?M8Kd42*C*r?j?HPER5 zGDz>22K3kgrRLE=TqEBt4xP1@3^Nb3F) z74)@@i}zyo^6E>w(yQU0ziPJ}ph+B$aCow3N5AepYMZupxR*C2QYp2=D%jG6N2C&l zLYH?5fr$%U_pj4lx7FP*xCimwyr*R?xBQpC&b#93EYpd&&@Wv#kZqoZqDrsn8+;sW zwp&;{%H9Nq>MIw7gtT|nn|lp7*}*bS(9a{ z!r6o0i+_QrnTmEM4>Qw{Vs<8({OQBw`{8B|pxPj&t!v$AXa%a1E8?;BGknJ!=|0yV z4B@?xOe@<+#o=y!6Y_1b`YaKM6mj-_l9%K#Zr?ZxFM0!L*1IHnTE?v(Oee~`eHwY` zfDzgI9RJ5DNlHK`eBSMecJJV%k2a(UY7}Z?fT8plszqrpo+Jp5Wg%AS@s{5fZW4iA zeekA<+M2s}QFTJ|TKyRXed;8tY#tnmXAp+=mmi6?rj(6I*qdKfqtMu{&Z?fQrb)Mi zppdh)32RB!6%LHRdGEHlk&B7Z#4-YIu*chf$RKx5HN3c+3z%l7jd4H=<$ckMR5fl| zp^`tPSLuoL7GnzP`q>38l`rpSX=R1OFUN_H*dS+R`t{c@1v^~%uVW*gHd!6V52v5M zzYhMKcxg$^Y_`7`;;rc|7;cx>C18pwJO1&@8V~TRudP10oqsDD@c1km-=9DQ;S7RG zy)y0dSHlp=Qk%*C-{NPkH-SeNQp-D#0rU1iA}Se0 zQv67^`e|y(98I3mw*_a{?~h2KZj;A)=*w0$BMopi5&Tb-S+(NM-*%&MHyLoY6LY&| z`enD+44zU2qb2!<3{Q%DoLWectYY(Yk}c%>Wl_TDq8{MI&6+N8s%mSVa`22ffRGJS zk$eI{_3UTV^G?BGvSxrrOf=(vw}hXO>?y~Ryr-D|H|Bbsi*l!Xy)7wWbw0+_a3`rI zkt(~!@l#xy^jj}OM8~&@Bk#rue@`b0(%9%EflYqmnLQ4KRkC*6uLpE^TPGf<-|DJP z{9&3gdY)>qj2N=pXu%kB`r`uCWqOTJq%qfy+EJ9>zKz*r*J0^tDG>gMD-VEIXJ-2U zN#xYGHY{{p+sKb@ZiZUzmeAuFmfE{O%L}QQGB@41U^N(hL9Xa%PB`;rwYSnAk>!tP ze0BwDyE7)B-365=*xQOirGcVIJ?36p&qKp2R0pg(Nr{Ju}% zxqwR849SI)E}pm@qHrbRWTks!Wk^V%HxesD6`8u@Z z+GMMO1#((xWLFj^p2;)aE|iecezIJe_zKlDQsnsEQ3E8Zdd^~wDE>=&+AmcmkXrHy z*q?8UBl>EMi1s~lo}YVnP`ca%l|LuD2xJRBtexlYFO33GD7OofojS^JVZmqVf9snm zW0Z!GXbRh~nHwnHje8Eb&6MTjWi=QL1@Ga{gNyYPL{=PxpJY!xwNS3NTBx?Ypnu-8UPX(*WoybQBee3M2l?tPqKxOIm!B93)&u{Hnr zuNqxDHaQ@HQa11cXxNtS7Z5O_mIU1;7ugeQH-H((^l^s`Q<2mTime#Rv*4}drkdI9 zaI`3@Y9%qp(&Ie^Pglp$QVhf5%Z(I*>t(AJa^Ha2W9iqBgLn^2gdN^D>BP$6Yct@- z{d7E*Kl8meY`X^4)*kx8IB%tCKA)aLQ4(H{y@svIgtQ1~AQb^*`WuuSB+xS|e4#Wi zoGkFyd%6d%W#sPcb2CL-+i87gjTQB2w1n53%0c5U`tG&n=Rqe4Y`8PzJxGoIJ|r1e z^W(#?8J_7WiFqUsSbtlQn7m*cefHo(&Bx!;7hVQLVpiE?d3pq2x{iDdqApr|)%S$M z3c=%bb6F-m7e6K9KW8uQ9bK0V9K=xuj*#RvMZ6|oxT#&bEmGEczm9%JO0Ur^gR+G@ zRrkvA3~pFrT@F2{W)fJz2rA4X=4>Y3r@Y~L z-2!EN@JF;mFrfFDJ3u5>+J9JGsj;%S-fkk-uLF`#I}oMrQDwEM^?p{dDU&hjuw+R$ zms$O~zb4!Tc^MxlqSO-;;iZv^tNdu7DA$NR>S;25ZYk)DQ-AF*xxvse4Z|0M&-FV* z-Wn$qy>nt(T-R#Qo1Y7Dr!Qd|=Yu>~Xh@y7;?o>{u29!<;k|W*Gop-7VYRnd{9n<@ z-=9_qRRk;ybrmbB5BZf=8g(C?Pafqw%a+t+n#xXtEyU1G zIyB1j`fpn(x5Fa?`@YFVka-kXqoWOat|AAq?=KIqUXNc=xsTq$#4A`^~vN zWA_rLoOF-p+O|5J#j{dz_&2(JkZe?6@10EvTFh%s^dKe2(1v>guF+lvbZ?bP_4;y) z-9;`((X<5=k0Rw|bhvpys`2d3-0#^>U#!@uMTn!kMV*Muj$ntMuUYKoSS}PXIMfKD z7sxw4CBE11U$suC(=N07J(!4DnW%Vl#>Akd_7!GBYXxH88A&r|N&>r}b;dn(SZP4I z>DrlMR*<(zQc@u;&RzArW1%|-%KhY%BGH4$q>PQEj666gOb6$03fj-{MZ!>vKd4vV z;9!^x(R9pE{=;1N5Cy?JpHIXJX@(0fBS{`$e|#9U^ERCJM_pgr4oqGPC% z`hyOlfPjhNakz%F2x5s{ixp$fR>1K?o@r~S)Z;VVKjx$7>0u_}Wf!ald`Z|Z1KXv# zBxf785z@&7XVfh0(20V+{Ia_yo)a4xg`M0M31faY+M>3@dHq(r9!@tH6dFLae}w=Q zFJs73xw`1b`iG%Q1piqbtm47ltgc;BaI?U;g{Gg9R-k=9MYPVltI=QR>sOdin}Ykv z5mO#?fm|CnM0U`&qjb0G4xe3QktVY6^W;$!hTahasyMBBtiEf+^>a^a9wmcr70TcJ z&cYDwxY@z-oI|MoxQuMk^M#VsAe-k|vmqTw-(8BN+HndzPw+Vc+muz`bCrv1AH3AA zsjDl0<9*~pAV&MXmDg~|g)Lpo9P-_CniN;|#nG$(7>pg8aB;0`@Lm-4QM~vb5mTXI zFyvp|S7$tSxtIUR_qHvg_lITkU&8Ly)Xg2R;IMW+7JT$L(+-FK=f!Vwb#^lj(huU& z$Gv2HrVSpDR<@1}#JVl= z80a$&^#u42Z4KH_DhT@Kx|2;1ed$=CPXck|hl4% zAx=?R`)}iIO}*OCdp$RIq1Kq9*VZ0adg-1xF+a#`qfvWkz z(|aRQ+R4?oJNuNRg6_qUp}JN&Z#~(2)5=Y0*B26U_x(N+gv*HeEv>E@U3=Q_K98Og znI53#sCN_N7Q4pGnb_H~R#v7?lkZ##$M1Nn!6cxn%!U91m%breheebBw zI}Us?PYk4<2CL>?Cx(7$_iMSGK6;`XGo)0Jcc&&(1)k=txgBM~UCJEmYPs;~-6q zCngI+!U@SMVbkZGiL2F;gcQ{|fSW{qd4275x})tkuT2WwL`9zvdX%cVJiiOk3OlC8 zdP1Oq4{4{y&HOr_;TFUns*Zk*_A-VpO4`mRR5B=iQBIfSqX1RaK0uThle&$qU(!?e=8~F(jkhuOYsdGy@bz!tT4^0h%m^Bh3R$di;WzDg3xNC&nTh; zc1UI!9v&h=0EN|3Afs5T)|)SzcuRPzMlux8U%9Za9Bxsy;l6Bnlo}yNj$&1|TKE&G zO?RWVlKCHLPn?aAdNO7`g@lFP*KULEdWzHgyQfID@2~ZfrK_0Xg)1U_WbJlM{CrOn z+NY-wJXog;RJ}2S<@(A|B^#xF45CxmA2c6Dwp&tqr zj@du8q}!pqb3=ZV|J1ShVZFI4T;2ar;CXK$;UaHH4Oe-*!`p*BXLghMXp0BYR9Nm? zRodW~M3|`I2O``{eVWBG@I{4WM10<0ba|O^EGq0T!RBi|uhW8Q$2!s`lGl_C{wHb0 z5t5rJw1dYp)zd}+gf?zs86_|<13x@JF9+P9?Owh=Xn^fAKxDcLj0DQMyQ!)o){mwV z3%okd5KX*RYL-1UVqev*IhSArOxk^yi%;}62B%Uo%AYwTMaPFW?mw>I`$5D1y*4Y8 zE)48!LDt9X#wp}5xTmYk@6atZu?0xqKDvK+qoM7LpXh^@)sT2Z&YLB}$SWL$&YLy> z)>oWy9gVZ*frMj2Xx|z5wJ-V|$B}p43jog{tZL)DLxDd7%~qGICF&RI1&`OgcBj3Y*~Ph^`I&QgU9nAQBKG&n6+4?6 z3<47>@P#VqE7pzB^$(J_P3)NiTG6C48_UnNt~WZ2n)1 z=T)nl!h#P9d|NewAs|)aBep`YiSmT|^SUJ@NS-?>Rwzxv*f0;}yu^OUopA zp0T>c_#l*=j(X;NaV>s>yVU|}-30_l{&a{0L@zQ}62HYZ9@MlvJf7t#Z-<&e02Lh^ ziX}Nb5JSW>wnUdAjXduqc-i38nv`=7`oZy3PPhkMs)yZowu?sySoLsb8=AmK7d1`g zb3Z~2dY#(XKcW)v^9#DBb69sf?P&OP)(Vx3f8NBoT0$ABNCPMNmtqw$69-bge!%Xx z*~EI26i;6;nxsY#wsBi5i_#|EQE9r9M%FU!CqkZFT<Arny`9r8{nMVpzql z_W2VJy57c{xB&h`vu&sXW8G;*?DK+>f{R>MYCN8wjs1>5F)GGp%9RVRL_%DQj$zI# zNTkuf_)%;NtC9<8Y>``YzOO#^E!ZHz`*d{&CT@^8>^hm#Tz#(*-b6<#prs#bAeF}X zN=g9}kH46$#75XXCpuWm&oG(p?ZXmXabwjDs@^H!imU9G@=UmBmd&1sSAZm)(p8h- z9e6!>qn5Ikh8B^J4j$;qQpCh9A>>$N@A`H7pwPi4FvsN*z}`c0I%==rf7;Tc_IT>q zl>4~(CMIMOEs73lJy`=@inaqt!JRO4VlD*lP)lHh)svyrZVkPCJV}=rD6SgUi zhfZ&V9OmuE))kUc<^A%LmVD$*<2xAWnY-3FeELApcMc<5N#Dvt8e~Q*hv6e#QNH4@ z(ktEJS$)#nb6~C7rde9rWU3>RhmsCdNaT)P;7$@T*ne+f4S(|CxW#nT@UD?-W|%Nb z5k}Cfmc>dnVOeo^^=euc({kPVqz~IPXdB-&;DjH(&iy@Kp-xzFp)ITLWC9MxmQ(B| z@QI0-l!4VM=%VF)bJFpiF%Jk;!uus0yd)J7Ys0#7uJsPNwX8hNH0bG*pvPEEaks-D zlpgnpoa*I7s7>$ix$s!DHt@Ep4G`mXY6J^J><9z8>&r9)K|v7}cR|SbHui0<&to{Ct@~xuq~sP%z(0AU!!f*K2$ph~@+txSwwDn8}?8 zha3ub-z|GxTqW5Y2=?fI0J#1aEw}FVb_=rK zioEf(z2N;Y>}HuW+LvO4PVtrxdGo{z zkLgT%(1G0X!cv`7Ej0RtC)K`@ZBe-Bj?@_+TKfz4!6ALkPxPOX(&1Q)-wjd=V(9TJ z#dv0w$BE}ne_H`h%f)kMmFs5rvk)p%6M16j6NZgPZb-idrL z2d+&C1M2Y#(GOM6!C7Ia&jcczxM0eH_c87KLr?w}*>!@Qn8oeJ9aI~Y9vqX zbkCy`XI5^b+GUBgtTmTZ)$hK6Eym0Zlam@OVh2F38e1dY*+Bt+*`ar{`iKWx$jmgW z(JDn1%#|UOHzi2$kem_-Dkhu+x$K;PmQ0oXNV+>Y`OIJ)=!XL)Um63Eaxx_)6CW;J z0eEw_T8ZGCzt=Wk7P-{J9wFDn3^OA4>mUI58_WCiyF z_FF0dE4dt|OSssM;YwDTvxY&1<%s)q7BnV#)@6m%+xE>%47dJaIpOp(SI$AIb5~HV zdeA8oxs;Ib&Vd$w_V212oz=M-f2SwY9v<|Sx&Rs~wKwa=WxlUUzEZRF zlQ3K>P57Cw>Q^1i!7UX|;=qaLH_p%T=-O>+yiokX_GZ2vO_d%jmeDg3`hb^V_FkDG0 zj4LO~%xz%}6O4}1on`j$jkP0J$ z&yEleWO@={O0s;+DD3VGXHMg^WgnB&rN~BIxcMQn2Xz%k>cMrT`E-5f6zl5HdPV!4 zH3W zv@|=zdrz@I`od*%HA(1v)Gmy_!)NLjOEiwIa)ioFBKHyKA=K~m1fKbA{1WzFI29mU zhbQ86xmvQw^}i!7&-Y8(8hweyiUY74+-@T5Gt&Psv5xw0x!-E~kr|Wu9j!HIVJtY7 z_+2CV)-I`hr!mmPfLa32#y+-kk-J446aQ!Ap};Hr{tP5VrsM`xQ8jsFTP(8G?v_xj zjpfni`OT9qeYu`8&X&0gRvB7vM*EAmeG{Q}Qe1oP@*H1gXG!=p-G_>eJr=3B+n93q z)}6CCbhG+`jJY|4Jy53eHGh}Ho)I28m=H8Q#)Kch=$UstD@7!T3#*O%cwY7+^%uYB zdNJB)5Dw_fAeRZPmcY*Jo=h4d?WtdjaRaEI&WLHmhyf(w=Us~vx>RBVM_+`Ga@!6C ztC+uzd^NA8u9+#kY3YNpd7iHkd&lKpSRY_K09nlnYE8l)Lul+ zY}VRcceN~0B9(9)Wd_YdE^Hn8(@KE!vQ64={_E3pS@kOZ4ngk+bWU{kduDMRTv+(# z8n@F_f!KdvM1Ava-Uj&|(t#U+J%$`|;6aV*^ZHs&2FSrf23clpS$k5pk~uCR&MrVlpM@ZJG%!kv6FHaw*@WD|Ha zwG>X@2M$1sd=a0vR21qkK)>&LvH1>@N>atbVkbEsT+$UA7kBxGZ^HTJ@FT#SsXJXR zPL8Ol^Rs8F{RJWtIyqt3Gz>Nw@-K#d@IrzK-cbyE?(^w->?aZquydbx2%bI*fBR9p z4+H1lBg4f^%JBZw5_qdL-n!#{{tB>FJHCsOg7tD2FPJkXau06M09wc)TCT_)uS`Zw zVl>mwtNoC?f@o}adGxcjsXnf?j`)DJq&6FA#}oHs9|`dh9u8q26kd~?jgnw&$F(5k z{_GZY;85bdXu=~2y!6}IWr~7bZEK2h>Tr@O+S4kpK-vnqDCioIiX7Tb2KQIQoS6q; z3TwEU^A8D`P#*ZzqPsOZ#mWxS3gs-{qbeZ38?JR*o9A5jK5jZ$n&mn83dtph8Qm3$ zDy@IMZHd3QaI;}cohFbg0_1`@j_pzKNSNMMuvM`@AWOdg)%$n~F+hx`H-;0Ws@ZBC zKvvrwfYoxc@->JiLh6qc@C77)_U|NCwuId6)Ly*Ml@k*yZ~xKW)oQg;j+p4VctREu z#J2nVt*s<({tVNgeKlx|0>t0QzlDZ~BG-Q?Nfj~imT#5Rw_rnoGe-vbonRVc4xmk= zU=kD`flPAij^FYC5Uf#~aUesW&lXDErb5V|`KfHI3GHOVvm}WN}t@_HL$ahl&CjHCI4xyL7Rc4*T9$W>T z`Nd)+R(*vJK@4nVw4bX$Sh^oQB^!xC-vA9Usp+J3eR}_%UVQoEwz#)%t_|nF5!nRp zs9t6>Ul43BLm$YndIlfG`Fh;Mai!r4sI%JkxpYwmBM3<|G(zVMOX&O$Ab z{!gAM;t%;}&yy(#WzHU&-V(;V^v<0D0v1jhCV*%-1<|~krMFu6z3q4MXCnR_wQW9P zQ=~T>pUu0bptLc&Ffc7zha-w1PLg-LQogU^{dKds6tHv5=?nxjkGCP7QI3bqmC=sG zw(SwcmEW@?vb?l=8Y=kXK`En_F62m~jjQ#HgylcpBO}|g`nC6U_^6XPt*rD8T0{Gm zsqY)xn>r{d_c94{TMtFyCBzFSmF)6X^8WO@!LTENJ9gu1(J!xT_h=cmH6QM{jE1Un zNHc8AZVRiYRH64_P;qP8q==ae8&H6du4{UKsb2gH9f=90%H`q%v5f*>E+sfo5X9?) z1inhez`sR6S7q2;I08AD`8lx(o#_pwpD{`Yn!Zo4?&>$>zzn7Z9JE*W8vzj|;-^tdSORi2@S$hPqjtuLE8>+T1X z%Q?s2{Te0@rPwRs3%~9t*2DsIq9jdm&l9+eh#kG=PFyu`I~@Wv6VPL63HVWIY8S6}rVkI2}x4@X`YRG-K#;M|{%weqkHrRCG1O7Yu!+s~*Mp-z1 zIk+EAPL=_F@M|16*(LA%!+A;c@1O|9e;fGfmdRmY(y_%MtNLA#wQ>^j_i7bM^Z#X$ zVUi2?05Z$c?*`wq1?8V^}BvWxO z{il(pyQgbec@u`&hCOL33oqm0679hIa+SJ5rR!Tloxv3TyWtN@v*eqT5r}6iOCz@u zILrNrpCy8>o8=EdhBHd*l-d`?P|B1kfyMRXWfsa{;8MWlWOR_c)q;~DcwQi*YkY&h zei!$#%dJ`C!AKJ!=rIE1zdOHfMS28>-3NMD_={ri{in~Cd>n(l3O2im{3^ZQjCaCz z*<9S7H<_1YOfOfd>c-|xluCZCmBk8X*(tU2EfTu1oHl;(JE}Musj(>-*aCoEi_Pus z->xKlD5FUr9Y~@5aT4EZP~fu%QjeweF?uH|1xz$d0c@q2Ge0;3xti>a;B3$7SUG;k>N*d`xL++3$v9JC1&ThONuy5_d0qOcQ2JLeU~ z!NxWJ1j5^K9F3^m(Td@XnM`3+pSwn*@$umq!cu&)L$m zrU9rbg>G5gx|T5ZgQ326@LlPe#hKdNe0cjWH|9ZA=&Bs0J55574;Nyl1659|gHi!c zb|#`L>Y_PZ6s*mle?g2F7u*W*Psg_WZ(iOx?imi%`+4w8oJ;z7eNzx&A?IBKD3LO zo*~@JCu`v$S9UoYA!g#jbbEfLhA(*!WOH7ncmCLetEA=D3QsSTcPc3`6cltdRu4P& zqjj*o!<(EfMH!BK!M<5W_fzR>Ts@Pfq?D5mw2k(?1JeVSD(!T}&xg(XLGKe+N|Z)K z{AR%lVcg{X*{T*=1lRxqR?W(2w!WQ;3*SFssg5^61dY2Tj>=ch{wK8-$dcVrz=>9>X!Uz-Q9k!p>R-twl{n6ZP?wuEhJ zV_iO(<-SfK&|RWuU@yXLG z!VZhpuz1t=-cD)(P!=H<4rN?fnestVaX0$NnwVPVN!l3bW;Q_O{Q zBxh}EXZx!%9&`cKtI~v)IobGK!(l8dtxTNPL`3r_wYHxQUdKQ}@B3oi>@MVX zydDQ*>B@NY1N?zq4yqWkr5DXc_Z|pRztoC1TBprv`RRbP;_?%OB!^7SqMRrH9HGOk z%ZvQrku8IGTrAlvcw~g9txq&}h)i}{yJ3nP*spnYml?e$2bEx)BEH*?wgcJ-F+FC> zTksoXJ5$OcaH>pur1kk#W1V=c=$JJ7X@TI$rQ6Vp*;yu!UZW(^avoWJ>f zGEwxau_{a9&!bf(&2tMQNqn~;k8KVTJrnl#Q@4Z5!@a zFWBAJ?^JVf$Uyh<3DB~{iD5ceoi|e&kjdN<-Q{3JvAycng66KW30&LI zAntIIc>vf(Y`#VNdCb$uLMl(-lCBOF6GmH`n**u4$b1PG_=Ozl$)Hf1O)~-~ho2FW z&TPAWHCKX;66-e=l)&pwAe!BwQe<~wJt^vD{%4yGEB+diCY}xtt9tReMgurAf6n@B zAD7qDUu)`;j=jq>&MRV|yoAGs6D5_vy~6!DiKvtg^9tx&kGa-IMNZr>TIz^NWpkLv>l|e zue1^SM;JaT1NEPTn^#LN^xiiLNcYU3WMNLgeqbU;fx1YJIzgGo!8~Y&A*KW!ehP`u zKuv^#zb4h33?M*bW9U)TUCyR5^O+SE`LR&sFR-<(2VKmZ|ESJ%MqhktNFz3sjs5t1 zgJZ4rm^9GfXOacm^b1zUiZHnF!@U$#L`ECGeYx1ZNzUh1bw%-;s}U*rK^tC%$m5mV zxG4!k8d%#BDOJ<)ZHDHLAfd6WxT4}I<3KTr6jNQNl7PB6fN`Zw5F!~`)6DGG?CI8D zW6}(=Wy05kJvCuC>kAUO`!&t!hZ}|bTs^2~igdeeT_2h6QcI zJohQvjSrNSy*sYlEUyL0>FR=eE0NV96D5MUBtin`ta30MmUcACCd@Zr?iYk%Weg!i zp)nB&nj_Q8)E`TYre=ga(rJDBp_Q!_zdUmHX=#8u!Q-ceCX!RYm}G=}N^S@D?-{OJ zmv*Pj*CgSkjwsLq6GdP>{HJEn`0cH-s!PDPO4R5NU&H*v;3elh_<;b)p5{1^!=Xc2 z6N~JmDfgr9h}B5*@qu3M@kBjbE=+qW^BW73cewb1I7v)la@aBQNitdDy+5qOE<^q>jH49Q1r5{}!N2_|GNZOK!LL zh%LJ+ZC-yp`5)<DDZ?Xl&cc=o+@LXGvi7C^&H14aoF1=45T`!)oT4 zw+gWeYN}6~qiiRFe6dvzg&^Yn$^;W1>Oc!Xx&ATJw2&nEv~= z$$UF=v(PtAt7~1p2rwSi)IYZJj4Ao3zv!VRXYEmf>n9cS<*#lCDa*qKkps=A6^uUb zPB}*-&UXOtyf5FUqs-n|!`d$A{`UU6wTg`7ALi%p@YiljKnTR-w7km^vsFjG6UE-Y z^B!1}n*@5|m~xV+(qT(gjV$rz)5I2ba+bQ&y|{Jtrhc^cH+?UqbA9)J*_hiS;Uz-? z^9B`zZHLt@=-&b#dyB98wuxoH=PQ-AHnK{F+NrQMCdtQJ$D=RILClpMHSxk~0mV?X zm-jK}wFd|64l|K)@iGW0gh>ODs(P6a7B~MNX`??^$fgXvj5rqK{Z3g-Lh;|((MS*t zmCzLhxfA&GNf4%)8(xvhMl6T|%SRb&P4Rjdg<$F{A|rl4?V|a*(JIh$zJXiB#xKC} zs*vI8zbAWp807Y0#|F#2I+swaVQT%*XG_9*i2sw>&0mbF@g!_Qnq+Fm5t?mcbX;aD zwAOtUpP1gN-zbI1+_P3fI_Sm&liGdSVPC$bW~R$|f_Fy!x9nPb)@a%b zGEzxnx?LgQFKj`48S7zXNKM6?5+JQr+rM3YvKEiq9a!Cc#l%8WCUWiz64FX+WI2`R zlawIqsFnN%o#++jHNrFGj}oLNXPd4w*o?XGdlLkvn*M=;e*u!y!6zwA!M6fT?>@51 zhG64L3Bo#LgMmwp`JoACt~N~(CZvj9Q3H#8B`<^FjZJQ@t(U&PQOEgk)DX8zK1;Mc za>a=30fANW7mm?&L;jJN6|N0y7j}Hdm>{k^87n*)mp{#X9)D6=-Y=2!`kX{>M@v4s zx0H$P78rPDtH>yejS}51@Vj@;3AS9Hm&7 zXB%k-GYH}xlJsZRHk=m0X=!Hs^=!B}p_3DWVS5`UAa4Cmi8xAT(6DD*c7WD2I7*r@ z4#z)MiOL22M1$a5Wj>m{4P(T#i8dDoPPfs%OvEDlh07``6uWqr`YS>Jo?ngLCLo+^ zrsLtrFuVe+p=@qDz#fA2$ zlEyMP#gZJiyWb3rN;Jo9W>Q)hthN+bpK3GJ)>u{!XpHZ{q^ z4*p=Yb<~X5g3ttM<4Rz^G!xfhH}Sm61?oKkbCHV&3ji*omHef#iWBrb1U^r+priWB z%jw(K>46OSa%u6Yn!ty!1SD=`7SSQ%K%)}GL6!oFqU1G)! zKF0rv^P7h_@!cSr8f->XTBi002{u6x4#R!#?!^wS2rNHnKiuzO+r5qtM+xT#>&G9_ zU*~s+b(Wl6xN@_@f{Q}5zRVRVasJ&x$o%6jwWNY`8NC3`q9VfS>%2Q$mTh#EObtS6 z-S(+>7K5_oxWC{@7k}CrVx;Hj(+dlaQePz20_*9$$#@}n*W-NbYd_#wNjz&c=-xE! zdsHBC^vW+E2=3M9kG0`WB$~0!w;RuOSe&rOPFepoI~e3rFzqsmfd7l~_E(GXXzRXRxO7u#?x1u~vMC6^-y((7{;y=flf zt*P#tZue_ZPp=wWp3cF^Rn9(2dpw2qzMy@rPPBx!9nm*E>Jgq>e_4KW6Vvv5ze(X# z*}+SBP$67Gcu2-8>ZtiOF5g<#PPBW3p7(ibLoD0t5Hd$Z@*~~e*)t7kOY)UhGW_Y0 zBz*}B+X25OxT(wFH*bt^YtQs`@OfMEnP*dc^2r1#bLv+t1l+izgKvKPr)h0i#q}zV zbiL$Kx*iWHC%opxw7JPOYcti2LG=l}JPlMSyDiqU74H{o+?2BCWa0fqp_!t$ehz|U zrSXfx;&ZM-HCGE#PShqAqalg_3eh<)^=iqH5(bl!{uqpv^cENXJ4h)p7rVuJDH10u z7we8>aumL*9>PqE?lnlckzX|Gs~P@tVY-y|c{vTL)WFa5ypW(O?r|XiMN{0x9?US; z%rvmcJC&u&hffpuREbX)_zH;z0Ue@#(7mL$<)=K#J}?ITV`X!O^yYx89Ycq$-4o}( zUe@WGsm)1REO^KD0l~&s-ZMY)t>f z$8rvzdMe51o==gss{hb!4FNv>i-%T^@n4L-Wb$sxRW9#(;EQQ;CF7n+2lpagn5Ue$ zWzUzN#NZn4On&X86Mo7fbcSeQ(dbo`GQpa%I@NM#gsN1Y$mQdM*&`I?Pgady)EKp$ zBDOWDwy!vGnzs9!nwIO-vF%EMAlsqhcP)PYNYE9CtRk@Hv3Ljp9T7oC1oAeFry-Gp z(Uc^Whxs}KgqWs{ZsB*I)j2TvxGWw+MWI$Irh9(Ub}DR!vYpK*!)VIT#KfhkXh#%FD-F$cj`?->R##^) zyDZ>20Ln<@CEq-g<@3i<92>Ssnyz=J(Wmg!oBe$3K$tC!(|=_WI67$Z-ye0XA)g?igDOPH z==Zn^C|;jpDL3ukV{IU%+x{^cniM#}^Vh9)q=a+*5Kq?@1gm`WEVuPwrl8*JZ>z{y zDBgDpj?c++U`gOpxE}3dwt%V@oC1ZkHm!JH^&9{I18Ik^pUm)um(rXVwaD3S;OtJjA))HQS4yRodpU%!y%ubxlQpR%X@y){+gy?1TnSKhn_Wu>Q(+YVeDa@E|u zI;*);e)3L!ZfYoh(tBpw-W*<2)41k2NlhkTxaz#Qyq5*ALeLcGYHmEvgk;!5m9#kQb$ck+%NVHN!-E~?_{!BAci$TA@b8$Wf`dpm=^`z=}3s337aXW!EX!sQy zP2>o6=tTVxG|C)C9#=oM4I{DT9)-tJ67)fL%haHPcglMVj?dHhzX~ZYp)6%bl?h~) zXGkMJ6>Hl8(3i0J`xn!E?PP|F3EMUNfo8wLt9pIBe|L~WT?WPs3jLM?KfavfQ%@#& z>`I<|HMPG2sv@}W<_&z}12+>1uJEvgX~DSxh^Ll&Bp#~)zX2ON-TS5uf#n^J$MpC# z=xv1FMt5Gb9D(gXA}fhy1@SDT^Rgi6;a)7K!BMx2^KA891)MrEqVHLV6)g6bT6FzD7vc z+yf!u*0;0N&(G`(va3~}bqRDKVe=QyB>BpT45Jxm#$}hLD*W`J z4SeQTUqy3dg-1v87M!~RiOlS;_3+R&*wEoR0b(f#trA@e55Ub5&=l~61+8Hyw|sLZ z45uXVtRQ2$)j+nxL_@RLYTI&V4PpTv^`c(Rh*}&0qO6QVDH`)QXh;mo<@B#rtU~R-x8PqpbT)hI36H5r34Mbzc7ySloi*VA za3nl>DaSvb$ne9yJpC!#)i#rofF{`5sPT^N0p5H~fZoXLp2lQe^5qk0{?BtMPK;Vr zTl|&dH&ovJ>TP`TgEy~y(Lc+E3j?0;?tq0QP2aFTV?4y z#4?aF-R@hqguEp&or%YoZhNlfOf6qa)NcG&7Y`A*5qAv-wP48W!XbcFiqJagQzjPVxs9t9`4KY>7z-0aw$)C zHp?GqZSeEqx9sIt-@2EE(9AjlD}pN{?#bohQI4um(fY4QM>8~r-HWtsLo~QN&LfNF|9(|zvUi?$C983=xKEY%sf2GDQc5>nLrEXs&fEbO4|I(N!RFqWz-^;ca45s z5kw5Zu2zG$UgPKPjegeG5bX!|n)AYt$!DKU@r~1268V|a{lTsG-?ycePki7IKXv^& z)RnG^UhJ(qJigo`@mPu2PNA(x*^%E6a@+nX1+{Kn^}O{Skjta>4T5Esp7LYkr%EZn zY@OT+NCX+wk|RKsu2Ug}Mqa2mQjix4d8v>`C69t#Fl<>t83+@`I+Tko3L%lw6+~2U zN~#NPBpy^T5t$c&uVC2gV&Yn)BMD+we$Uf=?6T*LS`GiDCLDmqg7UX%x?*4+YY!>i z4n!HR_J7S#Ec@~Bn9RVan`Y>-U{<{YAd#0GA2E6OVvdLU^1L!?GM1G%(rpi9sIa9` z)L0p?JwtC+~)6&rTE9=X@)Y+tR3)#fTpmIpSx!VAA84jbhWI4h^UmV zn&#yZ&%^F9J>^1fx(3~?W#T+y=^}$3D;L{_i^Hz!e;pA>g5@da0z#Oyls&GvokU9N zWQ2w(g`2D*1*TBQ6`Tdd)`${t3TArAflv?zbUX1BMGcpyZ01TuZ&c!UA9xypFkmva!lPf8Ql<68LQi5L-bcHl-?J>A# zlb@ej?<1(qZ8C}F9KQ5&hR+;L(wDGjt@8)aHHDjZcJiC=zMi`dtV3H33l@p%UB5i+ zrPO%Th7fLBp7K_I-nH68;yMynU4|{WlVx)N45l4YrerW})0eR6 zPr0|};x%e`C3B$Ktssjo*UQmTkpMr-J4og*E%JWgA0R;-lN;&Dni%X);y~r zyTxPaupPMQwdL`s11(Vq6ci?<^yZqiitWIaQEyIJD=5M(EA)i_JSO8vcP{X3mAX>l z0La^tq$#l+P=%{{Z%Z&#fnB(-D{g(HM#*o#z9K*oZu2OkAl?@-6gopHyIOSiwdw3>)7ajm z6VhFWzT@W?|-655YQH>of8XKc3TN*W*{0eP>`a}ZKmgM;%ldqo0 z@Xga%2GTZGjgBQ%5p3*?@@sG3$9rD0ZFRKvn~dYQ?fw#8A5D)r5Dq|d)Jwuuo(2GY`%9s$G@D+@Wd69q&d5)e-R;|ts%hA-@Aife$yU$ z+rx`8#zm(n`Zw&=)p^VTRdH3hwN;ks;<5N#8m49ss)xsP1bxsPDU1Gl#=x3H78d+< z?j+)|f@y02|0)coc`QE3j92@=NNE55))s~`4vD-ZmUD>Z91^A^V@lG66n!b(D1Xj& zBliw&rhr!P09cMhR|LA^M)DgBh30@lvtOY*tkM-yXz;lae4jf1l>PZ&OL$?(2Hs?nFJ)tg-xzO6+W&n72l#|Lr z+{+~Lr~@6%6YAd*Fa3Y5lFq?!Y`I6_u~Y;MSNFqn_<2;ri~cVf+U{0;xyMj1$ zHV^gX`0^`hj*nQ3XPr4^lL;W|Q@DGBj}QOyJ>0Up6LqzxCly6?yp}p1bHQ&wTcdY@ z_NYWkxH#lpoIMs!Gzbl$iO1elvo8vXNP#yflS_u{x2f`KSx;M U(Pz}jp#T5?07*qoM6N<$f)@CT2mk;8 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-06.png b/docs/en/docs/img/async/concurrent-burgers/concurrent-burgers-06.png new file mode 100644 index 0000000000000000000000000000000000000000..4bbf247c0f3b51a7e0e4edbd454146442785aaff GIT binary patch literal 164838 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

4RFXOxbDw5LZW!icJgDC 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�@*isWQ8&$(d@c`puDn{l}0L5dTmS? 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

$${1cpK2$znyFR)oyi=M{`Lf^ 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

bcb6( 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 +pM3o2=1>m{-Y4;yR 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.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 VzBl4^-eUj&002ovPDHLkV1gk&*@6H7 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/async/parallel-burgers/parallel-burgers-02.png b/docs/en/docs/img/async/parallel-burgers/parallel-burgers-02.png new file mode 100644 index 0000000000000000000000000000000000000000..9583b84dc239e12f7b4790393e2fbeb9dc07c16d GIT binary patch literal 203644 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 z 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

Onv+Y%F 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%0AYei|4 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/async/parallel-burgers/parallel-burgers-03.png b/docs/en/docs/img/async/parallel-burgers/parallel-burgers-03.png new file mode 100644 index 0000000000000000000000000000000000000000..bea9ff0d8039df561b328eb803fafcc6f1346a0b GIT binary patch literal 168628 zcmeFZWmr^g`!76nH-a=G5`uILk}3!&p`r-V4bmVzFo1+eNjIpJfpm8dJ@nAc&^gpl z^Db`h=h^Rnf8EEiKkfMdbIir8b$0yDa}oAJLz#@2kr)I5k*TUEz5;=8fw$N?g!sU( zOUn4WAS@6_Rq@el&-CqCk92*v2Fw8>rLn<$#E0SzXTabc+#FSy?IXNnZ>1K)BJV%6 zz3>n`zR$!QJUp**B=6upCf>NyfY|ZP&v5mFLaO=)Ci@-SD>*Ox7@}8{r2aq@vXlv zm52_bcBZge!EjTN8}AfOA;Oet z_&=6|)Ii4{6JpS(zc1#!CEEKS_P_ELq2>ASTipNm_C_co|Ci-}d%pCDiD|RMKFw3? z8T;*aXJ+a!aEmb^tkT&aNkK?OB&ONj4w4wH!~b~;44UY#vY{fyFR^FJf``geHoF

=#QVj%&%>%sJeT;mwXEdseSj}_Ses%Ki?V) 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
h}Se1glj6jVqtTRtAN2|-(u4!43>I+H4ns1Ny z=C9M*6B`XMp?*(+|A1TIE70W4czmkU}Qe~xq%Bof~B#`)i%@h%;IA<~#PYIUXnD5-qIH{ea9{cni$ zxtg9E{RrX`5)EdhPKYLH8ZuFN7&`6?Uq3DD77d6M^nN0(QCzvi(9aW~x$6t|e;!HD zDbyq0J2ZH|2$d~bL z^x{EBe6qUr9k2^i_$naq5=;^tP?0gor?5%&!50>bHa=UMtg%xUG%^=Tun+ zfcN{?Xa(*0^>4$02zSZkVm(*5j1NUk0RD(gq9Qpe&bhw`=gXzV3{xU|d=p|dAt7CT z+i$x#T#)T{(gr^CMctAGr!c4%ee7Bm3@qptuPt8bLgIs zW2O@j<8pVls%Bx4FJZ+X_`&#V`@_&YUh(*(vdmTCIUp{0purS0`{KEB_g;HZvd5Ep zxk!&AI)*0-zuBcb#Lb3$J z{-g6DO6rOAgLzKOpy={Col}t1zaK2|v<#oOLBE+@q?5IkB^wv zB!XlJOYMz07t~D9h5l?|p|A=qx`Bg#Bma?2>1~VS1y>^pt$xcb0g@O-_`M@dyC z`4jW&_~&2m<1DRAT{wxYiSZg85Z~>bV;Aj$csJWUq);Ud|B6ip8waOAR&?Vt%hAU< z0&U*J@dR~d6gmC~z)&T(F4EdB{l_63ju@l-YrBECj)hyNmItY!z!0vh6hCvh3oqVR zTIcDRvY6N3@H~{T9530Z5*5;-S`JI6mFsomVcyOYnH7xv@r|r05aw&AC^G$uy2(!{ z0El8KuB(ejLc_(6Ra_nD+YD`bt+aCSCd26p(9(^aoDaV|U%eVa%jS{qhS}g}?R}k* z6#@8kJ4qA}L%BtFS{rOuq}-7mvf7aD*_%_~Dy>GZ6Ips#q!Je02~tlxL_Ke7&s1y0#h*rXD6vhjh2-qU=GO*Y&vw7T0tX4Ik zsKn}M$vCpkLl7cENh(Un^)kd7gb=~|PIrv5(6LCB&QU`3ZC1^<^j&WR zm6&02Nsq7pNWRU0aRl;)(NXa`y$e2+%@x~VY)ORzsjBqiyy(9eoyKzIFGAB(JLOgV zXc0&pKkLdj#-SUGX*m$hM&XyD--qxNQ#znrG zG~kD*YAC&~|MuYz^}+BuOla27d{8BIX^9s<;`2U3Z8wccy4DoccR6=wEOUQZ7;z%P zap%<4?)ZMmiA?$mNLf{EpAe*@ii(CN20p+C@^xtu(zO-SMf^ciy&kRssQ*Fv(f)Ua z_%w{4z8dLQb$Xb(!ET61Tf>1MlX`gUyU)QqMnCN6V0~PD8$S zQCF!jA1jH{ukHu(VL=GPR~R>s=!%QY#$Lpx`-gZ|{@r9?*9(O2mW8vi$IUGi*0nW^ z`48~7U7ATW6wQj6A(?-k>ZpFGtMj~X>Qiz)K4y8XXsh=|r&F?EJoe%Ny=GnZYUWMO zj!}qtsd}7DU+%_K=!Z^CAj8DcObF*Vje!P@Gx4W7bAztqgb^X2WmPS9<66G<-IE)e zox}A+JQgcF4ik2<{~-gzY7tqB$te4V>=_FJ9MP|xa03<%UrGGva~!Khe5F8XF=piv z0+W1zVONwYbsf@zUKYXW`vC(!q=bx}+(!y&OR#O4{W#gXycz}%c3~@u0=+C4B#)9xJ z#X;(mr(ou5(2uCQR;I+Ul^HDdMB2nSHDMX8246q7D`{_?nm~h$j3W>b+YLxj5+uRs zRc#Ky-Uq6D-JbAy{gL)GA5IPPh7&rC4lP{>G6I_4!o(xaTH8wpcvOFu(8*K3UsUg- z>e^|sW8wh~H4IW+rIm^rvt}7V7h1aM0Tbm}PdznNR4SMk5O8$41mxBMv7%uxXsGkjC8qhQuxxe31a3$Ddzz?TalIp6GmR1Ye>3 z-uFHRLF0a4;>9hWyBWy?vzhEdPu9p)>?6N!=0N&!O{LSD9BQa`c^3 z3cv&Fq4fLg3lqIV)uQ>YL}(f&w@5&X8I)u|xQ}oaq!rVmTFWaP7)rF~mN)Q`RDzV{ z%K?3GYL&gCTM3bATiycv_H&l>l@l0pO@%FehkiGs{p)Mc;g*wQ$>ZF3l&P0k;y0ec zqm^sEqa#IV8*sExuk~P!FwG{7$9T69AaaurFRsYJYTD+nF4q}>h>KKxIR7@%)FKPd zG62gJ+Kg(Wb73W_`#PMK62teq-J7j%4;5yb)eBftnpdlKAm3>V=j{Zo3M&fCr<+lT z%|!;E#OA;xH)L;)Ix+i|V(|n#UQU8l&!%{VVGcNL!yy}h{&=&BRyN%x^Ow? z`$L}c-mS6k-Y!1pPtmT+s!(XJlog>R2l?%-o`pNfVVv#~5|Gmqs`_A)6(tLrq@%C5 zM)}VL1a0-k2kghs+%+Uc6BO1xtQbhkoHcM#$&Ve2yb1dHQDBn_1lxfz`PS97u-Pth ztoxQ~m0V$ivi!t}Z{W)N!Z7XNhHYEoQ?c9Nq=t8UAARHI zrETJ#T9dEu$MvUVHLc%l92lp9f`spknx+-Jw%BrKldF1X>Nz(48xYf;aIE8YdJD+%qnH9+qgX}VuRvgQ;zv`eHDD=Nu7LWigW#|kxW9tT!%t}Zj#eTE53frcq zS-PgYYM>ji+ua$~o>4bgrG7Y&=6ehvs&(1=xBfr|%p7KUo`5CxdcS4^ z39yRSM)?&UqALEm*B)!Eo6%5wv6$%BWduY4q<#6D*I+6OUKS7xh*Ct}sAC4Hmhu5L zhc-SwqL8kXVXw1{kiSy4IA5yZQD*7vq@uHjjc9noHn-E7){dHIOn~e|NAvxPOiD;-ZQh;UcdEm zokuBgir{{7^TUB|bZP>YU2T|1!R&|ZkU?xg#lIkw&L<8slBy#C}c)qHeCXvS$uPn_xdn85;%H&!Zmfvp^g?)HY z$AyN58Z{=G4pwW`kRFkcXJ{3yKb^AX>tM|U;nXwW11>Yw zH$~XHNx1d1!83KfT~WQlT#IJa{b;vP?Pz2!6GeUD0?t@PG)Z%B@*(jT)TLpUuvFo| zm_*2v?@RDC_vD{H^S$|~Vt{a%Kcx#CayfZyv|KHa*l-A7rd^nwb<0KIzwOYew4s7B z)5n)fB0mJkyfV7)FeRAUS)0-j?aLxVc1SU{e4|J-fMbg}RC$2YT48DJyKP|F?qI`t z{-ugJ@|d^`VD-$|1Ggz!j&6j;Jrj|V+y0sS$inWCmXYmffHS4619MLxhl*2*bLHH9 zlFW{^yH3L;YQ4Lu&Hkb%B69H?e|zw~kX?wE3g9^l$)_}PWXYO4NXSRhJ6H)Sp@6ndPCye?xo$L36K*Qa0 zvNo0#V+`t{Q5l)-dG{JpZ3BTZnw$AXP5yv8C8(v#puRs%z~-XaW9v#8hmD-YBt-1b z-`0ILx)ja}_u)0FeoQxS#(q2rm_AG|q12Ii^nfUga9b71voZ}-(HBlK(-&V^li=#_ zcvL0TJ~jk@5DAPBc5{&~HOvL&SFgJbez0M`$x&nRx&G-kiwNPc*<@up76yRm|AlpT z$O*(_h664{gXzv}P2G@eEjM&UR?8s(n}{l8s>K}2+6BeJPvi3bktcnP1AtM^nfep5 zSZXju4!3wV?yswc1Ut#R^H7p)(1m1ad{d=1x1YT7Yn2FT-Z51iySn03z(}I{|L*d9 z8~EF|krkeyRbWBSOl=HD-Ut2WD?(U$P;9nF-g+oKe=Jkp7o@XWD ziYynR`4d&Spo;xxjw_Qt;&n+Z)!g%R@1wtjJl*I)_xn(0h9}50jPYJzYyJKBYkOV! zU{8r&BoXcSiZLHi!Z> z5fW8?_VGTA$7-Csu}Ryw`s8KNVJk>9e_b#`m~+9>8?tr-8vXEZBDK$>==j2P-n-50 z5MaOONU7+DSL`mJv0pnHIf~=WVhB4pcJCt2+ooE~y2m(&MEuvfhr#%hB*LXJSO6PY zvs1@{nbnI%yurBPU>>!XFI@K0%FvS#L7jpKj5U_DwLS1)oZkWN(Bzz@)f_F5Ugqx< z8o7`DH)WLvrYqj-_#724gJ-M07eY2pqze`u6#m=)F)BVla6loL(|syqU@2=A0{|cL zeqCf{ZT(jgfCdP=fX_p)YV27rJL&roBWLg5mRuV@KV2in`#^tuR}x&?5lfNp2;Q{-Tn74Lrc(g<@sWSUTR;g}0sLYBJ5=%o6lcz>O>mr+A`!C< zL&KVaUPDR=W--Y)Nk6AB9(wQ&tFlKAyFFg2Ins5<6L@Vd zoSdEA3hOfBTKs-V_{IJ+BFLG<){9m1Xwe++&6jNEIUglvk=msLXS%2Bt?2N5<4WY& zbH2G`PWfJG+5MIxIHQZsaU!4r+l_UB>`FWxfE3Yr z;S0_%yMHRAC|Q?9?Hj2nv7Zir3;k5tEQjo{5>@pbDxcL{3^1c`Lt%zEKC+_Kbe}9O zU67iDd>Z?!o1w=|akD>8ji_#sMVs`22&(2(r%L;Mv-w`uobspuWLNLbz!kdKT&hVd z6?KCt+X?AYt9}dPwU(33in90B+92DUfhc)az2_*${dmZMXCRX(=Y-3$SL2s zeZDb(5=@M6-e`CTU7%xm7W2EJy!PAdIc0_gUaPD^uh5CcZX^*)+#AC#6hG>s&(1-2+Q);3bX>Lre9Le8|PqFm@?HLs_v+G;{*80-(Uj%+s2GXt}lU5t+G{k z5Iji>#MMj0!tZb+W!Z34$LCaRKrUI)!GYKtTXTJ5mdzV2kDWmzkZ17mG51C(k|kaC zl`7^~)g=lOh-z#0zqNs0_>?%sA1I)(lymjpDVWBf>Txnlr8?GUPRMG|ogIzRV6k0s zrtl(CmfZ@F&K_*jcTK%w=EiC&hE7|t+QIOP?U|5nGC4$%2bw(*2Du<3>V!D|4GIYV z#B@)?+c66s)ogsYHV@M^oKna?o-I&L^Na`@GYCi?BqrA2g}?!6tDQIdAwvS~;D@q! zToD{l^1fKw*~((RkcPfX&@mS@OEdKST= zq{R>gQ%DZdysVYRc|NF-ja-Q)=2l3* zc8DlEZ-|zL|9Cn^_RrFfMWR*45p*Eqv@AX^}725Gd>a1OTR2+g&ModU|B&AOmK} z-e)T`?M9P{n(TQQkNMu&On&Do2m5_v_wiRxJ9WB@YkeW;;XMN`(0%Vva~DGb0}$?^2= zzG+A0NDJW)sj&Z30mWL%p(G8=E|!MhP{Bq9a%$Ll<({6=1s`x~D*-u|Jngt>0F237 z$U`;pl)CI^`oe!Pb|S%nX!VLeEIL;Rs?(8vW8PHrh53(|Cnn;X_Js?Kd{)+=+3EcH z1}T$@0_m9{n&l)LH7KdzU{e(Xb>9`)XO%&Bn1XW6J^!LHFgA?hJ=Dro)&EB=n9}JZ ziu-kKvA6c~7BzFW&}w2>1q>A|kS4}peTBh{=xeCG)@ID3Bt{mWnAl=FLq51GN#NAJ zX)$!feX{k2ocN=NkL6O}3}{6^zT*~#U~0IC(^Be1b)00l4cr&cNa(M-aoj9(V4Vr% zqJyRG>y5w{s_x^z8*|}%|R}0#jkNer6$TqVJ zU~9Wls0!Y{r~Q-G4g2hqRZHXt>bPoe7!|Rlo8{NZ&qn;bL{k_5X)R5``KD#bWbu>! zZ_RhG5R*C;2p=;6x?$0|4LMd$yb)K}2H8Xysr=*76(@|?E0T!mGxash>qPA>e|J+L z+1~t0f9_PxMPK-DC{vIGdzg32;v0b!Wi3mr^9EeBwq}&`hL^9eCr}$Kng?s6fa+k_ z7XL71DDeGS1OAl2o~6!?@cAdjfKrm}k7pdUmB^0Mgr?`W&JP!)B$D8p+F4Ip<$OXD zv17;>#C!qI)rdzT+vdO>sNtbpsul5phBSqOsf& z3ut)XEK}j)IbM=xK>unE*oxGsWcD^wYr{C0iBigi1`0T8|8(J_*M{V2fv}N7b_Tpj zRA=aQxJ?7#)~)dk`vV&&7uKj|Eq_1)c0$X(>#r z{KN3^ZFBGtla}-5;00P1CwaaF$?~(L74Gwy>mZn*rK=q9(M5FZ);D<|i!@Ze^!f&p z38EiZWjIe*RatVhS${iT`NM%3SwUdcSIMQYjOLmflZOJ`&!ha`M~lcdb>#+Z%iZxl zFmy>Yw#dLlWM2iA@kkwJ+^xem!46ewC`hD8zVg%!e?W*#DWz{YtTzb{*FaqS}Yr1 zW?^rtfLs!SKcs#4z>Jj!Dxm2ceuyNZgQKIs;o<_}wjaA{V~^SJejzui7qx32oFImE zH#HC0a$%z1p-@SKzsnzfESW#|&PyfK9F}%@Oz2|whU|g2eV7hLqyym%0m#ZfD=gm3Cf8X-{UrJRc{64~N@1r!zh&9aZ}`=OQEzC7R!GRh zl*db(#&}>6>neO(GaV%FEt z%bXuEQO%_BZ275EQc#w>$IsjC2Zb|oRJ?5YwDOk91bNWGa`?Q4K(HJ zYI!>CxO$hBgrb70D+dAwIqUkKDsau;*wAnGXOZJG`Q*BvyGHo1xwC4L5k@io@-HCJ zZ8$2Xb{n=8lLudhE3y0dOVeYg(Qk=m+no4#Yzhh!9@x;MYy5ciJV^y<`qzeT2Aen# zQ1$}esHOuCO+Ee!iHXv+4#omvklc#Ms*Q^qL*)~R!6#0+XcUFZVma$(mTW=TS-mL2 z1Uw^>e}4H_I7ylTOS~xDZTg}3$R%*K=B%ps7HgR7x4y+Fm8jG#n+x|uEFhi`P)`MM zYbA%TQ7PSB-2gRhmbE!L+OA=bjjUyLaiG)6;$_+V%jJR0p$qqyD$g?TMnOEJN=qd# zX?_jDLYrYLqHODM*3T$K`Z{uTGs7(7s`j@K~7g4O7lleW<&}S zYUAWnjGFC7nMPR4#9cdGF-mrMzPsQcdaLCiWCPn`fdv zab=oZ7qc}T11L_-4qnLfKp(%})Wga<8$tIoWEz;c-l?r&soKuWj3P7cg7dtl`GSIn z8thsQxASQhb8tmKr>ddFSvDj@j0OB`N|4Y#qD6(OdYzforseT^^Pr)3>#83^^e5|n zofu%~ddQk9m4g_gYa{^$BUV6|r_^0bO%%HSZ|*@<+N^6`II7AYqG!@?68%xRQ~J4O zD&o?EG%7n{e%SC}AD;2qM%T*Y2~)GTPTQ2jkHu%vHE_Kr^sC>4T#WizvW1?cFss6w zQ|^=)S`oy9k)#D+L!CGNYtI5_$MDEVT-V#m;$oA-Eq?S&cPfl?<@8I3Em|hhjA&@! z313V{jw+P)kC-zs>U4*l%C@0spiuYKm+x}`|FLLBi8^Hzi&A03qVDlzGr{`n>`gZ! zEcMDq7i?IEyoEw24Mo-o$)d1>72x(FCx?Q|S}2Zp-1B!R|8*E+sw)H#h zg4elu=8fdbx_){hxlvJm{}{-S$?5>}>&ISS!mqhf+Mj~g?51TlRcZZpc8q|tly;mp z&ASAVo?92H9~BQIX-AmgFI&(SS%__2Ae(ZQl%AmzdK)v9ON%J1I|eRVtilAf#>kd@ z0<76Y5G$P>F*ji8=6R6Bz=T`Cyq4?*#MqyRq(mYJWpC4Qr*1-vQhy*da;b~>MQ|X6 ztY{K8bo-Kn66CbOu8)ruEB(>q08vCl1g^eb+#mUSTRV>6BlCl6cXp&NmaiTsK)t^R zWe7$=V%VmHUO6LD^``SQxJlpTF`i9>z=(>GL4zm9G}h#Id`532k0lG-*G$9|pJg&Buo z@%jlW`~2C%6tjxY8SfJXv|WQN2_Xlkd`5-B!SiudA9y&5XoFQ8mj+Z^b#1Or*mVk> zoWSG_m7LBzu;}QBqD%I*%HI^sJ8-G~bL{8)TI^S(oj|h!dVB2D?d%MX(loLRp=s1v z${mZ!;XcKFJ-RD~rER%w-#+C_HdDH}HFen{eJB%({1!C#xrEtXooW!X-iw_f40$6m zG@W#TCRNTS3w``HAi}bu2Ewfja1KA`{4`RuHpwL8{OJI#yf9xAelE@~BtGX&ro3?V z9Ox%Z4&bg#8VQm{B36X@h}xb0{;<~1uE@DH_(*!x9|l852JSK8sAthBDG1<2;5Q2W zu{vQvZ8;hc4EkB5MF%QY3{Y8%?znbV6B+r3gwb8~25Vfxsf4`G04WtSAm$TN9r zp!_#&wEgRH6)tdm5@@Zy`V+| zTsB(2P2Mi@s_TWHvtwX8- z!#<>g&hLaa;{|5aDs^{zQ(V7J)4>~ij+I8 zTk+2%8o5NuR3z33ScVP)$uby|$IdeyQO$*x^Pn(~{S_XxA7-{*42jIPB=ir zp7%V`E{p$-m8}v3xIzlHBWVJ-5?{$FoO*EG?~6iR6JHB_&*i``dHTUHJGY;!YipIV zjMJI>V!nJi_Hoh-wZUZu?O7fwS@(o7$Fow?6zMS|q{x@`M+{!UeLOqr+Zz;vtOzhD zLi3^#%1mdK8$p|)9}*SXLknm8U5&@O0Rn2&#DNMblt|+oFzkGZkDS{+die=7#w7yk z{#-J4kd6x~hmjp(gBrB~St!Wkt@-vVK^amWras*1G27uc8OR6QYo|If2pLF6fwHl4 z3y2}DEe>x*O|VI;#61l5J4wzs!KVs>;M>x8ksGyVZ?N(NrmZQGAxHh=K4=4_&FcmRJ! zDi+*rmV$?FiH^2sZ}ROhN(K*PJ{@$ zUqp8z<()oFVR(4hLmmcr^qgjd4ANabCHW(PjZdC0>0p;fM^n?i7y<&CO8t+s8nhLG z9CD_(loTZSEqg{Ye3b7NbdKSYmVFvmxauIpFfxwzGI_zQyTR=|6V1{|*j5Fn3HCoF z{knrNlzl;#aIIgNq4IeAMzJUBE~Vg<$OM~Yv=Bp)=BWRB+r-gVV~u~fg=4r9(|3G> z(s+Nr3p&ob3*N^Ej?9Ul)h|+R{gx!5*k%O^;n>lla z1y7^NS_|vLzm2R1aS&eeX&7cNHwW$Kv9p+Hhq!+pDUyR1mC3##7{hXlN&sjm&*Q~3 zar@APo-U;P*QS1Y``I*ok>h@K4^yFhuR%Q&}(HYb#PmY-u6~ih$Jw zUv(R5hFe&HOOmG+6EJDq^X|~#cX@pEbku$pS#hYWT}HdK@{<+`B!ta`>J#7jK~31+ z%wSdo`OAxdu*oLg_QIyoYJ&??Njh|K_GB;aO)$g*d5fnkozgjy5tZb-cyUu+s5QZ* zTC(Vh=ZM7!GjeF>ujgE8xt5`ZQHZJ!56alhSLou8>yZZ<#vZw98jz02F9rP&tNLpM zUU#CdTl6l`NBeI=rp%4g+gHpZmlGy1wW^xl5WIXXOha}_@*tuvbb-{XJ8W^AvRKK9 zPbUjFuhflF7gmfRB=)t=M*gMg(}rw?6pc!#p=y?BT2!hc2xsAEv3wlOI@&tOg-`Vk z_s2HVQScMXR4(ASPTv=V%JUuk6QN9SApX+A?bR|%HLPB{4D+p0yVV%3<=(0CDq+yCAt~eVZRDdrU51l|TnZsjL zt0tM}@dOX9-z%B3#FH=)t>z)5jkSRrC%oT24{Lb7AY>5^2G^T`Nf*itsI`%pde*s@ zOpWCFi%8-aQ2=}8X^ntI^@@PMv7Qlhgf41UOYc91&x-DB2!|4@$?L7cx>dW&Dg^@& z*XX*e(vtn)q{%${<%*&yj_@2;e4(V7%zZb(?FEiA z$zu)~pJ-i&rXh&iV`NA%x1OX%D0Bp&3!Pkyko@Xp33loqG?jETr$_m|WYwn#H*)rp z9r)L_a+6lpLt)nqdG6|$8M)y_8e!Bi!e6BhLi`;bvCstU*TsJwigGhwMKAb%-^CyH zUr8F{)QRCV|MRdj9+Q?;io?EUya_8BK*6wHfBQ>b{?NHwKaOD0Fz1Quzma8L+bOo=nj$kR(X$K(iwAk)o%*kZ&! zw+wzv)8|movt~3sbKw*e-1w-ccZZqM>Vke?0*Y9uvMS zIhVo1kB@$<$u({3fp)*(Rnz9Dps6=gm+G%kj>#a=-VvT*PR_SaN&kwmtokmtB#>&CBfAIy*1LgVJcK& z11$b-xb+o@DjO5ABz-AA#OJ)r0Wd*2GHCI*?Vrc54A*Rm`Nm^LpqDAw5@L&J4GUra z>J8oG9H(XBKC1q%?R^rBz@3xBmKRIdrd@GOP=gbiN8sJVtQf@SvK7Mj7qiNFZ{9aJ z|6z*Y(=DS7`Vavl=Z98Jg*tuC>wH&SZS#Xi+eS(Pm)UI*wmwo|NP*2Y0O3cL zslZ4?zEFOxg3lMp-$ja^$I3AfsEz0lr+0Lfp(VugS;z!1tHV$Q> zr!RZfAW6jY#l7tK7e``DYF~?juW~U7cbZEbb#*~cHK+6Su*Nw37H((YR%M8A81r<% z!k4wXuVRH@iAiWw*W%E?Hp>r_VNk0b_F=NTB6cRO<}6()jHrn$BX?g3LM7)TQwZGj!Z#p=F;Ye65CVZ@RTXlX&hRs9eT<-1 zo>3{46o6$`Gr5rr2m4ZnekS+5i{ANKwW#unkbI*1+1!EWRV!4ns$%{e6|UZqK!y*tc-A)uj}2k>+@X==8>C@j4vzP3~AVr!|E(FZ&V=ygD@?o za(|OlG^&i&tgA8&CoZ(Bp%9R85@P3nCY0%Ph2d7h-W*n_@wLXI$N7!C>ZW>z59R0t zalQpvp_&?#?!s`8^Q$Wbn`D{Ja|Sk5<8x>oP=;ZT?Ng~>U;ldzeD({Q${hzMjitqa zuAnL%Qk8hdn2%uyGp_R4{9014P_HZi~#HE`E-CM&l9lv{eg2*a&KKFOZq5 zig}J`xJ7lF*jAqjZ@@)TevFozt1Z~>3mfK#!_Pz`b0Sx@jRW!(SzR;7r9h^;;y{Q3 zVptAiJMZ%5AVHnP%+Cgc>R;&wP@msQNO8o4I2P#3X-UxmcB`8{G@!NjooE|9WkSBV zq>lbYvNDI~fkAA{+95Jj@bWr>cV$B9k}VdiiwQlvSHyDr_5vec z4gIS*d;AU~k!8$}i1!^w0tLSM=fmer$dH(Z_n+t1k2}wD5uvTTV>oS;e{VIrllvwM zo<%U3^GkDvhV(2g3GdVL0*-1^jO>E@Zf?iqshi_PbSo%tOk-AM{t>i~{{4JQB6%^b5*p1`TCzGM|5qL2z zE-m5J9~YtiZr$apUfru=d(>XSs&cjnEapDGzaF?~dE7d07njSv zqxoeOnuc1l2!zaQK$(9;-$z0m(Q*zM&u#hM2a+s?gVrhvp<=uABe>_^j5IM85!yEu zH!4|+qyuCIh9Q#!&(xMc?BaU(2d~3A4xHZ`^!PHdnyR?snmWgaue&P zI*Sl+PcJ#8R!Q5!;W_ynK%>X=;lItVzc)4EAi)Q} zSPF_go6@3FFh_*p?c5Ix{{tYl;cZJqBM-oK-1#NV92U59e02^(R2eb^lgA-$^mz1X zZOEw9Qta)fcGOK)@ShF166Y-|T->a@f|IFGim(?17H&k|;3B%bWDKDABd(q3C29y| zmP^0u_VM_KniNSEWXZP5-dN;4Y=-NNHzDdE%DPzu{|I|%INhw2oIY8avfw!Lb##5x zi(LG($ij16YcJE1qro!QLTqTuwvu4dHPf%A`<1QG%Ichbif4ksB;iQyI=EcxS~CGs z-N;b6FQ*_LT?wg-R8J0k?@+JP9?i_ue@P5l7*B3SaL=*nFVL(c*^>Q&L_BDv715_C z92L*?u9X1PY}PTes@j2kJ?cP9`NmL*MpCCB2z)87Cd#y^BiH*CU}`rH4_PyT6eXVC z?0Tt@XUp`Th#9RXnm2W7l`#mAZi&Qtl72RdvMAP3W(qGRC;F)V+;&HerxTbrZMfuC&S;i(L-8m=s_SmC23^{l&IK$zMGqsS{0<*u<3}Hq9F8uK-%|tBUnf=E@({V8wgb8V4%)!(Rvi58w8h^+^+oTqIK5B)`|)p0|#7iOXTd-1Si(z6Zu zbnv>Z5)#Z4<0oTc7!jy&O)YjrwUl@;cJNLg8%j>gd#oC;qFX0Xe=(a7{x6=BED0B6rj`qB(NNA(hA`P|k62$l*ZMyOz= z&Z*Hu%<#vTY`WLJJc@VR7QB_1p>~=$SiQwK7>7U^Dw=%FduyyN zhw*-NYAS#@PM2*45l)+K?EoY0%`tWbmZ$TqKDR<2GOFZYg3pP|2)1}eaWQ}QeqZjV3qHgrtWapb?3Si@ltPJwVh2Mca?0?5R9J7jSk~6+JCP4 z+buYceRI41)!rs8jO(m3^p>TZUwk`uG%bMyY*VdmXv$9DL6tbH28!;5lN>h=w}&G$>-l++ zOaBQ*LG`kMo*MS~#p@caIi1_5@c4wdo&+XwWThb}NZf#=Q_@wR?73$(I@obkg{aC7 zH`QtB!w2PFsKDWsrPHPwJox7y5fU^f#?I!EoZ zmm2q4*3bUiKI<)9?;JV3skl%C&Ov_J$jUg>>r3WT+iqs}Fr5%h+MH~C{meJ#Rmx5z zr53?#y%c8aJvvm6vX2@pB8s(L%}L730s%sbNHy7e*VYKyeS_sM@^gX z)$>E2WiFw!&&j6b>8Ux7-_>$lbR`aK29>2>czq!nHj2qD5ms50nEJ1i^aM8%t}UWp z&dr1ke;;Ii=)7!|ly8`&>ucrdvOZevNv79AU3{)iQ z)v8w&M@GD($T>JCt2S~rKd9qtLwU>s&-~HjYnC9?Eb|Wa)Dfz(2E!u3(qC9G$6EMr z^#K79EdgD4UyqV<3XSH5=`%qGu3ee;x!`=u~uZn09RhmmMd!(Fv-h2IOXvg)x*)9k0Fcz5gNwC7!8pZnLxv$3RK}-kq;daR1Bl2 zuvLJBdx^XGyQ4iDIue&2!I?cp;E(Sd7omQ!;x&tATg(0x85>`x5(Fb(i!}C)DG|eV z?=`j-f1S2YTipIw@p$1~ne8=)kz84TN=__5-PS5c5>?6RGx-~mjn8R z7Ti+4c5(ZL+RU;rjKt@~fH-ba=)7^A5>LXESU@~0>~kIlq-^v+|U_Ezl!T&OgY z__%~~u{fI<9rkxLjFu&)a`%z*;KJXER-0yHBJ4_%-cm4^`{n zV*d$_fGE|nZ3j!~(+4xQB0}#m(BtE=H=p;Iniw-W(oS+AIuoWio#WEyQ*VmX_JbP1 z%^*i=oZ}7$1hS_5$8jCbj+v#-TqdXqdNZ!^*vS+d94`DaA(9B>7h|h5{$zpn%^<5H z{xR0y;Yy6wX+-#^g2_}g(w}?2hfCT7%vg;gl9Z>9))hS`{;T`f!W-`xSte1n{YaH_ z-EZgtE1s8ZRHiV!NGoxyBuKv$+dF|j`NM5Nq`Jq-1!Tg-B^j|96|`bblK!Ph{@c<5!48jo5y$7(q*jI`u|D zOgxYU@?B=f8@tM0`q9tR0B79>S)lr>(tsiz7m!5N#EUUzHM}p*FKqP8Z~D#UIa;6W z@l#5C;&p$PSijxOZn$;*4yid#q7k(JIV4L{(xT4hZ^Cie!* zroK2+Ny5^X1fpX*`$>a(-Kh6}VCCib;%L8PnLP!4uh)}#&0TWpJh0$%*`9uxs+{{C zD9~leT1o%FWlNr}3_6&oZsi_{q9a7kWMuEbKS+gJ<8n#ZeAI?d;o>h&_9r^2b8ca{ zm+abz;~4wRXFN39OI8H-Ti@c7Fo1f`EUR}?;Xfl(S-#wj&#N(v{w8~ol{rXw_>9#E29+e<~e z$T`YP?%1r#yw4pq;COubhR&YHsbuOXeSN0(AeZ{{Q%`Qa*4UqEpc7@EQlB}BZvvM~faY?1TS`>2i`RPfg+b!5M!p#gm;yU1|aLIdO% z=cO&6;2UoK+pzmK) zih0NaD(+{Ug0;~yhlTS3Rj!6wV%bZewDA-zOOVY;4gS@y(fUZcZx(2v%0 z!|Au@g7UDCU*VZg_;AlEIgo&59M1K+ew3QJhKzcHh|uytHFjTTkDscO5^G4n3lR8z zcOBqTApwI`$+)DMHUFjssn#q;^K*q$M1#J@1W9L0UhLWleYxAibX!m{=Qw@%=dS(`G<=~EPs0h zn#awl6PQOVF+WU4CtRTn4T%Ryn@17BC*kqHCQ(>43F{}HDvClO1J0Bz=YMxjLRlup zGxe<>k<3B5r+hOT;bGK85jtP5TAVTzI4V&tu}jD-{b*EzFwcAj3ERYG&QSxoqMNe<{U>=~mph zt|g!(v>vuNC=V8+p2i3d7Ljvkl6>`(;Hm8KJ6l*sv+X+|S^66}T$%(2@VhP#!a{0E z-=J@4$K@#5w?gypJbypc{KH|C)JYy2op}uUluN&_Dk^boD>?=&llcg8w;qbQpV=Y( zFYCszrOK(3K~o7hJXZBPa+yEZXeXk3pFq5JCW-$|aoXH=qszoaA%QQCW4tJo5FpX! zYKDe!BbtS{Ax~Mxi+w)&FPBz~GN3YxeZA`6yR?>1;czP8%p6)GmYFKG868(ExG!D1 zhjqH|cvENX)8ij)QRa3{$Y1~TVPRn4u`lxE{<*54Bcbe`PCjpzS&y_AoRy@i;pj*{ zMPavkMiBedQki$sP#|r(F5xxfViDkzc6vENOeRsG(OQa)30-23*hsK@ZML{%88yQB z*`9_?KouioY(IldkPA=ACJzI%>_YdEL=XO*ixOvzqijNg~%Fq+Aa{m%O?xL=#zWQ>J{G`-5t{pE|E}% z**mW_+h93bnXUcrX)N5t=6CTpe$K&FVRHLoHX#$kvJH}Pm_EiX9AKC1d&b|r*tfU+ zth`WFU;q1T13B*mrup7*Wf|?{2nQ}bvU+A^4fkm9ruMy-}bJyapw}0+b z5-M^ch-Fz04dx!uox zEeNP*yCW(C@(58jG`3t^0>Y1DYzqjOPS4jo>j|V~|M4~B%`xk$FoVjEfldD5~%kNzhx(=-l zEvuXY=Env{)N&qRnS~n5?i}*6C%8(sw%x{Ve(pv0wtG`L=7 zBfJ97w-LpjVYzbhtze+SFr7LH0hx4maa!w43lK`eabT-qZ!p>ixE~`7HOXt#WkZgQ z;9lNTMiX{TYC>+khXv6s1=$pNl}jrs;QK-xh9fl5z*~>Z=&?DhrRffZ$=ijhF*gkU z`%+sfR~c(Q3x}>&L%$mfr>Le0OGUo;9|%DdsksciI_GA^Ck(eg%m63mDXdYw68U$Y zuEW920L`EtS|LGXg1Q;56w(Q_6JUsJqrKfq+%Dk|%SvNVJhlZl$%Iio16yCka1V#n z8M@6eb%V`$@L?%;hCc}Jw;HTVh)D)Qojq()$s##BYh3STaNO_;8uNkq^E^uR!tDdyw^uU;ZA^xX*#bX8S0)lUsVw%oK_Rc4UE7flYNEmD3S*i96J=hFLN6Zij1Skk~&gGI}%@fQCYmX`jGc+^wO zfIjgr3oF6%ZfabF43&3Hg=%fp(TC4|U4*E@&C$Ny2s};bihJUDB_6P<_;}CV{)U+U zBj^=ovzFa^`f&a3g2Rvd)YsaI(W;uIQS< zX86I?6^<(04_|TsvBXZqqX9ik-zr!Cr^8MWN#=mdLt)x>Fxt$Dj0ODTsFt=>FZo?d z9y1$jhyOflc zhME6)zvK8fXJ>Zio;%jH*11skU(YOu^=u#Yfh$9P&#_oc&#m#Szor^wD*#Hi(?`7} z@ox;7zyC>iuk^(;0&2mf$gE>?TU8wI*b7{yNwMqshVhN3T(Gs zefOJZLI=;j?!R*atBl(VKW*RO)a2>^`r}@S$g*~~aoGahGgh$^Od642-+}t7sPpuh zrZ2)tL!^kKUP;9{aK}LMWjsd-2#rUMYy~z57h!UZ~ zD#%eU53k%M<2b|eXl)l!V2Od!1iUR`(`u6-d81Y65}%lrd_t{J>J~l%5){JEFG^5DBYJgxV1Gr{nn04$d~Z zmIB`*=X^Oiwn$%;Rv~kX`a?*6FzeHx{zovNrl(WJnn`bG+TMR@cnGEYtu%QAXT+y^ zzO`fZdJL0hh$mk(qX5_d$LmB@DgVu60YNy`Om1`ft7s?BLKVXhYQTqo(Bk_>bo4s6 zvxl*apMl5D_l(&$fF}VFv}0M2Q!9nU6TVE4feRAXgGp@@bdXOO(-P^K$ch&BM0IZA3txtBJL^fN_Gp0I zda$(dOl}&Hekzaj3p(drEojVL7g5>%O^t1$OMk744qIoeoQ678 zxn>uA)YFtg_(TM__%~yN9`6&^%&SO&C>~&yAd)4a2cw*Zc%mI3`J^h^(2oHSrLL|n ze+-BvEfy#a{VpTa!V}%R3Nu_%xYe76&r9RU!(i%4bLrdTsl&mZCFRp}KhLsn-EZMO z-CD!@@K6KrS}4}lXxEf@plhqg;TUo%QK9wk?LgwdN30(Y=RZlQihA13kR4_iGP%xG zH^h;AXr(USyINj-`L5-=wDhg_@=eD@f=mQ=Fq!Cj4Et*b?7$_qCVKuCM8Djb|mkWC#`<> z1#-v6a+6NJM^3u%Yffxg%%Pe47^MEtuhYE64Gmmx$XL)R-c=ZfB5;AFAy}S@AUk^Sk_RZMx#X~&Roe$jzgZ=;05?qHYf@%h#ssteL zx@>GHOf6 ze%120zHgC(#-W2_z^icMr6uh_Lr&fNPh^rybfb%tHjHJ~qKOe<^)}^m=nb7b^orW$ z62b<+!J0Z~=j`!W(IneS7x@3676r3sd4s17y>`KB9-63_S&r*jf@Tr)p2nQZHZ0<5 zWFrR?PyN=!wEnyo;as9U8o~Ge6NxsyMDYis74o3JLDk=++a@aG5H&BYRlGwC+iB_8 za~vg3+RONE!IA1h%G?qO=_F?Vh4c+j5rKp>tGjz{h485ou>T%IF0GbP!dQ24w+=i;9rG7mg{ugx47DW}R%79#X$rDXpc}KfDdY9sC{xly z8-HIZiEVhmV8o7!`ip>@uL`Xub|tK!pp)Ksf|c6ZWOa`Dx-=H0psoIIGl9$Pv6a7A z{=89;$QM6%xR3=saoico@jE8auQ?p=K7HgcJ^_a`M*9BdFVlC;5uKxUYF|r#-I?cx zS>*G>Qp4xhs=Qlt&W$=H87QK+NVzf{0{b&p^u2*Co|y*oX56AayQ+04@E zYKTJ|E>%R_0-0k6g+xh|iJ}C-+~tneuH$vtM6EO;CrIkrh5jeCEV>63)jV9Df#`|N z1kX)=@Q0%6dZP){)x^4Skh}&me)iFL|H%0TewMGk43!!{niCr^g!u^OY zhnaXZ?N&EFL8c+;r?mz(14OgqolI!!| z*ucrvb2t@T+v^O$F=N8N7H%ZyWXz+ZD?>!OYM<(NJhzGh0cHdlWX%7arkWfU1$0oV ztcYZk=_C?7kZ_Y)x=D#jZZr=Can{wh`s-{C;@UBAf{gN4fJb(>rosK1C&H~D&)BDk z1~5f%>`g!zE?kSB{)%8)%V48K=E*gy-nqktZXnuFikumNx|w2r1#pBu>6lHf7rlf` zN1LR1Yx!Cl4A&~crXX4R72IL8Y4}DokU62}%D8sG z#~wn=^<}&Q3%YIMzAcG68~0-Iv?e!*yx^WfaqUf2k`^+#l&j4aFysb^DeuJmdYt;h zvD0@j*s3gYKjYquM)w>caS7C^^M@i&cVm9MW?OP|495<-QO8Z$R^nlMT=6bgUpMNJ z;|b-(c&-F&6mqZzaxEv#%~H-A($+ZGAb$>%@(hFVazjO?@~P>-K9$i=auJG1LtGBQ zqvo2vOZ>N@T{(NGTZ{;z+$wk;BB{lfB0FDSLd8{rXz@DYso|q~CjOmw@mgqq__)?< zJKXTD;{y`;Uu}*zWyAu83?y%c#MrY4Z01)A!-IqDQaZm};|bC1@)TY^e*L~B_JVN% zB&7I@fcVu(PCSXAxYfx(;*fukc@ch-R?I5VtQ2{^Y^tsK)H0#dKbp&bMN8Q7U2%ktRQFVPd!+QnrPnOa~ zzM+6P-MjD}zY96bs1A9y?@Afx5v^>LC+L`Siv7=S_1af+ma93!RNO_W-Vgc+@zz|) z@0CSpOyw?zjY}GSWKP7S9vqf76wK5dtacGefT`S`m`1hQk`$*{(cnu>Wq_o0 zhE3MlUWA@|l-FW5Q@4y9^nIG;fsfo+W`FSyps4&y)05!A8QZKs-~y`#G;^kJ6VF*3 zhyEQ+wwP6>OUHeGP?fc`zw$!&j|6O$i?qp|yx>~|g6^WM>F_HokYxMIG`>UmPqc*$h4+Vl#fdWCS8LU%C>pU0V+e$8_XOWV7YzPUkN zm6l=~3DYo0Uw?^ZA=vq?Y#V8yThO z)e-?;_`}7J=w@sp5vxj6X+|>>vj|QM%z4t!12Hvb++w=#tug$RBcx;^j>sS?_Yy|` z>FN44^*cbOy+#fhT2Qj6Cko>4oa7>I`a(x;ZWR%YLjK?kpHmHvjcwBCZSCORC%P;W9Za|moI1*iJ<@(fiJ zhOurz=tk~-I!y_Sqg!FmdwVtBYM!NdX8MEA%F=vwijlIaVj2tsJgL?2*%d}J?fEWh zceyzpkjvM$f|c_6W$zs04IeX4Af!{!iBdL>c+}|y9oHl57^B1SIK`>oTuHbeZR5Gj zx%0X%&W@lpR^pzkNv7){+w5eZkhWo=>q$_&dd!b4{pzm5{VF9}tZbVQ4AaJLkZGv! zo?1tnW!&HwF_qNz3!UE+$(;xx?D`6=s~=n4YE!YyLdxZE-@#egKFJZ$`^SeDw8+yF z_=naK5c402&%{(TBouT8D<)n~LDIm`F9@~FCDS$Udt9ortp90c5w+;7mIp;?b-XUs zn}#R{!)Xi=P0+v@#&~2_aVTLL6=3ZVx_JnlT&2TOyEwj-2E|}<@Vgs{m^7)k1>XKq zzm4L!W_0dBLYyrUQ}>wpxGy%mT1|UN2VYp6Qn9eSkAiR<67as-A^ui8>c{MzQ0Z8{>R~CIe<1MoJ9sa^-e~ZD%Zl3a=J;3hvSL^o}{osW@ z+?yVD)n^Xn>ImOSok4lP+AhnRX?U0hQw?7RK6T@{z{W<2OQf~NiBr%S0Y2f4cN|#m ze#UICk3$=yMgLoeBFnOGQC*x7@pbGPzivN`R?Z+PEoV?PLMja3KLKe=msHS}(5&dj z`3i}~04^MxRtK%bNsb&|8oSCz5w3rIL}HM>DPj#s&)lr+L?yqS`j(J2?Wq#Ht_W}( z&;A?cqzSo302|g1d6`xM_FFw3=pR@8Wdjv#P{$&=C8)-`%=Jmc#>nOf}GPw=N)`{iEmy1=m)Z8$cPB=!#}Ip_*b)~Cn7 z?8?qTlT62DtGyvAsh)MC5P>6qU`0sY-JbJ)+jU<|=EsP&!MKhVoGNJRtRz4Vjl);~ z+o47V@F(1Q{4F`+I*2~S;P^f2RL$DLgv3UQy6C}^V*~Ihs(Nou$5TAx>EQEARSFfA z0({QPUOp9B?cQ%RDbON_qiIJp45q@^<{mB2kmau1w;)#^@ZxK65pn|T|H%I(>ylp& zB%1cJ+${MB`oHt_Jh!1kPTPk(eFST|u%m7oUQqC2=xWYn1q-dmzk2|CUp2Pp;CP*IFQj{>zRfA*z&W2G;$1WnnmMQ%F0xU9&^bCBWyd{R4 zVfT2*J}y$jDRqwKM3jvQ3qjh)J5fqG#unsAKb=&B@hDofUpDgoyJ^@@6L1fm8S0|> zKLsj9m{xNj=m^1w#~4y%!U zBB&+zcqQMwK{VBGB#9BGGU-Q5(ZGT014TIzIAYi7l_NK-4^VmZP>Am8Iz^#YgbjCR ztnFB&JR6CMulfk>-$)oe&b0L7K^{JpS>=Gd-vI@B#t30KiM;Ec+4tHrY=P#U2*Xr5 z2~Wo57js7et@c37XWE3A(pi4kVC!@?Ea$xc za4DC8J9cXluhw(ALA5K)bOWzEsTt*6*v{q!PY{vVCF{+cZnZt@&(-*)SmFba?|nHy zR}x>FzKJemgb8_inLhB(->M{5!H>HWQ0svPp0Q(;%NB3gcMHz#A0~7L;JeCqX;c8i zJz>$;0GvTmigGB>G|*UIgsr&+vNw$Z@K*@lXJ*(PWf6Hoh14M|0m|J@@GGxe^_sKz zEX5?#=3;nF-G5NlD3M)vU2_sZP3J=`pZ?w_Tm%|rJ?AM4LN#nBD4p4E$Bgv5?2=rC zqO~KWSaa55b37)vRFB*ygap|19aF^#a{_}LBWUxYvd1Zg*Or5^R{W|QINTaSBY)ki zxxZnWgu<=-p5stMUY2Y^#i`Sx;CzKC=Rp>Rk8ovuK?iuy!K>>+lwSOb#Of-fpqQHoF0VgWb2{}cw_9{ICe*H3qUHc*r?4?3CuXIm zp%{Nao&NagSs$$%)Im%fOEFr~jGBy9eQU#5gTxZw^9YNyedn_rblUpg?i80^CbnDs zUqGvoZ4HXrGRta_LkGP~kGSB`d6Gi`VJTaAG}~!2Nx~sA02oD4Q^%9{G&VfrW5Eyq zacJ;D_CMORe4E25Zuv^~o#tI1N$!`K8EOqa8(#tgT4ojIQ(WBYDB*S+)i*T;9d_3W z9&z+68Qcy^tZLcy1F4bH31l9eXoDXt-xVcU8vsLaX})_T+V^ssWR1vA9&YRY5DZ7F zuZi&*;*Os$4vX1-hMj%*d~OdgGc?t*=Bca3BLB9h>$b6x~o7uqPb zQ4M<-2*~YxvmK87CCejTyKW=6vM;eDV#_ietwlQYdcp&620JFqx6|^$n*O-x$w%m5 zBf??8MDWu!h%Png`CKvnn6A?x;JNj5$yeo`xD>qt6t)^CnOWd6V#1hr@ik(Tln4Ddk(EXYfjqo-sJ_-aOmD z*TET2J|KV2>!)2>P&@11PGX+dJ(L}e&MnhG#ncA`9h3@=KNlGTKh|PM}z+HEeHP1Z>XCVYJh87Eb_Q|AUS^b>b>->sFfr%n18fzTdC{=2z;2q zSuedXi%y|2t5MY!e)@+a%82YLYVpXmT$R=|GLiCxah_MvLo`7wHJ^Nu;iD~F&-p&= z@F4jyX?{22^`@2$rDJ$T+4IYSORE0sZ9h14p>{SQJNg}g!NGwSWTijt@mhoA;)3I( zjf-V77ZRqwG&-uLyJ21vVvcv(+HT_53*VUjBvG!*!HHM|L$-k*e+#zP!j&{4jQkFX zXn%n4Z~J%`sF90FkA{ZevzZ{$7`i7R^iaxSE+H*7%i~T6a^+`tWDJH2aSdFjguq7? z-*IlYmQBP~B zCKH2TPU`7d`2*Sa*_XRUfRR_n~f}-6IPvJ(lLE- zU4<%paDbg6<%N#>(e{d%L>n4t{7;a*TqzP4W+`tIX!jT-)>QBJ_qTT8cc5m8Fv<1Sj2OK(V9{YoS3-2nWE z!Jp!OJb)Y~c_ek`PlD(yO!jfBsFtt5#W%Y__c)IEMl*)?tdmyrtS!-CH%mll5?u+o)P zzrs$%N>*N3bz$xa!O{+ z&fml2l!uQB5)p^D3$M%Hi<eVz zCRh`G>Gk54CSCpTL2DjNMLBqb3R)~HoO1TKQG7>i3=s+%+MG+i%wNnH&Z81i6RH+P zE(6&v&e<kZ}-P2L~SBC<(G zTDns<#jXRNE%MpvP`(3z4%<)liEBkGSoY@S88V*+>AxK@ub-O_lU}Iw|GxICs;wR7 zm1;a(LxwP|&*+pmlIo>)ZQ9tdj|RDw09oRp^!isrX;YBT_KR4I$bF{Cg>iTC@0^fJ>9oM9f?#Dnnb9l%xi_<(5>W2wz}1U~)3Yi4Xes)I*u+&hCODPZgVlSD(liIF z?~c}?k?lh|ff(a*mYP?htddWLtCoFI@_#}ro`ieY67;PaC2*EgK-SE!5H1wrw2vg* z%%qG+5Xq>67-Cp3u{x?fA?e0fp%~VjT~qWx($tQk?x=MRjiGh&&!k%B%e=Q_Mv@*_ zx3k40W}`pqxA??-J{OlhWtWenl;W{F*@+vJoOkmd+sU&3KVBl7@a7r8xji@+YLgyVlWMo-$XefSVfGHJ)hL_X) ze@Jx&4wX^CuO+~pJd+};6NVsZrK(YF6bOuA8S~b?Ku=PLLk~~B!lc<9 z^EsQyy$I#a^~%NZjVhTx5W^dvqVVuDXj-uk4P3}1l3)BtWUOG+csOPq=-Jot`^i|v zacQdt=!&H%=1X9vq1gwH{7&5Df3?mXC%^pnSp*N+ciN3uVD?!E_%s&dOH87IoOTov z*tEZjnEgnWKY3jYwN6gNZz%rIRE>c+RC6yuHpHT}x|2tP+#k_|Zc@F&-{A+J79zz8^rDmZQ2%z03N-I2}GRixXC-)_8UL%w5 zAf+~|&g!8)8E$%L{-WM-NjX9+Z2ovGk}TSV6p&Jj?i|wI9PNrQpxIN82^M z3jVSj4Ln0x{ zu)9Q^xNa(G3RFHx2HC+`I}M6qJozkoNZzY(y>&;iFQza*`ui@Ry0MXSO>gF>GXj*W z8#T;|E1kRUtLeK#sy@-BY+J_EcHoW<;hx!n*vbbcXP8i~hX|;-Juf_w&7y0u0W()XC>=hnzP((@@tH3x zgPE0shHNDji38@!#PNd{?{NErbKt~=vzz^%l;Hp;r077&LvL&w^p@eYvA?ooGQHqZ1!c>i;#!Aws5Xr$-EDq19YyPM^kDXE#w&k+tAXHB_WfLPipj8sb-Wg986wsr&5GLA#hS^uPEwf

+5wYA`U2h{ej&t|ugMM%C;EEU+5SI9( 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 O;HRmkt6HNBiTodF$1I!x literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/async/parallel-burgers/parallel-burgers-05.png b/docs/en/docs/img/async/parallel-burgers/parallel-burgers-05.png new file mode 100644 index 0000000000000000000000000000000000000000..45aca8e217fee2975f9b79c58a6fd2133a9e9bff GIT binary patch literal 185116 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 z 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Î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�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 Date: Wed, 17 Aug 2022 10:48:46 +0000 Subject: [PATCH 620/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5f2f0e38c..6cd2a298c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add illustrations for Concurrent burgers and Parallel burgers. PR [#5277](https://github.com/tiangolo/fastapi/pull/5277) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Jina sponsorship. PR [#5272](https://github.com/tiangolo/fastapi/pull/5272) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, Striveworks badge. PR [#5179](https://github.com/tiangolo/fastapi/pull/5179) by [@tiangolo](https://github.com/tiangolo). * 🌐 Add Persian translation for `docs/fa/docs/index.md` and tweak right-to-left CSS. PR [#2395](https://github.com/tiangolo/fastapi/pull/2395) by [@mohsen-mahmoodi](https://github.com/mohsen-mahmoodi). From 623b0f37de152a49fa27078c1e28fd1ee80e2587 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 18 Aug 2022 17:24:28 +0200 Subject: [PATCH 621/814] =?UTF-8?q?=F0=9F=93=9D=20Remove=20unneeded=20Djan?= =?UTF-8?q?go/Flask=20references=20from=20async=20topic=20intro=20(#5280)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/async.md | 6 +----- docs/fr/docs/async.md | 4 ---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index 43473c822..95d2f755a 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -232,11 +232,7 @@ This "waiting" 🕙 is measured in microseconds, but still, summing it all, it's That's why it makes a lot of sense to use asynchronous ⏸🔀⏯ code for web APIs. -Most of the existing popular Python frameworks (including Flask and Django) were created before the new asynchronous features in Python existed. So, the ways they can be deployed support parallel execution and an older form of asynchronous execution that is not as powerful as the new capabilities. - -Even though the main specification for asynchronous web Python (ASGI) was developed at Django, to add support for WebSockets. - -That kind of asynchronicity is what made NodeJS popular (even though NodeJS is not parallel) and that's the strength of Go as a programming language. +This kind of asynchronicity is what made NodeJS popular (even though NodeJS is not parallel) and that's the strength of Go as a programming language. And that's the same level of performance you get with **FastAPI**. diff --git a/docs/fr/docs/async.md b/docs/fr/docs/async.md index 71c28b703..db88c4663 100644 --- a/docs/fr/docs/async.md +++ b/docs/fr/docs/async.md @@ -205,10 +205,6 @@ Cette "attente" 🕙 se mesure en microsecondes, mais tout de même, en cumulé C'est pourquoi il est logique d'utiliser du code asynchrone ⏸🔀⏯ pour des APIs web. -La plupart des frameworks Python existants (y compris Flask et Django) ont été créés avant que les nouvelles fonctionnalités asynchrones de Python n'existent. Donc, les façons dont ils peuvent être déployés supportent l'exécution parallèle et une ancienne forme d'exécution asynchrone qui n'est pas aussi puissante que les nouvelles fonctionnalités de Python. - -Et cela, bien que les spécifications principales du web asynchrone en Python (ou ASGI) ont été développées chez Django, pour ajouter le support des WebSockets. - Ce type d'asynchronicité est ce qui a rendu NodeJS populaire (bien que NodeJS ne soit pas parallèle) et c'est la force du Go en tant que langage de programmation. Et c'est le même niveau de performance que celui obtenu avec **FastAPI**. From a79228138bf2d3fa7b4d2cf4485b387cb833f910 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 15:26:58 +0000 Subject: [PATCH 622/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6cd2a298c..1ad350acb 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Remove unneeded Django/Flask references from async topic intro. PR [#5280](https://github.com/tiangolo/fastapi/pull/5280) by [@carltongibson](https://github.com/carltongibson). * ✨ Add illustrations for Concurrent burgers and Parallel burgers. PR [#5277](https://github.com/tiangolo/fastapi/pull/5277) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Jina sponsorship. PR [#5272](https://github.com/tiangolo/fastapi/pull/5272) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, Striveworks badge. PR [#5179](https://github.com/tiangolo/fastapi/pull/5179) by [@tiangolo](https://github.com/tiangolo). From a0d79b37068e21647b55cd2b69c2d1cb78c49638 Mon Sep 17 00:00:00 2001 From: Baskara Febrianto <41407847+bas-baskara@users.noreply.github.com> Date: Thu, 18 Aug 2022 22:53:59 +0700 Subject: [PATCH 623/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Indonesian=20trans?= =?UTF-8?q?lation=20for=20`docs/id/docs/tutorial/index.md`=20(#4705)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Baskara Febrianto Co-authored-by: Sebastián Ramírez --- docs/id/docs/tutorial/index.md | 80 ++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 docs/id/docs/tutorial/index.md diff --git a/docs/id/docs/tutorial/index.md b/docs/id/docs/tutorial/index.md new file mode 100644 index 000000000..8fec3c087 --- /dev/null +++ b/docs/id/docs/tutorial/index.md @@ -0,0 +1,80 @@ +# Tutorial - Pedoman Pengguna - Pengenalan + +Tutorial ini menunjukan cara menggunakan ***FastAPI*** dengan semua fitur-fiturnya, tahap demi tahap. + +Setiap bagian dibangun secara bertahap dari bagian sebelumnya, tetapi terstruktur untuk memisahkan banyak topik, sehingga kamu bisa secara langsung menuju ke topik spesifik untuk menyelesaikan kebutuhan API tertentu. + +Ini juga dibangun untuk digunakan sebagai referensi yang akan datang. + +Sehingga kamu dapat kembali lagi dan mencari apa yang kamu butuhkan dengan tepat. + +## Jalankan kode + +Semua blok-blok kode dapat dicopy dan digunakan langsung (Mereka semua sebenarnya adalah file python yang sudah teruji). + +Untuk menjalankan setiap contoh, copy kode ke file `main.py`, dan jalankan `uvicorn` dengan: + +

+ +**SANGAT disarankan** agar kamu menulis atau meng-copy kode, meng-editnya dan menjalankannya secara lokal. + +Dengan menggunakannya di dalam editor, benar-benar memperlihatkan manfaat dari FastAPI, melihat bagaimana sedikitnya kode yang harus kamu tulis, semua pengecekan tipe, pelengkapan otomatis, dll. + +--- + +## Install FastAPI + +Langkah pertama adalah dengan meng-install FastAPI. + +Untuk tutorial, kamu mungkin hendak meng-instalnya dengan semua pilihan fitur dan dependensinya: + +
+ +```console +$ pip install "fastapi[all]" + +---> 100% +``` + +
+ +...yang juga termasuk `uvicorn`, yang dapat kamu gunakan sebagai server yang menjalankan kodemu. + +!!! catatan + Kamu juga dapat meng-instalnya bagian demi bagian. + + Hal ini mungkin yang akan kamu lakukan ketika kamu hendak men-deploy aplikasimu ke tahap produksi: + + ``` + pip install fastapi + ``` + + Juga install `uvicorn` untk menjalankan server" + + ``` + pip install "uvicorn[standard]" + ``` + + Dan demikian juga untuk pilihan dependensi yang hendak kamu gunakan. + +## Pedoman Pengguna Lanjutan + +Tersedia juga **Pedoman Pengguna Lanjutan** yang dapat kamu baca nanti setelah **Tutorial - Pedoman Pengguna** ini. + +**Pedoman Pengguna Lanjutan**, dibangun atas hal ini, menggunakan konsep yang sama, dan mengajarkan kepadamu beberapa fitur tambahan. + +Tetapi kamu harus membaca terlebih dahulu **Tutorial - Pedoman Pengguna** (apa yang sedang kamu baca sekarang). + +Hal ini didesain sehingga kamu dapat membangun aplikasi lengkap dengan hanya **Tutorial - Pedoman Pengguna**, dan kemudian mengembangkannya ke banyak cara yang berbeda, tergantung dari kebutuhanmu, menggunakan beberapa ide-ide tambahan dari **Pedoman Pengguna Lanjutan**. From e23fa40e6c99b0550586194d4ee2ef7cc61277ab Mon Sep 17 00:00:00 2001 From: sUeharaE4 <44468359+sUeharaE4@users.noreply.github.com> Date: Fri, 19 Aug 2022 00:54:22 +0900 Subject: [PATCH 624/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Japanese=20transla?= =?UTF-8?q?tion=20for=20`docs/ja/docs/advanced/nosql-databases.md`=20(#420?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: tokusumi <41147016+tokusumi@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/ja/docs/advanced/nosql-databases.md | 156 +++++++++++++++++++++++ docs/ja/mkdocs.yml | 1 + 2 files changed, 157 insertions(+) create mode 100644 docs/ja/docs/advanced/nosql-databases.md diff --git a/docs/ja/docs/advanced/nosql-databases.md b/docs/ja/docs/advanced/nosql-databases.md new file mode 100644 index 000000000..fbd76e96b --- /dev/null +++ b/docs/ja/docs/advanced/nosql-databases.md @@ -0,0 +1,156 @@ +# NoSQL (分散 / ビッグデータ) Databases + +**FastAPI** はあらゆる NoSQLと統合することもできます。 + +ここではドキュメントベースのNoSQLデータベースである**
Couchbase**を使用した例を見てみましょう。 + +他にもこれらのNoSQLデータベースを利用することが出来ます: + +* **MongoDB** +* **Cassandra** +* **CouchDB** +* **ArangoDB** +* **ElasticSearch** など。 + +!!! tip "豆知識" + **FastAPI**と**Couchbase**を使った公式プロジェクト・ジェネレータがあります。すべて**Docker**ベースで、フロントエンドやその他のツールも含まれています: https://github.com/tiangolo/full-stack-fastapi-couchbase + +## Couchbase コンポーネントの Import + +まずはImportしましょう。今はその他のソースコードに注意を払う必要はありません。 + +```Python hl_lines="3-5" +{!../../../docs_src/nosql_databases/tutorial001.py!} +``` + +## "document type" として利用する定数の定義 + +documentで利用する固定の`type`フィールドを用意しておきます。 + +これはCouchbaseで必須ではありませんが、後々の助けになるベストプラクティスです。 + +```Python hl_lines="9" +{!../../../docs_src/nosql_databases/tutorial001.py!} +``` + +## `Bucket` を取得する関数の追加 + +**Couchbase**では、bucketはdocumentのセットで、様々な種類のものがあります。 + +Bucketは通常、同一のアプリケーション内で互いに関係を持っています。 + +リレーショナルデータベースの世界でいう"database"(データベースサーバではなく特定のdatabase)と類似しています。 + +**MongoDB** で例えると"collection"と似た概念です。 + +次のコードでは主に `Bucket` を利用してCouchbaseを操作します。 + +この関数では以下の処理を行います: + +* **Couchbase** クラスタ(1台の場合もあるでしょう)に接続 + * タイムアウトのデフォルト値を設定 +* クラスタで認証を取得 +* `Bucket` インスタンスを取得 + * タイムアウトのデフォルト値を設定 +* 作成した`Bucket`インスタンスを返却 + +```Python hl_lines="12-21" +{!../../../docs_src/nosql_databases/tutorial001.py!} +``` + +## Pydantic モデルの作成 + +**Couchbase**のdocumentは実際には単にJSONオブジェクトなのでPydanticを利用してモデルに出来ます。 + +### `User` モデル + +まずは`User`モデルを作成してみましょう: + +```Python hl_lines="24-28" +{!../../../docs_src/nosql_databases/tutorial001.py!} +``` + +このモデルは*path operation*に使用するので`hashed_password`は含めません。 + +### `UserInDB` モデル + +それでは`UserInDB`モデルを作成しましょう。 + +こちらは実際にデータベースに保存されるデータを保持します。 + +`User`モデルの持つ全ての属性に加えていくつかの属性を追加するのでPydanticの`BaseModel`を継承せずに`User`のサブクラスとして定義します: + +```Python hl_lines="31-33" +{!../../../docs_src/nosql_databases/tutorial001.py!} +``` + +!!! note "備考" + データベースに保存される`hashed_password`と`type`フィールドを`UserInDB`モデルに保持させていることに注意してください。 + + しかしこれらは(*path operation*で返却する)一般的な`User`モデルには含まれません + +## user の取得 + +それでは次の関数を作成しましょう: + +* username を取得する +* username を利用してdocumentのIDを生成する +* 作成したIDでdocumentを取得する +* documentの内容を`UserInDB`モデルに設定する + +*path operation関数*とは別に、`username`(またはその他のパラメータ)からuserを取得することだけに特化した関数を作成することで、より簡単に複数の部分で再利用したりユニットテストを追加することができます。 + +```Python hl_lines="36-42" +{!../../../docs_src/nosql_databases/tutorial001.py!} +``` + +### f-strings + +`f"userprofile::{username}"` という記載に馴染みがありませんか?これは Python の"f-string"と呼ばれるものです。 + +f-stringの`{}`の中に入れられた変数は、文字列の中に展開/注入されます。 + +### `dict` アンパック + +`UserInDB(**result.value)`という記載に馴染みがありませんか?これは`dict`の"アンパック"と呼ばれるものです。 + +これは`result.value`の`dict`からそのキーと値をそれぞれ取りキーワード引数として`UserInDB`に渡します。 + +例えば`dict`が下記のようになっていた場合: + +```Python +{ + "username": "johndoe", + "hashed_password": "some_hash", +} +``` + +`UserInDB`には次のように渡されます: + +```Python +UserInDB(username="johndoe", hashed_password="some_hash") +``` + +## **FastAPI** コードの実装 + +### `FastAPI` app の作成 + +```Python hl_lines="46" +{!../../../docs_src/nosql_databases/tutorial001.py!} +``` + +### *path operation関数*の作成 + +私たちのコードはCouchbaseを呼び出しており、実験的なPython awaitを使用していないので、私たちは`async def`ではなく通常の`def`で関数を宣言する必要があります。 + +また、Couchbaseは単一の`Bucket`オブジェクトを複数のスレッドで使用しないことを推奨していますので、単に直接Bucketを取得して関数に渡すことが出来ます。 + +```Python hl_lines="49-53" +{!../../../docs_src/nosql_databases/tutorial001.py!} +``` + +## まとめ + +他のサードパーティ製のNoSQLデータベースを利用する場合でも、そのデータベースの標準ライブラリを利用するだけで利用できます。 + +他の外部ツール、システム、APIについても同じことが言えます。 diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml index 985bb24d0..b3f18bbdd 100644 --- a/docs/ja/mkdocs.yml +++ b/docs/ja/mkdocs.yml @@ -85,6 +85,7 @@ nav: - advanced/additional-status-codes.md - advanced/response-directly.md - advanced/custom-response.md + - advanced/nosql-databases.md - advanced/conditional-openapi.md - async.md - デプロイ: From 7e3e4fa7eac3c6ec5fc085652fb633c2369076a2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 15:54:41 +0000 Subject: [PATCH 625/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1ad350acb..88becd991 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Indonesian translation for `docs/id/docs/tutorial/index.md`. PR [#4705](https://github.com/tiangolo/fastapi/pull/4705) by [@bas-baskara](https://github.com/bas-baskara). * 📝 Remove unneeded Django/Flask references from async topic intro. PR [#5280](https://github.com/tiangolo/fastapi/pull/5280) by [@carltongibson](https://github.com/carltongibson). * ✨ Add illustrations for Concurrent burgers and Parallel burgers. PR [#5277](https://github.com/tiangolo/fastapi/pull/5277) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Jina sponsorship. PR [#5272](https://github.com/tiangolo/fastapi/pull/5272) by [@tiangolo](https://github.com/tiangolo). From fc4ad71069b7a690944a7f17129ab0630173f57f Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 15:56:11 +0000 Subject: [PATCH 626/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 88becd991..abbb1584b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Japanese translation for `docs/ja/docs/advanced/nosql-databases.md`. PR [#4205](https://github.com/tiangolo/fastapi/pull/4205) by [@sUeharaE4](https://github.com/sUeharaE4). * 🌐 Add Indonesian translation for `docs/id/docs/tutorial/index.md`. PR [#4705](https://github.com/tiangolo/fastapi/pull/4705) by [@bas-baskara](https://github.com/bas-baskara). * 📝 Remove unneeded Django/Flask references from async topic intro. PR [#5280](https://github.com/tiangolo/fastapi/pull/5280) by [@carltongibson](https://github.com/carltongibson). * ✨ Add illustrations for Concurrent burgers and Parallel burgers. PR [#5277](https://github.com/tiangolo/fastapi/pull/5277) by [@tiangolo](https://github.com/tiangolo). From dc7e13846c2ddddd9b8f56bb8c20dc9be61e24e5 Mon Sep 17 00:00:00 2001 From: jaystone776 Date: Thu, 18 Aug 2022 23:57:21 +0800 Subject: [PATCH 627/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20`docs/tutorial/security/first-steps.md`=20(#3841)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/zh/docs/tutorial/security/first-steps.md | 189 ++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 190 insertions(+) create mode 100644 docs/zh/docs/tutorial/security/first-steps.md diff --git a/docs/zh/docs/tutorial/security/first-steps.md b/docs/zh/docs/tutorial/security/first-steps.md new file mode 100644 index 000000000..116572411 --- /dev/null +++ b/docs/zh/docs/tutorial/security/first-steps.md @@ -0,0 +1,189 @@ +# 安全 - 第一步 + +假设**后端** API 在某个域。 + +**前端**在另一个域,或(移动应用中)在同一个域的不同路径下。 + +并且,前端要使用后端的 **username** 与 **password** 验证用户身份。 + +固然,**FastAPI** 支持 **OAuth2** 身份验证。 + +但为了节省开发者的时间,不要只为了查找很少的内容,不得不阅读冗长的规范文档。 + +我们建议使用 **FastAPI** 的安全工具。 + +## 概览 + +首先,看看下面的代码是怎么运行的,然后再回过头来了解其背后的原理。 + +## 创建 `main.py` + +把下面的示例代码复制到 `main.py`: + +```Python +{!../../../docs_src/security/tutorial001.py!} +``` + +## 运行 + +!!! info "说明" + + 先安装 `python-multipart`。 + + 安装命令: `pip install python-multipart`。 + + 这是因为 **OAuth2** 使用**表单数据**发送 `username` 与 `password`。 + +用下面的命令运行该示例: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +## 查看文档 + +打开 API 文档: http://127.0.0.1:8000/docs。 + +界面如下图所示: + + + +!!! check "Authorize 按钮!" + + 页面右上角出现了一个「**Authorize**」按钮。 + + *路径操作*的右上角也出现了一个可以点击的小锁图标。 + +点击 **Authorize** 按钮,弹出授权表单,输入 `username` 与 `password` 及其它可选字段: + + + +!!! note "笔记" + + 目前,在表单中输入内容不会有任何反应,后文会介绍相关内容。 + +虽然此文档不是给前端最终用户使用的,但这个自动工具非常实用,可在文档中与所有 API 交互。 + +前端团队(可能就是开发者本人)可以使用本工具。 + +第三方应用与系统也可以调用本工具。 + +开发者也可以用它来调试、检查、测试应用。 + +## 密码流 + +现在,我们回过头来介绍这段代码的原理。 + +`Password` **流**是 OAuth2 定义的,用于处理安全与身份验证的方式(**流**)。 + +OAuth2 的设计目标是为了让后端或 API 独立于服务器验证用户身份。 + +但在本例中,**FastAPI** 应用会处理 API 与身份验证。 + +下面,我们来看一下简化的运行流程: + +- 用户在前端输入 `username` 与`password`,并点击**回车** +- (用户浏览器中运行的)前端把 `username` 与`password` 发送至 API 中指定的 URL(使用 `tokenUrl="token"` 声明) +- API 检查 `username` 与`password`,并用令牌(`Token`) 响应(暂未实现此功能): + - 令牌只是用于验证用户的字符串 + - 一般来说,令牌会在一段时间后过期 + - 过时后,用户要再次登录 + - 这样一来,就算令牌被人窃取,风险也较低。因为它与永久密钥不同,**在绝大多数情况下**不会长期有效 +- 前端临时将令牌存储在某个位置 +- 用户点击前端,前往前端应用的其它部件 +- 前端需要从 API 中提取更多数据: + - 为指定的端点(Endpoint)进行身份验证 + - 因此,用 API 验证身份时,要发送值为 `Bearer` + 令牌的请求头 `Authorization` + - 假如令牌为 `foobar`,`Authorization` 请求头就是: `Bearer foobar` + +## **FastAPI** 的 `OAuth2PasswordBearer` + +**FastAPI** 提供了不同抽象级别的安全工具。 + +本例使用 **OAuth2** 的 **Password** 流以及 **Bearer** 令牌(`Token`)。为此要使用 `OAuth2PasswordBearer` 类。 + +!!! info "说明" + + `Beare` 令牌不是唯一的选择。 + + 但它是最适合这个用例的方案。 + + 甚至可以说,它是适用于绝大多数用例的最佳方案,除非您是 OAuth2 的专家,知道为什么其它方案更合适。 + + 本例中,**FastAPI** 还提供了构建工具。 + +创建 `OAuth2PasswordBearer` 的类实例时,要传递 `tokenUrl` 参数。该参数包含客户端(用户浏览器中运行的前端) 的 URL,用于发送 `username` 与 `password`,并获取令牌。 + +```Python hl_lines="6" +{!../../../docs_src/security/tutorial001.py!} +``` + +!!! tip "提示" + + 在此,`tokenUrl="token"` 指向的是暂未创建的相对 URL `token`。这个相对 URL 相当于 `./token`。 + + 因为使用的是相对 URL,如果 API 位于 `https://example.com/`,则指向 `https://example.com/token`。但如果 API 位于 `https://example.com/api/v1/`,它指向的就是`https://example.com/api/v1/token`。 + + 使用相对 URL 非常重要,可以确保应用在遇到[使用代理](../../advanced/behind-a-proxy.md){.internal-link target=_blank}这样的高级用例时,也能正常运行。 + +该参数不会创建端点或*路径操作*,但会声明客户端用来获取令牌的 URL `/token` 。此信息用于 OpenAPI 及 API 文档。 + +接下来,学习如何创建实际的路径操作。 + +!!! info "说明" + + 严苛的 **Pythonista** 可能不喜欢用 `tokenUrl` 这种命名风格代替 `token_url`。 + + 这种命名方式是因为要使用与 OpenAPI 规范中相同的名字。以便在深入校验安全方案时,能通过复制粘贴查找更多相关信息。 + +`oauth2_scheme` 变量是 `OAuth2PasswordBearer` 的实例,也是**可调用项**。 + +以如下方式调用: + +```Python +oauth2_scheme(some, parameters) +``` + +因此,`Depends` 可以调用 `oauth2_scheme` 变量。 + +### 使用 + +接下来,使用 `Depends` 把 `oauth2_scheme` 传入依赖项。 + +```Python hl_lines="10" +{!../../../docs_src/security/tutorial001.py!} +``` + +该依赖项使用字符串(`str`)接收*路径操作函数*的参数 `token` 。 + +**FastAPI** 使用依赖项在 OpenAPI 概图(及 API 文档)中定义**安全方案**。 + +!!! info "技术细节" + + **FastAPI** 使用(在依赖项中声明的)类 `OAuth2PasswordBearer` 在 OpenAPI 中定义安全方案,这是因为它继承自 `fastapi.security.oauth2.OAuth2`,而该类又是继承自`fastapi.security.base.SecurityBase`。 + + 所有与 OpenAPI(及 API 文档)集成的安全工具都继承自 `SecurityBase`, 这就是为什么 **FastAPI** 能把它们集成至 OpenAPI 的原因。 + +## 实现的操作 + +FastAPI 校验请求中的 `Authorization` 请求头,核对请求头的值是不是由 `Bearer ` + 令牌组成, 并返回令牌字符串(`str`)。 + +如果没有找到 `Authorization` 请求头,或请求头的值不是 `Bearer ` + 令牌。FastAPI 直接返回 401 错误状态码(`UNAUTHORIZED`)。 + +开发者不需要检查错误信息,查看令牌是否存在,只要该函数能够执行,函数中就会包含令牌字符串。 + +正如下图所示,API 文档已经包含了这项功能: + + + +目前,暂时还没有实现验证令牌是否有效的功能,不过后文很快就会介绍的。 + +## 小结 + +看到了吧,只要多写三四行代码,就可以添加基础的安全表单。 diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index e70ec7698..9e8813d6c 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -93,6 +93,7 @@ nav: - tutorial/dependencies/global-dependencies.md - 安全性: - tutorial/security/index.md + - tutorial/security/first-steps.md - tutorial/security/get-current-user.md - tutorial/security/simple-oauth2.md - tutorial/security/oauth2-jwt.md From 8fe80e81e11f3bc9a6be7ddfe63ded5e0160c916 Mon Sep 17 00:00:00 2001 From: AdmiralDesu <49198383+AdmiralDesu@users.noreply.github.com> Date: Thu, 18 Aug 2022 18:59:02 +0300 Subject: [PATCH 628/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Russian=20translat?= =?UTF-8?q?ion=20for=20`docs/ru/docs/tutorial/background-tasks.md`=20(#485?= =?UTF-8?q?4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/ru/docs/tutorial/background-tasks.md | 102 ++++++++++++++++++++++ docs/ru/mkdocs.yml | 4 + 2 files changed, 106 insertions(+) create mode 100644 docs/ru/docs/tutorial/background-tasks.md diff --git a/docs/ru/docs/tutorial/background-tasks.md b/docs/ru/docs/tutorial/background-tasks.md new file mode 100644 index 000000000..e608f6c8f --- /dev/null +++ b/docs/ru/docs/tutorial/background-tasks.md @@ -0,0 +1,102 @@ +# Фоновые задачи + +Вы можете создавать фоновые задачи, которые будут выполнятся *после* возвращения ответа сервером. + +Это может быть полезно для функций, которые должны выполниться после получения запроса, но ожидание их выполнения необязательно для пользователя. + +К примеру: + +* Отправка писем на почту после выполнения каких-либо действий: + * Т.к. соединение с почтовым сервером и отправка письма идут достаточно "долго" (несколько секунд), вы можете отправить ответ пользователю, а отправку письма выполнить в фоне. +* Обработка данных: + * К примеру, если вы получаете файл, который должен пройти через медленный процесс, вы можете отправить ответ "Accepted" (HTTP 202) и отправить работу с файлом в фон. + +## Использование класса `BackgroundTasks` + +Сначала импортируйте `BackgroundTasks`, потом добавьте в функцию параметр с типом `BackgroundTasks`: + +```Python hl_lines="1 13" +{!../../../docs_src/background_tasks/tutorial001.py!} +``` + +**FastAPI** создаст объект класса `BackgroundTasks` для вас и запишет его в параметр. + +## Создание функции для фоновой задачи + +Создайте функцию, которую хотите запустить в фоне. + +Это совершенно обычная функция, которая может принимать параметры. + +Она может быть как асинхронной `async def`, так и обычной `def` функцией, **FastAPI** знает, как правильно ее выполнить. + +В нашем примере фоновая задача будет вести запись в файл (симулируя отправку письма). + +Так как операция записи не использует `async` и `await`, мы определим ее как обычную `def`: + +```Python hl_lines="6-9" +{!../../../docs_src/background_tasks/tutorial001.py!} +``` + +## Добавление фоновой задачи + +Внутри функции вызовите метод `.add_task()` у объекта *background tasks* и передайте ему функцию, которую хотите выполнить в фоне: + +```Python hl_lines="14" +{!../../../docs_src/background_tasks/tutorial001.py!} +``` + +`.add_task()` принимает следующие аргументы: + +* Функцию, которая будет выполнена в фоне (`write_notification`). Обратите внимание, что передается объект функции, без скобок. +* Любое упорядоченное количество аргументов, которые принимает функция (`email`). +* Любое количество именованных аргументов, которые принимает функция (`message="some notification"`). + +## Встраивание зависимостей + +Класс `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете определить `BackgroundTasks` на разных уровнях: как параметр функции, как завимость, как подзависимость и так далее. + +**FastAPI** знает, что нужно сделать в каждом случае и как переиспользовать тот же объект `BackgroundTasks`, так чтобы все фоновые задачи собрались и запустились вместе в фоне: + +=== "Python 3.6 и выше" + + ```Python hl_lines="13 15 22 25" + {!> ../../../docs_src/background_tasks/tutorial002.py!} + ``` + +=== "Python 3.10 и выше" + + ```Python hl_lines="11 13 20 23" + {!> ../../../docs_src/background_tasks/tutorial002_py310.py!} + ``` + +В этом примере сообщения будут записаны в `log.txt` *после* того, как ответ сервера был отправлен. + +Если бы в запросе была очередь `q`, она бы первой записалась в `log.txt` фоновой задачей (потому что вызывается в зависимости `get_query`). + +После другая фоновая задача, которая была сгенерирована в функции, запишет сообщение из параметра `email`. + +## Технические детали + +Класс `BackgroundTasks` основан на `starlette.background`. + +Он интегрирован в FastAPI, так что вы можете импортировать его прямо из `fastapi` и избежать случайного импорта `BackgroundTask` (без `s` на конце) из `starlette.background`. + +При использовании `BackgroundTasks` (а не `BackgroundTask`), вам достаточно только определить параметр функции с типом `BackgroundTasks` и **FastAPI** сделает все за вас, также как при использовании объекта `Request`. + +Вы все равно можете использовать `BackgroundTask` из `starlette` в FastAPI, но вам придется самостоятельно создавать объект фоновой задачи и вручную обработать `Response` внутри него. + +Вы можете подробнее изучить его в Официальной документации Starlette для BackgroundTasks. + +## Предостережение + +Если вам нужно выполнить тяжелые вычисления в фоне, которым необязательно быть запущенными в одном процессе с приложением **FastAPI** (к примеру, вам не нужны обрабатываемые переменные или вы не хотите делиться памятью процесса и т.д.), вы можете использовать более серьезные инструменты, такие как Celery. + +Их тяжелее настраивать, также им нужен брокер сообщений наподобие RabbitMQ или Redis, но зато они позволяют вам запускать фоновые задачи в нескольких процессах и даже на нескольких серверах. + +Для примера, посмотрите [Project Generators](../project-generation.md){.internal-link target=_blank}, там есть проект с уже настроенным Celery. + +Но если вам нужен доступ к общим переменным и объектам вашего **FastAPI** приложения или вам нужно выполнять простые фоновые задачи (наподобие отправки письма из примера) вы можете просто использовать `BackgroundTasks`. + +## Резюме + +Для создания фоновых задач вам необходимо импортировать `BackgroundTasks` и добавить его в функцию, как параметр с типом `BackgroundTasks`. diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 2150d5c19..f70b436d2 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -58,6 +58,10 @@ nav: - tr: /tr/ - uk: /uk/ - zh: /zh/ +- python-types.md +- Учебник - руководство пользователя: + - tutorial/background-tasks.md +- external-links.md - async.md markdown_extensions: - toc: From b862639ce9eebcd113d0d16806c3f63a036bdd34 Mon Sep 17 00:00:00 2001 From: Atiab Bin Zakaria <61742543+atiabbz@users.noreply.github.com> Date: Thu, 18 Aug 2022 23:59:50 +0800 Subject: [PATCH 629/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20in=20`docs/en/?= =?UTF-8?q?docs/python-types.md`=20(#5007)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/python-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index 963fcaf1c..f170bb1ef 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -267,7 +267,7 @@ You can declare that a variable can be any of **several types**, for example, an In Python 3.6 and above (including Python 3.10) you can use the `Union` type from `typing` and put inside the square brackets the possible types to accept. -In Python 3.10 there's also an **alternative syntax** were you can put the possible types separated by a vertical bar (`|`). +In Python 3.10 there's also an **alternative syntax** where you can put the possible types separated by a vertical bar (`|`). === "Python 3.6 and above" From 65e4286bc9d00ccd640383f0cd265c6c534a7b30 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:00:22 +0000 Subject: [PATCH 630/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index abbb1584b..976b96e22 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for `docs/tutorial/security/first-steps.md`. PR [#3841](https://github.com/tiangolo/fastapi/pull/3841) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/nosql-databases.md`. PR [#4205](https://github.com/tiangolo/fastapi/pull/4205) by [@sUeharaE4](https://github.com/sUeharaE4). * 🌐 Add Indonesian translation for `docs/id/docs/tutorial/index.md`. PR [#4705](https://github.com/tiangolo/fastapi/pull/4705) by [@bas-baskara](https://github.com/bas-baskara). * 📝 Remove unneeded Django/Flask references from async topic intro. PR [#5280](https://github.com/tiangolo/fastapi/pull/5280) by [@carltongibson](https://github.com/carltongibson). From 48ca7a6368f7e5bf4d8a6eb3bf3cc321d6cf8b6d Mon Sep 17 00:00:00 2001 From: Ruidy Date: Thu, 18 Aug 2022 18:01:14 +0200 Subject: [PATCH 631/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20French=20translati?= =?UTF-8?q?on=20for=20`docs/fr/docs/history-design-future.md`=20(#3451)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sam Courtemanche Co-authored-by: Arthur Rio Co-authored-by: Ruidy Co-authored-by: Ruidy --- docs/fr/docs/history-design-future.md | 79 +++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 80 insertions(+) create mode 100644 docs/fr/docs/history-design-future.md diff --git a/docs/fr/docs/history-design-future.md b/docs/fr/docs/history-design-future.md new file mode 100644 index 000000000..b77664be6 --- /dev/null +++ b/docs/fr/docs/history-design-future.md @@ -0,0 +1,79 @@ +# Histoire, conception et avenir + +Il y a quelque temps, un utilisateur de **FastAPI** a demandé : + +> Quelle est l'histoire de ce projet ? Il semble être sorti de nulle part et est devenu génial en quelques semaines [...]. + +Voici un petit bout de cette histoire. + +## Alternatives + +Je crée des API avec des exigences complexes depuis plusieurs années (Machine Learning, systèmes distribués, jobs asynchrones, bases de données NoSQL, etc), en dirigeant plusieurs équipes de développeurs. + +Dans ce cadre, j'ai dû étudier, tester et utiliser de nombreuses alternatives. + +L'histoire de **FastAPI** est en grande partie l'histoire de ses prédécesseurs. + +Comme dit dans la section [Alternatives](alternatives.md){.internal-link target=\_blank} : + +
+ +**FastAPI** n'existerait pas sans le travail antérieur d'autres personnes. + +Il y a eu de nombreux outils créés auparavant qui ont contribué à inspirer sa création. + +J'ai évité la création d'un nouveau framework pendant plusieurs années. J'ai d'abord essayé de résoudre toutes les fonctionnalités couvertes par **FastAPI** en utilisant de nombreux frameworks, plug-ins et outils différents. + +Mais à un moment donné, il n'y avait pas d'autre option que de créer quelque chose qui offre toutes ces fonctionnalités, en prenant les meilleures idées des outils précédents, et en les combinant de la meilleure façon possible, en utilisant des fonctionnalités du langage qui n'étaient même pas disponibles auparavant (annotations de type pour Python 3.6+). + +
+ +## Recherche + +En utilisant toutes les alternatives précédentes, j'ai eu la chance d'apprendre de toutes, de prendre des idées, et de les combiner de la meilleure façon que j'ai pu trouver pour moi-même et les équipes de développeurs avec lesquelles j'ai travaillé. + +Par exemple, il était clair que l'idéal était de se baser sur les annotations de type Python standard. + +De plus, la meilleure approche était d'utiliser des normes déjà existantes. + +Ainsi, avant même de commencer à coder **FastAPI**, j'ai passé plusieurs mois à étudier les spécifications d'OpenAPI, JSON Schema, OAuth2, etc. Comprendre leurs relations, leurs similarités et leurs différences. + +## Conception + +Ensuite, j'ai passé du temps à concevoir l'"API" de développeur que je voulais avoir en tant qu'utilisateur (en tant que développeur utilisant FastAPI). + +J'ai testé plusieurs idées dans les éditeurs Python les plus populaires : PyCharm, VS Code, les éditeurs basés sur Jedi. + +D'après la dernière Enquête Développeurs Python, cela couvre environ 80% des utilisateurs. + +Cela signifie que **FastAPI** a été spécifiquement testé avec les éditeurs utilisés par 80% des développeurs Python. Et comme la plupart des autres éditeurs ont tendance à fonctionner de façon similaire, tous ses avantages devraient fonctionner pour pratiquement tous les éditeurs. + +Ainsi, j'ai pu trouver les meilleurs moyens de réduire autant que possible la duplication du code, d'avoir la complétion partout, les contrôles de type et d'erreur, etc. + +Le tout de manière à offrir la meilleure expérience de développement à tous les développeurs. + +## Exigences + +Après avoir testé plusieurs alternatives, j'ai décidé que j'allais utiliser **Pydantic** pour ses avantages. + +J'y ai ensuite contribué, pour le rendre entièrement compatible avec JSON Schema, pour supporter différentes manières de définir les déclarations de contraintes, et pour améliorer le support des éditeurs (vérifications de type, autocomplétion) sur la base des tests effectués dans plusieurs éditeurs. + +Pendant le développement, j'ai également contribué à **Starlette**, l'autre exigence clé. + +## Développement + +Au moment où j'ai commencé à créer **FastAPI** lui-même, la plupart des pièces étaient déjà en place, la conception était définie, les exigences et les outils étaient prêts, et la connaissance des normes et des spécifications était claire et fraîche. + +## Futur + +À ce stade, il est déjà clair que **FastAPI** et ses idées sont utiles pour de nombreuses personnes. + +Elle a été préférée aux solutions précédentes parce qu'elle convient mieux à de nombreux cas d'utilisation. + +De nombreux développeurs et équipes dépendent déjà de **FastAPI** pour leurs projets (y compris moi et mon équipe). + +Mais il y a encore de nombreuses améliorations et fonctionnalités à venir. + +**FastAPI** a un grand avenir devant lui. + +Et [votre aide](help-fastapi.md){.internal-link target=\_blank} est grandement appréciée. diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 53d1b2c58..32ce30ef6 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -72,6 +72,7 @@ nav: - deployment/docker.md - project-generation.md - alternatives.md +- history-design-future.md - external-links.md markdown_extensions: - toc: From b489b327b8e753d8b17fc17dab86f5c78d17533b Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:01:57 +0000 Subject: [PATCH 632/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 976b96e22..bad8aca0d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Russian translation for `docs/ru/docs/tutorial/background-tasks.md`. PR [#4854](https://github.com/tiangolo/fastapi/pull/4854) by [@AdmiralDesu](https://github.com/AdmiralDesu). * 🌐 Add Chinese translation for `docs/tutorial/security/first-steps.md`. PR [#3841](https://github.com/tiangolo/fastapi/pull/3841) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/nosql-databases.md`. PR [#4205](https://github.com/tiangolo/fastapi/pull/4205) by [@sUeharaE4](https://github.com/sUeharaE4). * 🌐 Add Indonesian translation for `docs/id/docs/tutorial/index.md`. PR [#4705](https://github.com/tiangolo/fastapi/pull/4705) by [@bas-baskara](https://github.com/bas-baskara). From 5d0e2f58e711979175fa2793bbdf9d08b520730d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Sim=C3=B5es?= <66239468+frnsimoes@users.noreply.github.com> Date: Thu, 18 Aug 2022 13:02:20 -0300 Subject: [PATCH 633/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`tutorial/handling-errors.md`=20(#4769)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lucas <61513630+lsglucas@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/handling-errors.md | 251 +++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 252 insertions(+) create mode 100644 docs/pt/docs/tutorial/handling-errors.md diff --git a/docs/pt/docs/tutorial/handling-errors.md b/docs/pt/docs/tutorial/handling-errors.md new file mode 100644 index 000000000..97a2e3eac --- /dev/null +++ b/docs/pt/docs/tutorial/handling-errors.md @@ -0,0 +1,251 @@ +# Manipulação de erros + +Há diversas situações em que você precisa notificar um erro a um cliente que está utilizando a sua API. + +Esse cliente pode ser um browser com um frontend, o código de outra pessoa, um dispositivo IoT, etc. + +Pode ser que você precise comunicar ao cliente que: + +* O cliente não tem direitos para realizar aquela operação. +* O cliente não tem acesso aquele recurso. +* O item que o cliente está tentando acessar não existe. +* etc. + + +Nesses casos, você normalmente retornaria um **HTTP status code** próximo ao status code na faixa do status code **400** (do 400 ao 499). + +Isso é bastante similar ao caso do HTTP status code 200 (do 200 ao 299). Esses "200" status codes significam que, de algum modo, houve sucesso na requisição. + +Os status codes na faixa dos 400 significam que houve um erro por parte do cliente. + +Você se lembra de todos aqueles erros (e piadas) a respeito do "**404 Not Found**"? + +## Use o `HTTPException` + +Para retornar ao cliente *responses* HTTP com erros, use o `HTTPException`. + +### Import `HTTPException` + +```Python hl_lines="1" +{!../../../docs_src/handling_errors/tutorial001.py!} +``` + +### Lance o `HTTPException` no seu código. + +`HTTPException`, ao fundo, nada mais é do que a conjunção entre uma exceção comum do Python e informações adicionais relevantes para APIs. + +E porque é uma exceção do Python, você não **retorna** (return) o `HTTPException`, você lança o (raise) no seu código. + +Isso também significa que, se você está escrevendo uma função de utilidade, a qual você está chamando dentro da sua função de operações de caminhos, e você lança o `HTTPException` dentro da função de utilidade, o resto do seu código não será executado dentro da função de operações de caminhos. Ao contrário, o `HTTPException` irá finalizar a requisição no mesmo instante e enviará o erro HTTP oriundo do `HTTPException` para o cliente. + +O benefício de lançar uma exceção em vez de retornar um valor ficará mais evidente na seção sobre Dependências e Segurança. + +Neste exemplo, quando o cliente pede, na requisição, por um item cujo ID não existe, a exceção com o status code `404` é lançada: + +```Python hl_lines="11" +{!../../../docs_src/handling_errors/tutorial001.py!} +``` + +### A response resultante + + +Se o cliente faz uma requisição para `http://example.com/items/foo` (um `item_id` `"foo"`), esse cliente receberá um HTTP status code 200, e uma resposta JSON: + + +``` +{ + "item": "The Foo Wrestlers" +} +``` + +Mas se o cliente faz uma requisição para `http://example.com/items/bar` (ou seja, um não existente `item_id "bar"`), esse cliente receberá um HTTP status code 404 (o erro "não encontrado" — *not found error*), e uma resposta JSON: + +```JSON +{ + "detail": "Item not found" +} +``` + +!!! tip "Dica" + Quando você lançar um `HTTPException`, você pode passar qualquer valor convertível em JSON como parâmetro de `detail`, e não apenas `str`. + + Você pode passar um `dict` ou um `list`, etc. + Esses tipos de dados são manipulados automaticamente pelo **FastAPI** e convertidos em JSON. + + +## Adicione headers customizados + +Há certas situações em que é bastante útil poder adicionar headers customizados no HTTP error. Exemplo disso seria adicionar headers customizados para tipos de segurança. + +Você provavelmente não precisará utilizar esses headers diretamente no seu código. + +Mas caso você precise, para um cenário mais complexo, você pode adicionar headers customizados: + +```Python hl_lines="14" +{!../../../docs_src/handling_errors/tutorial002.py!} +``` + +## Instalando manipuladores de exceções customizados + +Você pode adicionar manipuladores de exceção customizados com a mesma seção de utilidade de exceções presentes no Starlette + +Digamos que você tenha uma exceção customizada `UnicornException` que você (ou uma biblioteca que você use) precise lançar (`raise`). + +Nesse cenário, se você precisa manipular essa exceção de modo global com o FastAPI, você pode adicionar um manipulador de exceção customizada com `@app.exception_handler()`. + +```Python hl_lines="5-7 13-18 24" +{!../../../docs_src/handling_errors/tutorial003.py!} +``` + +Nesse cenário, se você fizer uma requisição para `/unicorns/yolo`, a *operação de caminho* vai lançar (`raise`) o `UnicornException`. + +Essa exceção será manipulada, contudo, pelo `unicorn_exception_handler`. + +Dessa forma você receberá um erro "limpo", com o HTTP status code `418` e um JSON com o conteúdo: + +```JSON +{"message": "Oops! yolo did something. There goes a rainbow..."} +``` + +!!! note "Detalhes Técnicos" + Você também pode usar `from starlette.requests import Request` and `from starlette.responses import JSONResponse`. + + **FastAPI** disponibiliza o mesmo `starlette.responses` através do `fastapi.responses` por conveniência ao desenvolvedor. Contudo, a maior parte das respostas disponíveis vem diretamente do Starlette. O mesmo acontece com o `Request`. + +## Sobrescreva o manipulador padrão de exceções + +**FastAPI** tem alguns manipuladores padrão de exceções. + +Esses manipuladores são os responsáveis por retornar o JSON padrão de respostas quando você lança (`raise`) o `HTTPException` e quando a requisição tem dados invalidos. + +Você pode sobrescrever esses manipuladores de exceção com os seus próprios manipuladores. + +## Sobrescreva exceções de validação da requisição + +Quando a requisição contém dados inválidos, **FastAPI** internamente lança para o `RequestValidationError`. + +Para sobrescrevê-lo, importe o `RequestValidationError` e use-o com o `@app.exception_handler(RequestValidationError)` para decorar o manipulador de exceções. + +```Python hl_lines="2 14-16" +{!../../../docs_src/handling_errors/tutorial004.py!} +``` + +Se você for ao `/items/foo`, em vez de receber o JSON padrão com o erro: + +```JSON +{ + "detail": [ + { + "loc": [ + "path", + "item_id" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ] +} +``` + +você receberá a versão em texto: + +``` +1 validation error +path -> item_id + value is not a valid integer (type=type_error.integer) +``` + +### `RequestValidationError` vs `ValidationError` + +!!! warning "Aviso" + Você pode pular estes detalhes técnicos caso eles não sejam importantes para você neste momento. + +`RequestValidationError` é uma subclasse do `ValidationError` existente no Pydantic. + +**FastAPI** faz uso dele para que você veja o erro no seu log, caso você utilize um modelo de Pydantic em `response_model`, e seus dados tenham erro. + +Contudo, o cliente ou usuário não terão acesso a ele. Ao contrário, o cliente receberá um "Internal Server Error" com o HTTP status code `500`. + +E assim deve ser porque seria um bug no seu código ter o `ValidationError` do Pydantic na sua *response*, ou em qualquer outro lugar do seu código (que não na requisição do cliente). + +E enquanto você conserta o bug, os clientes / usuários não deveriam ter acesso às informações internas do erro, porque, desse modo, haveria exposição de uma vulnerabilidade de segurança. + +Do mesmo modo, você pode sobreescrever o `HTTPException`. + +Por exemplo, você pode querer retornar uma *response* em *plain text* ao invés de um JSON para os seguintes erros: + +```Python hl_lines="3-4 9-11 22" +{!../../../docs_src/handling_errors/tutorial004.py!} +``` + +!!! note "Detalhes Técnicos" + Você pode usar `from starlette.responses import PlainTextResponse`. + + **FastAPI** disponibiliza o mesmo `starlette.responses` como `fastapi.responses`, como conveniência a você, desenvolvedor. Contudo, a maior parte das respostas disponíveis vem diretamente do Starlette. + + +### Use o body do `RequestValidationError`. + +O `RequestValidationError` contém o `body` que ele recebeu de dados inválidos. + +Você pode utilizá-lo enquanto desenvolve seu app para conectar o *body* e debugá-lo, e assim retorná-lo ao usuário, etc. + +Tente enviar um item inválido como este: + +```JSON +{ + "title": "towel", + "size": "XL" +} +``` + +Você receberá uma *response* informando-o de que a data é inválida, e contendo o *body* recebido: + +```JSON hl_lines="12-15" +{ + "detail": [ + { + "loc": [ + "body", + "size" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ], + "body": { + "title": "towel", + "size": "XL" + } +} +``` + +#### O `HTTPException` do FastAPI vs o `HTTPException` do Starlette. + +O **FastAPI** tem o seu próprio `HTTPException`. + +E a classe de erro `HTTPException` do **FastAPI** herda da classe de erro do `HTTPException` do Starlette. + +A diferença entre os dois é a de que o `HTTPException` do **FastAPI** permite que você adicione *headers* que serão incluídos nas *responses*. + +Esses *headers* são necessários/utilizados internamente pelo OAuth 2.0 e também por outras utilidades de segurança. + +Portanto, você pode continuar lançando o `HTTPException` do **FastAPI** normalmente no seu código. + +Porém, quando você registrar um manipulador de exceção, você deve registrá-lo através do `HTTPException` do Starlette. + +Dessa forma, se qualquer parte do código interno, extensão ou plug-in do Starlette lançar o `HTTPException`, o seu manipulador de exceção poderá capturar esse lançamento e tratá-lo. + +```Python +from starlette.exceptions import HTTPException as StarletteHTTPException +``` + +### Re-use os manipulares de exceção do **FastAPI** + +Se você quer usar a exceção em conjunto com o mesmo manipulador de exceção *default* do **FastAPI**, você pode importar e re-usar esses manipuladores de exceção do `fastapi.exception_handlers`: + +```Python hl_lines="2-5 15 21" +{!../../../docs_src/handling_errors/tutorial006.py!} +``` + +Nesse exemplo você apenas imprime (`print`) o erro com uma mensagem expressiva. Mesmo assim, dá para pegar a ideia. Você pode usar a exceção e então apenas re-usar o manipulador de exceção *default*. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 3fb834bed..5b1bdb45e 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -69,6 +69,7 @@ nav: - tutorial/extra-data-types.md - tutorial/query-params-str-validations.md - tutorial/cookie-params.md + - tutorial/handling-errors.md - Segurança: - tutorial/security/index.md - Guia de Usuário Avançado: From f9dcff1490bf3887d988589798ab42015d228d00 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:02:28 +0000 Subject: [PATCH 634/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bad8aca0d..784917dc7 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#5007](https://github.com/tiangolo/fastapi/pull/5007) by [@atiabbz](https://github.com/atiabbz). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/background-tasks.md`. PR [#4854](https://github.com/tiangolo/fastapi/pull/4854) by [@AdmiralDesu](https://github.com/AdmiralDesu). * 🌐 Add Chinese translation for `docs/tutorial/security/first-steps.md`. PR [#3841](https://github.com/tiangolo/fastapi/pull/3841) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/nosql-databases.md`. PR [#4205](https://github.com/tiangolo/fastapi/pull/4205) by [@sUeharaE4](https://github.com/sUeharaE4). From e5eb56f0b536f96dd618d3dacac1772f0f53623c Mon Sep 17 00:00:00 2001 From: Ruidy Date: Thu, 18 Aug 2022 18:02:40 +0200 Subject: [PATCH 635/814] =?UTF-8?q?=F0=9F=8C=90=20=20Add=20French=20transl?= =?UTF-8?q?ation=20for=20`docs/fr/docs/deployment/index.md`=20(#3689)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Arthur Rio Co-authored-by: Ruidy Co-authored-by: Ruidy Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/fr/docs/deployment/index.md | 28 ++++++++++++++++++++++++++++ docs/fr/mkdocs.yml | 1 + 2 files changed, 29 insertions(+) create mode 100644 docs/fr/docs/deployment/index.md diff --git a/docs/fr/docs/deployment/index.md b/docs/fr/docs/deployment/index.md new file mode 100644 index 000000000..e855adfa3 --- /dev/null +++ b/docs/fr/docs/deployment/index.md @@ -0,0 +1,28 @@ +# Déploiement - Intro + +Le déploiement d'une application **FastAPI** est relativement simple. + +## Que signifie le déploiement + +**Déployer** une application signifie effectuer les étapes nécessaires pour la rendre **disponible pour les +utilisateurs**. + +Pour une **API Web**, cela implique normalement de la placer sur une **machine distante**, avec un **programme serveur** +qui offre de bonnes performances, une bonne stabilité, _etc._, afin que vos **utilisateurs** puissent **accéder** à +l'application efficacement et sans interruption ni problème. + +Ceci contraste avec les étapes de **développement**, où vous êtes constamment en train de modifier le code, de le casser +et de le réparer, d'arrêter et de redémarrer le serveur de développement, _etc._ + +## Stratégies de déploiement + +Il existe plusieurs façons de procéder, en fonction de votre cas d'utilisation spécifique et des outils que vous +utilisez. + +Vous pouvez **déployer un serveur** vous-même en utilisant une combinaison d'outils, vous pouvez utiliser un **service +cloud** qui fait une partie du travail pour vous, ou encore d'autres options possibles. + +Je vais vous montrer certains des principaux concepts que vous devriez probablement avoir à l'esprit lors du déploiement +d'une application **FastAPI** (bien que la plupart de ces concepts s'appliquent à tout autre type d'application web). + +Vous verrez plus de détails à avoir en tête et certaines des techniques pour le faire dans les sections suivantes. ✨ diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml index 32ce30ef6..6bed7be73 100644 --- a/docs/fr/mkdocs.yml +++ b/docs/fr/mkdocs.yml @@ -69,6 +69,7 @@ nav: - tutorial/background-tasks.md - async.md - Déploiement: + - deployment/index.md - deployment/docker.md - project-generation.md - alternatives.md From d268eb201136d5e1ba188f5e9cff9b201aabb5cc Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:03:07 +0000 Subject: [PATCH 636/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 784917dc7..be1641443 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for `docs/fr/docs/history-design-future.md`. PR [#3451](https://github.com/tiangolo/fastapi/pull/3451) by [@rjNemo](https://github.com/rjNemo). * ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#5007](https://github.com/tiangolo/fastapi/pull/5007) by [@atiabbz](https://github.com/atiabbz). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/background-tasks.md`. PR [#4854](https://github.com/tiangolo/fastapi/pull/4854) by [@AdmiralDesu](https://github.com/AdmiralDesu). * 🌐 Add Chinese translation for `docs/tutorial/security/first-steps.md`. PR [#3841](https://github.com/tiangolo/fastapi/pull/3841) by [@jaystone776](https://github.com/jaystone776). From 46f5091c9f2e3c029d4aaecb43f95d5e01df6f30 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Thu, 18 Aug 2022 18:04:33 +0200 Subject: [PATCH 637/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20in=20`python-t?= =?UTF-8?q?ypes.md`=20(#5116)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/python-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index f170bb1ef..3b0ee4cf6 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -326,7 +326,7 @@ If you are using a Python version below 3.10, here's a tip from my very **subjec Both are equivalent and underneath they are the same, but I would recommend `Union` instead of `Optional` because the word "**optional**" would seem to imply that the value is optional, and it actually means "it can be `None`", even if it's not optional and is still required. -I think `Union[str, SomeType]` is more explicit about what it means. +I think `Union[SomeType, None]` is more explicit about what it means. It's just about the words and names. But those words can affect how you and your teammates think about the code. From 441b72653757d5a4e3fb77ff2ed1f5e939b4c462 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:05:11 +0000 Subject: [PATCH 638/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index be1641443..b57fa78bd 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `tutorial/handling-errors.md`. PR [#4769](https://github.com/tiangolo/fastapi/pull/4769) by [@frnsimoes](https://github.com/frnsimoes). * 🌐 Add French translation for `docs/fr/docs/history-design-future.md`. PR [#3451](https://github.com/tiangolo/fastapi/pull/3451) by [@rjNemo](https://github.com/rjNemo). * ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#5007](https://github.com/tiangolo/fastapi/pull/5007) by [@atiabbz](https://github.com/atiabbz). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/background-tasks.md`. PR [#4854](https://github.com/tiangolo/fastapi/pull/4854) by [@AdmiralDesu](https://github.com/AdmiralDesu). From 8afd291572c72d54e9daa353d0ccd0fc87cbb42f Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:05:42 +0000 Subject: [PATCH 639/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b57fa78bd..8dfa6d146 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add French translation for `docs/fr/docs/deployment/index.md`. PR [#3689](https://github.com/tiangolo/fastapi/pull/3689) by [@rjNemo](https://github.com/rjNemo). * 🌐 Add Portuguese translation for `tutorial/handling-errors.md`. PR [#4769](https://github.com/tiangolo/fastapi/pull/4769) by [@frnsimoes](https://github.com/frnsimoes). * 🌐 Add French translation for `docs/fr/docs/history-design-future.md`. PR [#3451](https://github.com/tiangolo/fastapi/pull/3451) by [@rjNemo](https://github.com/rjNemo). * ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#5007](https://github.com/tiangolo/fastapi/pull/5007) by [@atiabbz](https://github.com/atiabbz). From e90d53f6f4c455a4f2787a02a8f08b94b2b80cc0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:06:52 +0000 Subject: [PATCH 640/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8dfa6d146..aca99264b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo in `python-types.md`. PR [#5116](https://github.com/tiangolo/fastapi/pull/5116) by [@Kludex](https://github.com/Kludex). * 🌐 Add French translation for `docs/fr/docs/deployment/index.md`. PR [#3689](https://github.com/tiangolo/fastapi/pull/3689) by [@rjNemo](https://github.com/rjNemo). * 🌐 Add Portuguese translation for `tutorial/handling-errors.md`. PR [#4769](https://github.com/tiangolo/fastapi/pull/4769) by [@frnsimoes](https://github.com/frnsimoes). * 🌐 Add French translation for `docs/fr/docs/history-design-future.md`. PR [#3451](https://github.com/tiangolo/fastapi/pull/3451) by [@rjNemo](https://github.com/rjNemo). From fb849ee7ef623c4a6f581a78d46b4d4bc583d189 Mon Sep 17 00:00:00 2001 From: zhangbo Date: Fri, 19 Aug 2022 00:09:38 +0800 Subject: [PATCH 641/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20translation=20for?= =?UTF-8?q?=20`docs/zh/docs/advanced/response-cookies.md`=20(#4638)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: zhangbo --- docs/zh/docs/advanced/response-cookies.md | 47 +++++++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 48 insertions(+) create mode 100644 docs/zh/docs/advanced/response-cookies.md diff --git a/docs/zh/docs/advanced/response-cookies.md b/docs/zh/docs/advanced/response-cookies.md new file mode 100644 index 000000000..3e53c5319 --- /dev/null +++ b/docs/zh/docs/advanced/response-cookies.md @@ -0,0 +1,47 @@ +# 响应Cookies + +## 使用 `Response` 参数 + +你可以在 *路径函数* 中定义一个类型为 `Response`的参数,这样你就可以在这个临时响应对象中设置cookie了。 + +```Python hl_lines="1 8-9" +{!../../../docs_src/response_cookies/tutorial002.py!} +``` + +而且你还可以根据你的需要响应不同的对象,比如常用的 `dict`,数据库model等。 + +如果你定义了 `response_model`,程序会自动根据`response_model`来过滤和转换你响应的对象。 + +**FastAPI** 会使用这个 *临时* 响应对象去装在这些cookies信息 (同样还有headers和状态码等信息), 最终会将这些信息和通过`response_model`转化过的数据合并到最终的响应里。 + +你也可以在depend中定义`Response`参数,并设置cookie和header。 + +## 直接响应 `Response` + +你还可以在直接响应`Response`时直接创建cookies。 + +你可以参考[Return a Response Directly](response-directly.md){.internal-link target=_blank}来创建response + +然后设置Cookies,并返回: + +```Python hl_lines="10-12" +{!../../../docs_src/response_cookies/tutorial001.py!} +``` + +!!! tip + 需要注意,如果你直接反馈一个response对象,而不是使用`Response`入参,FastAPI则会直接反馈你封装的response对象。 + + 所以你需要确保你响应数据类型的正确性,如:你可以使用`JSONResponse`来兼容JSON的场景。 + + 同时,你也应当仅反馈通过`response_model`过滤过的数据。 + +### 更多信息 + +!!! note "技术细节" + 你也可以使用`from starlette.responses import Response` 或者 `from starlette.responses import JSONResponse`。 + + 为了方便开发者,**FastAPI** 封装了相同数据类型,如`starlette.responses` 和 `fastapi.responses`。不过大部分response对象都是直接引用自Starlette。 + + 因为`Response`对象可以非常便捷的设置headers和cookies,所以 **FastAPI** 同时也封装了`fastapi.Response`。 + +如果你想查看所有可用的参数和选项,可以参考 Starlette帮助文档 diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 9e8813d6c..b60a0b7a1 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -107,6 +107,7 @@ nav: - advanced/additional-status-codes.md - advanced/response-directly.md - advanced/custom-response.md + - advanced/response-cookies.md - contributing.md - help-fastapi.md - benchmarks.md From f79e6a48a19ef79d1b2368acadecd07ea309dcc5 Mon Sep 17 00:00:00 2001 From: Vini Sousa <101301034+FLAIR7@users.noreply.github.com> Date: Thu, 18 Aug 2022 13:10:25 -0300 Subject: [PATCH 642/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/pt/docs/tutorial/security/first-steps.md`?= =?UTF-8?q?=20(#4954)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/pt/docs/tutorial/security/first-steps.md | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 docs/pt/docs/tutorial/security/first-steps.md diff --git a/docs/pt/docs/tutorial/security/first-steps.md b/docs/pt/docs/tutorial/security/first-steps.md new file mode 100644 index 000000000..ed07d1c96 --- /dev/null +++ b/docs/pt/docs/tutorial/security/first-steps.md @@ -0,0 +1,181 @@ +# Segurança - Primeiros Passos + +Vamos imaginar que você tem a sua API **backend** em algum domínio. + +E você tem um **frontend** em outro domínio ou em um path diferente no mesmo domínio (ou em uma aplicação mobile). + +E você quer uma maneira de o frontend autenticar o backend, usando um **username** e **senha**. + +Nós podemos usar o **OAuth2** junto com o **FastAPI**. + +Mas, vamos poupar-lhe o tempo de ler toda a especificação apenas para achar as pequenas informações que você precisa. + +Vamos usar as ferramentas fornecidas pela **FastAPI** para lidar com segurança. + +## Como Parece + +Vamos primeiro usar o código e ver como funciona, e depois voltaremos para entender o que está acontecendo. + +## Crie um `main.py` +Copie o exemplo em um arquivo `main.py`: + +```Python +{!../../../docs_src/security/tutorial001.py!} +``` + +## Execute-o + +!!! informação + Primeiro, instale `python-multipart`. + + Ex: `pip install python-multipart`. + + Isso ocorre porque o **OAuth2** usa "dados de um formulário" para mandar o **username** e **senha**. + +Execute esse exemplo com: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +## Verifique-o + +Vá até a documentação interativa em: http://127.0.0.1:8000/docs. + +Você verá algo deste tipo: + + + +!!! marque o "botão de Autorizar!" + Você já tem um novo "botão de autorizar!". + + E seu *path operation* tem um pequeno cadeado no canto superior direito que você pode clicar. + +E se você clicar, você terá um pequeno formulário de autorização para digitar o `username` e `senha` (e outros campos opcionais): + + + +!!! nota + Não importa o que você digita no formulário, não vai funcionar ainda. Mas nós vamos chegar lá. + +Claro que este não é o frontend para os usuários finais, mas é uma ótima ferramenta automática para documentar interativamente toda sua API. + +Pode ser usado pelo time de frontend (que pode ser você no caso). + +Pode ser usado por aplicações e sistemas third party (de terceiros). + +E também pode ser usada por você mesmo, para debugar, checar e testar a mesma aplicação. + +## O Fluxo da `senha` + +Agora vamos voltar um pouco e entender o que é isso tudo. + +O "fluxo" da `senha` é um dos caminhos ("fluxos") definidos no OAuth2, para lidar com a segurança e autenticação. + +OAuth2 foi projetado para que o backend ou a API pudesse ser independente do servidor que autentica o usuário. + +Mas nesse caso, a mesma aplicação **FastAPI** irá lidar com a API e a autenticação. + +Então, vamos rever de um ponto de vista simplificado: + +* O usuário digita o `username` e a `senha` no frontend e aperta `Enter`. +* O frontend (rodando no browser do usuário) manda o `username` e a `senha` para uma URL específica na sua API (declarada com `tokenUrl="token"`). +* A API checa aquele `username` e `senha`, e responde com um "token" (nós não implementamos nada disso ainda). + * Um "token" é apenas uma string com algum conteúdo que nós podemos utilizar mais tarde para verificar o usuário. + * Normalmente, um token é definido para expirar depois de um tempo. + * Então, o usuário terá que se logar de novo depois de um tempo. + * E se o token for roubado, o risco é menor. Não é como se fosse uma chave permanente que vai funcionar para sempre (na maioria dos casos). + * O frontend armazena aquele token temporariamente em algum lugar. + * O usuário clica no frontend para ir à outra seção daquele frontend do aplicativo web. + * O frontend precisa buscar mais dados daquela API. + * Mas precisa de autenticação para aquele endpoint em específico. + * Então, para autenticar com nossa API, ele manda um header de `Autorização` com o valor `Bearer` mais o token. + * Se o token contém `foobar`, o conteúdo do header de `Autorização` será: `Bearer foobar`. + +## **FastAPI**'s `OAuth2PasswordBearer` + +**FastAPI** fornece várias ferramentas, em diferentes níveis de abstração, para implementar esses recursos de segurança. + +Neste exemplo, nós vamos usar o **OAuth2** com o fluxo de **Senha**, usando um token **Bearer**. Fazemos isso usando a classe `OAuth2PasswordBearer`. + +!!! informação + Um token "bearer" não é a única opção. + + Mas é a melhor no nosso caso. + + E talvez seja a melhor para a maioria dos casos, a não ser que você seja um especialista em OAuth2 e saiba exatamente o porquê de existir outras opções que se adequam melhor às suas necessidades. + + Nesse caso, **FastAPI** também fornece as ferramentas para construir. + +Quando nós criamos uma instância da classe `OAuth2PasswordBearer`, nós passamos pelo parâmetro `tokenUrl` Esse parâmetro contém a URL que o client (o frontend rodando no browser do usuário) vai usar para mandar o `username` e `senha` para obter um token. + +```Python hl_lines="6" +{!../../../docs_src/security/tutorial001.py!} +``` + +!!! dica + Esse `tokenUrl="token"` se refere a uma URL relativa que nós não criamos ainda. Como é uma URL relativa, é equivalente a `./token`. + + Porque estamos usando uma URL relativa, se sua API estava localizada em `https://example.com/`, então irá referir-se à `https://example.com/token`. Mas se sua API estava localizada em `https://example.com/api/v1/`, então irá referir-se à `https://example.com/api/v1/token`. + + Usar uma URL relativa é importante para garantir que sua aplicação continue funcionando, mesmo em um uso avançado tipo [Atrás de um Proxy](../../advanced/behind-a-proxy.md){.internal-link target=_blank}. + +Esse parâmetro não cria um endpoint / *path operation*, mas declara que a URL `/token` vai ser aquela que o client deve usar para obter o token. Essa informação é usada no OpenAPI, e depois na API Interativa de documentação de sistemas. + +Em breve também criaremos o atual path operation. + +!!! informação + Se você é um "Pythonista" muito rigoroso, você pode não gostar do estilo do nome do parâmetro `tokenUrl` em vez de `token_url`. + + Isso ocorre porque está utilizando o mesmo nome que está nas especificações do OpenAPI. Então, se você precisa investigar mais sobre qualquer um desses esquemas de segurança, você pode simplesmente copiar e colar para encontrar mais informações sobre isso. + +A variável `oauth2_scheme` é um instância de `OAuth2PasswordBearer`, mas também é um "callable". + +Pode ser chamada de: + +```Python +oauth2_scheme(some, parameters) +``` + +Então, pode ser usado com `Depends`. + +## Use-o + +Agora você pode passar aquele `oauth2_scheme` em uma dependência com `Depends`. + +```Python hl_lines="10" +{!../../../docs_src/security/tutorial001.py!} +``` + +Esse dependência vai fornecer uma `str` que é atribuído ao parâmetro `token da *função do path operation* + +A **FastAPI** saberá que pode usar essa dependência para definir um "esquema de segurança" no esquema da OpenAPI (e na documentação da API automática). + +!!! informação "Detalhes técnicos" + **FastAPI** saberá que pode usar a classe `OAuth2PasswordBearer` (declarada na dependência) para definir o esquema de segurança na OpenAPI porque herda de `fastapi.security.oauth2.OAuth2`, que por sua vez herda de `fastapi.security.base.Securitybase`. + + Todos os utilitários de segurança que se integram com OpenAPI (e na documentação da API automática) herdam de `SecurityBase`, é assim que **FastAPI** pode saber como integrá-los no OpenAPI. + +## O que ele faz + +Ele irá e olhará na requisição para aquele header de `Autorização`, verificará se o valor é `Bearer` mais algum token, e vai retornar o token como uma `str` + +Se ele não ver o header de `Autorização` ou o valor não tem um token `Bearer`, vai responder com um código de erro 401 (`UNAUTHORIZED`) diretamente. + +Você nem precisa verificar se o token existe para retornar um erro. Você pode ter certeza de que se a sua função for executada, ela terá um `str` nesse token. + +Você já pode experimentar na documentação interativa: + + + +Não estamos verificando a validade do token ainda, mas isso já é um começo + +## Recapitulando + +Então, em apenas 3 ou 4 linhas extras, você já tem alguma forma primitiva de segurança. From a9c2b8336b980da91e5d2a754a00c6e2fffed4d0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:11:55 +0000 Subject: [PATCH 643/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index aca99264b..0d2ed3d07 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add translation for `docs/zh/docs/advanced/response-cookies.md`. PR [#4638](https://github.com/tiangolo/fastapi/pull/4638) by [@zhangbo2012](https://github.com/zhangbo2012). * ✏ Fix typo in `python-types.md`. PR [#5116](https://github.com/tiangolo/fastapi/pull/5116) by [@Kludex](https://github.com/Kludex). * 🌐 Add French translation for `docs/fr/docs/deployment/index.md`. PR [#3689](https://github.com/tiangolo/fastapi/pull/3689) by [@rjNemo](https://github.com/rjNemo). * 🌐 Add Portuguese translation for `tutorial/handling-errors.md`. PR [#4769](https://github.com/tiangolo/fastapi/pull/4769) by [@frnsimoes](https://github.com/frnsimoes). From 30e7b6a34cf41c927979c595e90329acf9ecca7d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:12:24 +0000 Subject: [PATCH 644/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0d2ed3d07..88ec5566b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/security/first-steps.md`. PR [#4954](https://github.com/tiangolo/fastapi/pull/4954) by [@FLAIR7](https://github.com/FLAIR7). * 🌐 Add translation for `docs/zh/docs/advanced/response-cookies.md`. PR [#4638](https://github.com/tiangolo/fastapi/pull/4638) by [@zhangbo2012](https://github.com/zhangbo2012). * ✏ Fix typo in `python-types.md`. PR [#5116](https://github.com/tiangolo/fastapi/pull/5116) by [@Kludex](https://github.com/Kludex). * 🌐 Add French translation for `docs/fr/docs/deployment/index.md`. PR [#3689](https://github.com/tiangolo/fastapi/pull/3689) by [@rjNemo](https://github.com/rjNemo). From 73c6011ec47ebc2b08fd2b05c3a4acf03155d818 Mon Sep 17 00:00:00 2001 From: Bruno Artur Torres Lopes Pereira <33462923+batlopes@users.noreply.github.com> Date: Thu, 18 Aug 2022 13:13:12 -0300 Subject: [PATCH 645/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Portuguese=20trans?= =?UTF-8?q?lation=20for=20`docs/pt/docs/tutorial/query-params.md`=20(#4775?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/pt/docs/tutorial/query-params.md | 224 ++++++++++++++++++++++++++ docs/pt/mkdocs.yml | 1 + 2 files changed, 225 insertions(+) create mode 100644 docs/pt/docs/tutorial/query-params.md diff --git a/docs/pt/docs/tutorial/query-params.md b/docs/pt/docs/tutorial/query-params.md new file mode 100644 index 000000000..189724396 --- /dev/null +++ b/docs/pt/docs/tutorial/query-params.md @@ -0,0 +1,224 @@ +# Parâmetros de Consulta + +Quando você declara outros parâmetros na função que não fazem parte dos parâmetros da rota, esses parâmetros são automaticamente interpretados como parâmetros de "consulta". + +```Python hl_lines="9" +{!../../../docs_src/query_params/tutorial001.py!} +``` + +A consulta é o conjunto de pares chave-valor que vai depois de `?` na URL, separado pelo caractere `&`. + +Por exemplo, na URL: + +``` +http://127.0.0.1:8000/items/?skip=0&limit=10 +``` + +...os parâmetros da consulta são: + +* `skip`: com o valor `0` +* `limit`: com o valor `10` + +Como eles são parte da URL, eles são "naturalmente" strings. + +Mas quando você declara eles com os tipos do Python (no exemplo acima, como `int`), eles são convertidos para aquele tipo e validados em relação a ele. + +Todo o processo que era aplicado para parâmetros de rota também é aplicado para parâmetros de consulta: + +* Suporte do editor (obviamente) +* "Parsing" de dados +* Validação de dados +* Documentação automática + +## Valores padrão + +Como os parâmetros de consulta não são uma parte fixa da rota, eles podem ser opcionais e podem ter valores padrão. + +No exemplo acima eles tem valores padrão de `skip=0` e `limit=10`. + +Então, se você for até a URL: + +``` +http://127.0.0.1:8000/items/ +``` + +Seria o mesmo que ir para: + +``` +http://127.0.0.1:8000/items/?skip=0&limit=10 +``` + +Mas, se por exemplo você for para: + +``` +http://127.0.0.1:8000/items/?skip=20 +``` + +Os valores dos parâmetros na sua função serão: + +* `skip=20`: Por que você definiu isso na URL +* `limit=10`: Por que esse era o valor padrão + +## Parâmetros opcionais + +Da mesma forma, você pode declarar parâmetros de consulta opcionais, definindo o valor padrão para `None`: + +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params/tutorial002.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params/tutorial002_py310.py!} + ``` + +Nesse caso, o parâmetro da função `q` será opcional, e `None` será o padrão. + +!!! check "Verificar" + Você também pode notar que o **FastAPI** é esperto o suficiente para perceber que o parâmetro da rota `item_id` é um parâmetro da rota, e `q` não é, portanto, `q` é o parâmetro de consulta. + + +## Conversão dos tipos de parâmetros de consulta + +Você também pode declarar tipos `bool`, e eles serão convertidos: + +=== "Python 3.6 and above" + + ```Python hl_lines="9" + {!> ../../../docs_src/query_params/tutorial003.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="7" + {!> ../../../docs_src/query_params/tutorial003_py310.py!} + ``` + +Nesse caso, se você for para: + +``` +http://127.0.0.1:8000/items/foo?short=1 +``` + +ou + +``` +http://127.0.0.1:8000/items/foo?short=True +``` + +ou + +``` +http://127.0.0.1:8000/items/foo?short=true +``` + +ou + +``` +http://127.0.0.1:8000/items/foo?short=on +``` + +ou + +``` +http://127.0.0.1:8000/items/foo?short=yes +``` + +ou qualquer outra variação (tudo em maiúscula, primeira letra em maiúscula, etc), a sua função vai ver o parâmetro `short` com um valor `bool` de `True`. Caso contrário `False`. + +## Múltiplos parâmetros de rota e consulta + +Você pode declarar múltiplos parâmetros de rota e parâmetros de consulta ao mesmo tempo, o **FastAPI** vai saber o quê é o quê. + +E você não precisa declarar eles em nenhuma ordem específica. + +Eles serão detectados pelo nome: + +=== "Python 3.6 and above" + + ```Python hl_lines="8 10" + {!> ../../../docs_src/query_params/tutorial004.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="6 8" + {!> ../../../docs_src/query_params/tutorial004_py310.py!} + ``` + +## Parâmetros de consulta obrigatórios + +Quando você declara um valor padrão para parâmetros que não são de rota (até agora, nós vimos apenas parâmetros de consulta), então eles não são obrigatórios. + +Caso você não queira adicionar um valor específico mas queira apenas torná-lo opcional, defina o valor padrão como `None`. + +Porém, quando você quiser fazer com que o parâmetro de consulta seja obrigatório, você pode simplesmente não declarar nenhum valor como padrão. + +```Python hl_lines="6-7" +{!../../../docs_src/query_params/tutorial005.py!} +``` + +Aqui o parâmetro de consulta `needy` é um valor obrigatório, do tipo `str`. + +Se você abrir no seu navegador a URL: + +``` +http://127.0.0.1:8000/items/foo-item +``` + +... sem adicionar o parâmetro obrigatório `needy`, você verá um erro como: + +```JSON +{ + "detail": [ + { + "loc": [ + "query", + "needy" + ], + "msg": "field required", + "type": "value_error.missing" + } + ] +} +``` + +Como `needy` é um parâmetro obrigatório, você precisaria defini-lo na URL: + +``` +http://127.0.0.1:8000/items/foo-item?needy=sooooneedy +``` + +...isso deve funcionar: + +```JSON +{ + "item_id": "foo-item", + "needy": "sooooneedy" +} +``` + +E claro, você pode definir alguns parâmetros como obrigatórios, alguns possuindo um valor padrão, e outros sendo totalmente opcionais: + +=== "Python 3.6 and above" + + ```Python hl_lines="10" + {!> ../../../docs_src/query_params/tutorial006.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="8" + {!> ../../../docs_src/query_params/tutorial006_py310.py!} + ``` +Nesse caso, existem 3 parâmetros de consulta: + +* `needy`, um `str` obrigatório. +* `skip`, um `int` com o valor padrão `0`. +* `limit`, um `int` opcional. + +!!! tip "Dica" + Você também poderia usar `Enum` da mesma forma que com [Path Parameters](path-params.md#predefined-values){.internal-link target=_blank}. diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 5b1bdb45e..c37b855d8 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -64,6 +64,7 @@ nav: - tutorial/index.md - tutorial/first-steps.md - tutorial/path-params.md + - tutorial/query-params.md - tutorial/body.md - tutorial/body-fields.md - tutorial/extra-data-types.md From 58848897f49ac61d0ac7fdabc473e1c93eb13950 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 16:15:37 +0000 Subject: [PATCH 646/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 88ec5566b..0be6db642 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/query-params.md`. PR [#4775](https://github.com/tiangolo/fastapi/pull/4775) by [@batlopes](https://github.com/batlopes). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/security/first-steps.md`. PR [#4954](https://github.com/tiangolo/fastapi/pull/4954) by [@FLAIR7](https://github.com/FLAIR7). * 🌐 Add translation for `docs/zh/docs/advanced/response-cookies.md`. PR [#4638](https://github.com/tiangolo/fastapi/pull/4638) by [@zhangbo2012](https://github.com/zhangbo2012). * ✏ Fix typo in `python-types.md`. PR [#5116](https://github.com/tiangolo/fastapi/pull/5116) by [@Kludex](https://github.com/Kludex). From 38802eefeb7c1ef8c80373a7a07a7cb402946228 Mon Sep 17 00:00:00 2001 From: Yumihiki <41376154+Yumihiki@users.noreply.github.com> Date: Fri, 19 Aug 2022 01:16:54 +0900 Subject: [PATCH 647/814] =?UTF-8?q?=F0=9F=93=9D=20Quote=20`pip=20install`?= =?UTF-8?q?=20command=20for=20Zsh=20compatibility=20in=20multiple=20langua?= =?UTF-8?q?ges=20(#5214)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/de/docs/index.md | 2 +- docs/es/docs/index.md | 2 +- docs/es/docs/tutorial/index.md | 4 ++-- docs/fr/docs/index.md | 2 +- docs/id/docs/index.md | 2 +- docs/it/docs/index.md | 2 +- docs/ja/docs/deployment/manually.md | 2 +- docs/ja/docs/index.md | 2 +- docs/ja/docs/tutorial/index.md | 4 ++-- docs/ko/docs/index.md | 2 +- docs/ko/docs/tutorial/index.md | 2 +- docs/pl/docs/index.md | 2 +- docs/pt/docs/deployment.md | 2 +- docs/pt/docs/index.md | 2 +- docs/pt/docs/tutorial/index.md | 4 ++-- docs/ru/docs/index.md | 2 +- docs/sq/docs/index.md | 2 +- docs/tr/docs/index.md | 2 +- docs/uk/docs/index.md | 2 +- docs/zh/docs/index.md | 2 +- docs/zh/docs/tutorial/index.md | 4 ++-- 21 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/de/docs/index.md b/docs/de/docs/index.md index 929754462..287c79cff 100644 --- a/docs/de/docs/index.md +++ b/docs/de/docs/index.md @@ -135,7 +135,7 @@ You will also need an ASGI server, for production such as ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/es/docs/index.md b/docs/es/docs/index.md index ef4850b56..44c59202a 100644 --- a/docs/es/docs/index.md +++ b/docs/es/docs/index.md @@ -130,7 +130,7 @@ También vas a necesitar un servidor ASGI para producción cómo ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/es/docs/tutorial/index.md b/docs/es/docs/tutorial/index.md index 9cbdb2727..e3671f381 100644 --- a/docs/es/docs/tutorial/index.md +++ b/docs/es/docs/tutorial/index.md @@ -41,7 +41,7 @@ Para el tutorial, es posible que quieras instalarlo con todas las dependencias y
```console -$ pip install fastapi[all] +$ pip install "fastapi[all]" ---> 100% ``` @@ -62,7 +62,7 @@ $ pip install fastapi[all] También debes instalar `uvicorn` para que funcione como tu servidor: ``` - pip install uvicorn[standard] + pip install "uvicorn[standard]" ``` Y lo mismo para cada una de las dependencias opcionales que quieras utilizar. diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md index f713ee96b..1307c063b 100644 --- a/docs/fr/docs/index.md +++ b/docs/fr/docs/index.md @@ -135,7 +135,7 @@ You will also need an ASGI server, for production such as ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/id/docs/index.md b/docs/id/docs/index.md index 0bb7b55e3..041e0b754 100644 --- a/docs/id/docs/index.md +++ b/docs/id/docs/index.md @@ -135,7 +135,7 @@ You will also need an ASGI server, for production such as ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/it/docs/index.md b/docs/it/docs/index.md index 6acf92552..5cbe78a71 100644 --- a/docs/it/docs/index.md +++ b/docs/it/docs/index.md @@ -135,7 +135,7 @@ You will also need an ASGI server, for production such as ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/ja/docs/deployment/manually.md b/docs/ja/docs/deployment/manually.md index dd4b568bd..67010a66f 100644 --- a/docs/ja/docs/deployment/manually.md +++ b/docs/ja/docs/deployment/manually.md @@ -11,7 +11,7 @@
```console - $ pip install uvicorn[standard] + $ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/ja/docs/index.md b/docs/ja/docs/index.md index 5fca78a83..51977037c 100644 --- a/docs/ja/docs/index.md +++ b/docs/ja/docs/index.md @@ -131,7 +131,7 @@ $ pip install fastapi
```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/ja/docs/tutorial/index.md b/docs/ja/docs/tutorial/index.md index 29fc86f94..a2dd59c9b 100644 --- a/docs/ja/docs/tutorial/index.md +++ b/docs/ja/docs/tutorial/index.md @@ -43,7 +43,7 @@ $ uvicorn main:app --reload
```console -$ pip install fastapi[all] +$ pip install "fastapi[all]" ---> 100% ``` @@ -64,7 +64,7 @@ $ pip install fastapi[all] また、サーバーとして動作するように`uvicorn` をインストールします: ``` - pip install uvicorn[standard] + pip install "uvicorn[standard]" ``` そして、使用したい依存関係をそれぞれ同様にインストールします。 diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md index ec4422994..5a258f47b 100644 --- a/docs/ko/docs/index.md +++ b/docs/ko/docs/index.md @@ -131,7 +131,7 @@ $ pip install fastapi
```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/ko/docs/tutorial/index.md b/docs/ko/docs/tutorial/index.md index 622aad1aa..d6db525e8 100644 --- a/docs/ko/docs/tutorial/index.md +++ b/docs/ko/docs/tutorial/index.md @@ -43,7 +43,7 @@ $ uvicorn main:app --reload
```console -$ pip install fastapi[all] +$ pip install "fastapi[all]" ---> 100% ``` diff --git a/docs/pl/docs/index.md b/docs/pl/docs/index.md index bbe1b1ad1..9cc99ba72 100644 --- a/docs/pl/docs/index.md +++ b/docs/pl/docs/index.md @@ -130,7 +130,7 @@ Na serwerze produkcyjnym będziesz także potrzebował serwera ASGI, np. ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/pt/docs/deployment.md b/docs/pt/docs/deployment.md index cd820cbd3..2272467fd 100644 --- a/docs/pt/docs/deployment.md +++ b/docs/pt/docs/deployment.md @@ -336,7 +336,7 @@ Você apenas precisa instalar um servidor ASGI compatível como:
```console - $ pip install uvicorn[standard] + $ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md index b1d0c89f2..51af486b9 100644 --- a/docs/pt/docs/index.md +++ b/docs/pt/docs/index.md @@ -124,7 +124,7 @@ Você também precisará de um servidor ASGI para produção, tal como ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/pt/docs/tutorial/index.md b/docs/pt/docs/tutorial/index.md index f93fd8d75..b1abd32bc 100644 --- a/docs/pt/docs/tutorial/index.md +++ b/docs/pt/docs/tutorial/index.md @@ -43,7 +43,7 @@ Para o tutorial, você deve querer instalá-lo com todas as dependências e recu
```console -$ pip install fastapi[all] +$ pip install "fastapi[all]" ---> 100% ``` @@ -64,7 +64,7 @@ $ pip install fastapi[all] Também instale o `uvicorn` para funcionar como servidor: ``` - pip install uvicorn[standard] + pip install "uvicorn[standard]" ``` E o mesmo para cada dependência opcional que você quiser usar. diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index 9a3957d5f..932bb2139 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -135,7 +135,7 @@ You will also need an ASGI server, for production such as ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/sq/docs/index.md b/docs/sq/docs/index.md index 29f92e020..2b64003fe 100644 --- a/docs/sq/docs/index.md +++ b/docs/sq/docs/index.md @@ -135,7 +135,7 @@ You will also need an ASGI server, for production such as ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md index 5693029b5..0d5337c87 100644 --- a/docs/tr/docs/index.md +++ b/docs/tr/docs/index.md @@ -143,7 +143,7 @@ Uygulamanı kullanılabilir hale getirmek için ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/uk/docs/index.md b/docs/uk/docs/index.md index 29f92e020..2b64003fe 100644 --- a/docs/uk/docs/index.md +++ b/docs/uk/docs/index.md @@ -135,7 +135,7 @@ You will also need an ASGI server, for production such as ```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/zh/docs/index.md b/docs/zh/docs/index.md index 797032c86..3898beaee 100644 --- a/docs/zh/docs/index.md +++ b/docs/zh/docs/index.md @@ -131,7 +131,7 @@ $ pip install fastapi
```console -$ pip install uvicorn[standard] +$ pip install "uvicorn[standard]" ---> 100% ``` diff --git a/docs/zh/docs/tutorial/index.md b/docs/zh/docs/tutorial/index.md index 36495ec0b..6093caeb6 100644 --- a/docs/zh/docs/tutorial/index.md +++ b/docs/zh/docs/tutorial/index.md @@ -43,7 +43,7 @@ $ uvicorn main:app --reload
```console -$ pip install fastapi[all] +$ pip install "fastapi[all]" ---> 100% ``` @@ -64,7 +64,7 @@ $ pip install fastapi[all] 并且安装`uvicorn`来作为服务器: ``` - pip install uvicorn[standard] + pip install "uvicorn[standard]" ``` 然后对你想使用的每个可选依赖项也执行相同的操作。 From ea017c99198c73f0e4a67a758bc5113e2cca6102 Mon Sep 17 00:00:00 2001 From: Teofilo Zosa Date: Fri, 19 Aug 2022 05:12:34 +0900 Subject: [PATCH 648/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20misc=20dependency?= =?UTF-8?q?=20installs=20to=20tutorial=20docs=20(#2126)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/websockets.md | 14 ++++++++++++++ docs/en/docs/tutorial/response-model.md | 6 ++++++ docs/en/docs/tutorial/sql-databases.md | 14 ++++++++++++++ docs/en/docs/tutorial/testing.md | 5 +++++ 4 files changed, 39 insertions(+) diff --git a/docs/en/docs/advanced/websockets.md b/docs/en/docs/advanced/websockets.md index 878ad37dd..0e9bc5b06 100644 --- a/docs/en/docs/advanced/websockets.md +++ b/docs/en/docs/advanced/websockets.md @@ -2,6 +2,20 @@ You can use WebSockets with **FastAPI**. +## Install `WebSockets` + +First you need to install `WebSockets`: + +
+ +```console +$ pip install websockets + +---> 100% +``` + +
+ ## WebSockets client ### In production diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md index e371e86e4..2bbd4d4fd 100644 --- a/docs/en/docs/tutorial/response-model.md +++ b/docs/en/docs/tutorial/response-model.md @@ -61,6 +61,12 @@ Here we are declaring a `UserIn` model, it will contain a plaintext password: {!> ../../../docs_src/response_model/tutorial002_py310.py!} ``` +!!! info + To use `EmailStr`, first install `email_validator`. + + E.g. `pip install email-validator` + or `pip install pydantic[email]`. + And we are using this model to declare our input and the same model to declare our output: === "Python 3.6 and above" diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md index 3436543a5..5ccaf05ec 100644 --- a/docs/en/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -80,6 +80,20 @@ The file `__init__.py` is just an empty file, but it tells Python that `sql_app` Now let's see what each file/module does. +## Install `SQLAlchemy` + +First you need to install `SQLAlchemy`: + +
+ +```console +$ pip install sqlalchemy + +---> 100% +``` + +
+ ## Create the SQLAlchemy parts Let's refer to the file `sql_app/database.py`. diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md index fea5a54f5..79ea2b1ab 100644 --- a/docs/en/docs/tutorial/testing.md +++ b/docs/en/docs/tutorial/testing.md @@ -8,6 +8,11 @@ With it, you can use `requests`. + + E.g. `pip install requests`. + Import `TestClient`. Create a `TestClient` by passing your **FastAPI** application to it. From 3a3b61dc6e26717f824ffa4c7ace999ad96c07f0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 20:13:14 +0000 Subject: [PATCH 649/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0be6db642..b2e73d4a3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add misc dependency installs to tutorial docs. PR [#2126](https://github.com/tiangolo/fastapi/pull/2126) by [@TeoZosa](https://github.com/TeoZosa). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/query-params.md`. PR [#4775](https://github.com/tiangolo/fastapi/pull/4775) by [@batlopes](https://github.com/batlopes). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/security/first-steps.md`. PR [#4954](https://github.com/tiangolo/fastapi/pull/4954) by [@FLAIR7](https://github.com/FLAIR7). * 🌐 Add translation for `docs/zh/docs/advanced/response-cookies.md`. PR [#4638](https://github.com/tiangolo/fastapi/pull/4638) by [@zhangbo2012](https://github.com/zhangbo2012). From e88089ec210dadb06311377ab203eabfbda3d830 Mon Sep 17 00:00:00 2001 From: Luca Repetti <39653693+klaa97@users.noreply.github.com> Date: Thu, 18 Aug 2022 22:31:19 +0200 Subject: [PATCH 650/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20edge=20case=20with?= =?UTF-8?q?=20repeated=20aliases=20names=20not=20shown=20in=20OpenAPI=20(#?= =?UTF-8?q?2351)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/openapi/utils.py | 4 +- tests/test_repeated_parameter_alias.py | 100 +++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 tests/test_repeated_parameter_alias.py diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 5d3d95c24..4d5741f30 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -223,7 +223,9 @@ def get_openapi_path( parameters.extend(operation_parameters) if parameters: operation["parameters"] = list( - {param["name"]: param for param in parameters}.values() + { + (param["in"], param["name"]): param for param in parameters + }.values() ) if method in METHODS_WITH_BODY: request_body_oai = get_openapi_operation_request_body( diff --git a/tests/test_repeated_parameter_alias.py b/tests/test_repeated_parameter_alias.py new file mode 100644 index 000000000..823f53a95 --- /dev/null +++ b/tests/test_repeated_parameter_alias.py @@ -0,0 +1,100 @@ +from fastapi import FastAPI, Path, Query, status +from fastapi.testclient import TestClient + +app = FastAPI() + + +@app.get("/{repeated_alias}") +def get_parameters_with_repeated_aliases( + path: str = Path(..., alias="repeated_alias"), + query: str = Query(..., alias="repeated_alias"), +): + return {"path": path, "query": query} + + +client = TestClient(app) + +openapi_schema = { + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "title": "Detail", + "type": "array", + } + }, + "title": "HTTPValidationError", + "type": "object", + }, + "ValidationError": { + "properties": { + "loc": { + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, + "title": "Location", + "type": "array", + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + "required": ["loc", "msg", "type"], + "title": "ValidationError", + "type": "object", + }, + } + }, + "info": {"title": "FastAPI", "version": "0.1.0"}, + "openapi": "3.0.2", + "paths": { + "/{repeated_alias}": { + "get": { + "operationId": "get_parameters_with_repeated_aliases__repeated_alias__get", + "parameters": [ + { + "in": "path", + "name": "repeated_alias", + "required": True, + "schema": {"title": "Repeated Alias", "type": "string"}, + }, + { + "in": "query", + "name": "repeated_alias", + "required": True, + "schema": {"title": "Repeated Alias", "type": "string"}, + }, + ], + "responses": { + "200": { + "content": {"application/json": {"schema": {}}}, + "description": "Successful Response", + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error", + }, + }, + "summary": "Get Parameters With Repeated Aliases", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == status.HTTP_200_OK + actual_schema = response.json() + assert actual_schema == openapi_schema + + +def test_get_parameters(): + response = client.get("/test_path", params={"repeated_alias": "test_query"}) + assert response.status_code == 200, response.text + assert response.json() == {"path": "test_path", "query": "test_query"} From 8a9a117ec7f58711dc68d6d6633dd02d4289cd1d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 20:31:57 +0000 Subject: [PATCH 651/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b2e73d4a3..cbe368772 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix edge case with repeated aliases names not shown in OpenAPI. PR [#2351](https://github.com/tiangolo/fastapi/pull/2351) by [@klaa97](https://github.com/klaa97). * 📝 Add misc dependency installs to tutorial docs. PR [#2126](https://github.com/tiangolo/fastapi/pull/2126) by [@TeoZosa](https://github.com/TeoZosa). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/query-params.md`. PR [#4775](https://github.com/tiangolo/fastapi/pull/4775) by [@batlopes](https://github.com/batlopes). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/security/first-steps.md`. PR [#4954](https://github.com/tiangolo/fastapi/pull/4954) by [@FLAIR7](https://github.com/FLAIR7). From eb2e1833612e67c9b9ffd2bb446a672d3dffccf4 Mon Sep 17 00:00:00 2001 From: Xavi Moreno Date: Fri, 19 Aug 2022 06:48:21 +1000 Subject: [PATCH 652/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20`jsonable=5Fencode?= =?UTF-8?q?r`=20using=20`include`=20and=20`exclude`=20parameters=20for=20n?= =?UTF-8?q?on-Pydantic=20objects=20(#2606)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/encoders.py | 9 ++++++++- tests/test_jsonable_encoder.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/fastapi/encoders.py b/fastapi/encoders.py index 4b7ffe313..b1fde73ce 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -80,6 +80,11 @@ def jsonable_encoder( return obj if isinstance(obj, dict): encoded_dict = {} + allowed_keys = set(obj.keys()) + if include is not None: + allowed_keys &= set(include) + if exclude is not None: + allowed_keys -= set(exclude) for key, value in obj.items(): if ( ( @@ -88,7 +93,7 @@ def jsonable_encoder( or (not key.startswith("_sa")) ) and (value is not None or not exclude_none) - and ((include and key in include) or not exclude or key not in exclude) + and key in allowed_keys ): encoded_key = jsonable_encoder( key, @@ -144,6 +149,8 @@ def jsonable_encoder( raise ValueError(errors) return jsonable_encoder( data, + include=include, + exclude=exclude, by_alias=by_alias, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py index ed35fd32e..5e55f2f91 100644 --- a/tests/test_jsonable_encoder.py +++ b/tests/test_jsonable_encoder.py @@ -93,16 +93,42 @@ def fixture_model_with_path(request): return ModelWithPath(path=request.param("/foo", "bar")) +def test_encode_dict(): + pet = {"name": "Firulais", "owner": {"name": "Foo"}} + assert jsonable_encoder(pet) == {"name": "Firulais", "owner": {"name": "Foo"}} + assert jsonable_encoder(pet, include={"name"}) == {"name": "Firulais"} + assert jsonable_encoder(pet, exclude={"owner"}) == {"name": "Firulais"} + assert jsonable_encoder(pet, include={}) == {} + assert jsonable_encoder(pet, exclude={}) == { + "name": "Firulais", + "owner": {"name": "Foo"}, + } + + def test_encode_class(): person = Person(name="Foo") pet = Pet(owner=person, name="Firulais") assert jsonable_encoder(pet) == {"name": "Firulais", "owner": {"name": "Foo"}} + assert jsonable_encoder(pet, include={"name"}) == {"name": "Firulais"} + assert jsonable_encoder(pet, exclude={"owner"}) == {"name": "Firulais"} + assert jsonable_encoder(pet, include={}) == {} + assert jsonable_encoder(pet, exclude={}) == { + "name": "Firulais", + "owner": {"name": "Foo"}, + } def test_encode_dictable(): person = DictablePerson(name="Foo") pet = DictablePet(owner=person, name="Firulais") assert jsonable_encoder(pet) == {"name": "Firulais", "owner": {"name": "Foo"}} + assert jsonable_encoder(pet, include={"name"}) == {"name": "Firulais"} + assert jsonable_encoder(pet, exclude={"owner"}) == {"name": "Firulais"} + assert jsonable_encoder(pet, include={}) == {} + assert jsonable_encoder(pet, exclude={}) == { + "name": "Firulais", + "owner": {"name": "Foo"}, + } def test_encode_unsupported(): @@ -144,6 +170,14 @@ def test_encode_model_with_default(): assert jsonable_encoder(model, exclude_unset=True, exclude_defaults=True) == { "foo": "foo" } + assert jsonable_encoder(model, include={"foo"}) == {"foo": "foo"} + assert jsonable_encoder(model, exclude={"bla"}) == {"foo": "foo", "bar": "bar"} + assert jsonable_encoder(model, include={}) == {} + assert jsonable_encoder(model, exclude={}) == { + "foo": "foo", + "bar": "bar", + "bla": "bla", + } def test_custom_encoders(): From 74638fcf7cbdc836d46cfee398b781276860cd7b Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 20:49:01 +0000 Subject: [PATCH 653/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index cbe368772..855bd7ec6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix `jsonable_encoder` using `include` and `exclude` parameters for non-Pydantic objects. PR [#2606](https://github.com/tiangolo/fastapi/pull/2606) by [@xaviml](https://github.com/xaviml). * 🐛 Fix edge case with repeated aliases names not shown in OpenAPI. PR [#2351](https://github.com/tiangolo/fastapi/pull/2351) by [@klaa97](https://github.com/klaa97). * 📝 Add misc dependency installs to tutorial docs. PR [#2126](https://github.com/tiangolo/fastapi/pull/2126) by [@TeoZosa](https://github.com/TeoZosa). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/query-params.md`. PR [#4775](https://github.com/tiangolo/fastapi/pull/4775) by [@batlopes](https://github.com/batlopes). From 2f9c6ab36abff2f7c80b7c33cab92171c66a3cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 18 Aug 2022 22:57:02 +0200 Subject: [PATCH 654/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20Jina=20sponsors?= =?UTF-8?q?hip=20(#5283)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- docs/en/data/sponsors.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a5e8cae22..326ad2279 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,10 @@ The key features are: + - diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 7fbb933e0..af1f97818 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -2,6 +2,9 @@ gold: - url: https://bit.ly/3dmXC5S title: The data structure for unstructured multimodal data img: https://fastapi.tiangolo.com/img/sponsors/docarray.svg + - url: https://bit.ly/3JJ7y5C + title: Build cross-modal and multimodal applications on the cloud + img: https://fastapi.tiangolo.com/img/sponsors/jina2.svg - url: https://cryptapi.io/ title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway." img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg @@ -11,9 +14,6 @@ gold: - url: https://doist.com/careers/9B437B1615-wa-senior-backend-engineer-python title: Help us migrate doist to FastAPI img: https://fastapi.tiangolo.com/img/sponsors/doist.svg - - url: https://bit.ly/3JJ7y5C - title: Build cross-modal and multimodal applications on the cloud - img: https://fastapi.tiangolo.com/img/sponsors/jina2.svg silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas From 94bbb91ec2912dfbcababc77386abee6e3c02c1d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 20:57:50 +0000 Subject: [PATCH 655/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 855bd7ec6..fe3aebbfc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update Jina sponsorship. PR [#5283](https://github.com/tiangolo/fastapi/pull/5283) by [@tiangolo](https://github.com/tiangolo). * 🐛 Fix `jsonable_encoder` using `include` and `exclude` parameters for non-Pydantic objects. PR [#2606](https://github.com/tiangolo/fastapi/pull/2606) by [@xaviml](https://github.com/xaviml). * 🐛 Fix edge case with repeated aliases names not shown in OpenAPI. PR [#2351](https://github.com/tiangolo/fastapi/pull/2351) by [@klaa97](https://github.com/klaa97). * 📝 Add misc dependency installs to tutorial docs. PR [#2126](https://github.com/tiangolo/fastapi/pull/2126) by [@TeoZosa](https://github.com/TeoZosa). From 7f0e2f6cfa44d6710725a7950e8acd3235ad64af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 18 Aug 2022 23:04:30 +0200 Subject: [PATCH 656/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fe3aebbfc..1d267a97e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,27 +2,38 @@ ## Latest Changes -* 🔧 Update Jina sponsorship. PR [#5283](https://github.com/tiangolo/fastapi/pull/5283) by [@tiangolo](https://github.com/tiangolo). +### Fixes + * 🐛 Fix `jsonable_encoder` using `include` and `exclude` parameters for non-Pydantic objects. PR [#2606](https://github.com/tiangolo/fastapi/pull/2606) by [@xaviml](https://github.com/xaviml). * 🐛 Fix edge case with repeated aliases names not shown in OpenAPI. PR [#2351](https://github.com/tiangolo/fastapi/pull/2351) by [@klaa97](https://github.com/klaa97). * 📝 Add misc dependency installs to tutorial docs. PR [#2126](https://github.com/tiangolo/fastapi/pull/2126) by [@TeoZosa](https://github.com/TeoZosa). + +### Docs + +* ✏ Fix typo in `python-types.md`. PR [#5116](https://github.com/tiangolo/fastapi/pull/5116) by [@Kludex](https://github.com/Kludex). +* ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#5007](https://github.com/tiangolo/fastapi/pull/5007) by [@atiabbz](https://github.com/atiabbz). +* 📝 Remove unneeded Django/Flask references from async topic intro. PR [#5280](https://github.com/tiangolo/fastapi/pull/5280) by [@carltongibson](https://github.com/carltongibson). +* ✨ Add illustrations for Concurrent burgers and Parallel burgers. PR [#5277](https://github.com/tiangolo/fastapi/pull/5277) by [@tiangolo](https://github.com/tiangolo). Updated docs at: [Concurrency and Burgers](https://fastapi.tiangolo.com/async/#concurrency-and-burgers). + +### Translations + * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/query-params.md`. PR [#4775](https://github.com/tiangolo/fastapi/pull/4775) by [@batlopes](https://github.com/batlopes). * 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/security/first-steps.md`. PR [#4954](https://github.com/tiangolo/fastapi/pull/4954) by [@FLAIR7](https://github.com/FLAIR7). * 🌐 Add translation for `docs/zh/docs/advanced/response-cookies.md`. PR [#4638](https://github.com/tiangolo/fastapi/pull/4638) by [@zhangbo2012](https://github.com/zhangbo2012). -* ✏ Fix typo in `python-types.md`. PR [#5116](https://github.com/tiangolo/fastapi/pull/5116) by [@Kludex](https://github.com/Kludex). * 🌐 Add French translation for `docs/fr/docs/deployment/index.md`. PR [#3689](https://github.com/tiangolo/fastapi/pull/3689) by [@rjNemo](https://github.com/rjNemo). * 🌐 Add Portuguese translation for `tutorial/handling-errors.md`. PR [#4769](https://github.com/tiangolo/fastapi/pull/4769) by [@frnsimoes](https://github.com/frnsimoes). * 🌐 Add French translation for `docs/fr/docs/history-design-future.md`. PR [#3451](https://github.com/tiangolo/fastapi/pull/3451) by [@rjNemo](https://github.com/rjNemo). -* ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#5007](https://github.com/tiangolo/fastapi/pull/5007) by [@atiabbz](https://github.com/atiabbz). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/background-tasks.md`. PR [#4854](https://github.com/tiangolo/fastapi/pull/4854) by [@AdmiralDesu](https://github.com/AdmiralDesu). * 🌐 Add Chinese translation for `docs/tutorial/security/first-steps.md`. PR [#3841](https://github.com/tiangolo/fastapi/pull/3841) by [@jaystone776](https://github.com/jaystone776). * 🌐 Add Japanese translation for `docs/ja/docs/advanced/nosql-databases.md`. PR [#4205](https://github.com/tiangolo/fastapi/pull/4205) by [@sUeharaE4](https://github.com/sUeharaE4). * 🌐 Add Indonesian translation for `docs/id/docs/tutorial/index.md`. PR [#4705](https://github.com/tiangolo/fastapi/pull/4705) by [@bas-baskara](https://github.com/bas-baskara). -* 📝 Remove unneeded Django/Flask references from async topic intro. PR [#5280](https://github.com/tiangolo/fastapi/pull/5280) by [@carltongibson](https://github.com/carltongibson). -* ✨ Add illustrations for Concurrent burgers and Parallel burgers. PR [#5277](https://github.com/tiangolo/fastapi/pull/5277) by [@tiangolo](https://github.com/tiangolo). +* 🌐 Add Persian translation for `docs/fa/docs/index.md` and tweak right-to-left CSS. PR [#2395](https://github.com/tiangolo/fastapi/pull/2395) by [@mohsen-mahmoodi](https://github.com/mohsen-mahmoodi). + +### Internal + +* 🔧 Update Jina sponsorship. PR [#5283](https://github.com/tiangolo/fastapi/pull/5283) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update Jina sponsorship. PR [#5272](https://github.com/tiangolo/fastapi/pull/5272) by [@tiangolo](https://github.com/tiangolo). * 🔧 Update sponsors, Striveworks badge. PR [#5179](https://github.com/tiangolo/fastapi/pull/5179) by [@tiangolo](https://github.com/tiangolo). -* 🌐 Add Persian translation for `docs/fa/docs/index.md` and tweak right-to-left CSS. PR [#2395](https://github.com/tiangolo/fastapi/pull/2395) by [@mohsen-mahmoodi](https://github.com/mohsen-mahmoodi). ## 0.79.0 From a21c31557464b477ea284f9bad635b5cbef19425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 18 Aug 2022 23:11:39 +0200 Subject: [PATCH 657/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20note=20giving=20cr?= =?UTF-8?q?edit=20for=20illustrations=20to=20Ketrina=20Thompson=20(#5284)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/async.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index 95d2f755a..dc8e10bb8 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -136,6 +136,9 @@ You and your crush eat the burgers and have a nice time. ✨ +!!! info + Beautiful illustrations by Ketrina Thompson. 🎨 + --- Imagine you are the computer / program 🤖 in that story. @@ -196,6 +199,9 @@ You just eat them, and you are done. ⏹ There was not much talk or flirting as most of the time was spent waiting 🕙 in front of the counter. 😞 +!!! info + Beautiful illustrations by Ketrina Thompson. 🎨 + --- In this scenario of the parallel burgers, you are a computer / program 🤖 with two processors (you and your crush), both waiting 🕙 and dedicating their attention ⏯ to be "waiting on the counter" 🕙 for a long time. From 767df02814735b43898c05de016c976a144b38c5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 18 Aug 2022 21:12:18 +0000 Subject: [PATCH 658/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1d267a97e..01e01d586 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add note giving credit for illustrations to Ketrina Thompson. PR [#5284](https://github.com/tiangolo/fastapi/pull/5284) by [@tiangolo](https://github.com/tiangolo). ### Fixes * 🐛 Fix `jsonable_encoder` using `include` and `exclude` parameters for non-Pydantic objects. PR [#2606](https://github.com/tiangolo/fastapi/pull/2606) by [@xaviml](https://github.com/xaviml). From 09381ba04256adbd86e440715dc80e79d90fe840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 18 Aug 2022 23:13:19 +0200 Subject: [PATCH 659/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 01e01d586..54a4297d7 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,6 @@ ## Latest Changes -* 📝 Add note giving credit for illustrations to Ketrina Thompson. PR [#5284](https://github.com/tiangolo/fastapi/pull/5284) by [@tiangolo](https://github.com/tiangolo). ### Fixes * 🐛 Fix `jsonable_encoder` using `include` and `exclude` parameters for non-Pydantic objects. PR [#2606](https://github.com/tiangolo/fastapi/pull/2606) by [@xaviml](https://github.com/xaviml). @@ -11,6 +10,7 @@ ### Docs +* 📝 Add note giving credit for illustrations to [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot/). PR [#5284](https://github.com/tiangolo/fastapi/pull/5284) by [@tiangolo](https://github.com/tiangolo). * ✏ Fix typo in `python-types.md`. PR [#5116](https://github.com/tiangolo/fastapi/pull/5116) by [@Kludex](https://github.com/Kludex). * ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#5007](https://github.com/tiangolo/fastapi/pull/5007) by [@atiabbz](https://github.com/atiabbz). * 📝 Remove unneeded Django/Flask references from async topic intro. PR [#5280](https://github.com/tiangolo/fastapi/pull/5280) by [@carltongibson](https://github.com/carltongibson). From ab8988ff7c5bb2ec25d41ba8c8687114962e0986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 18 Aug 2022 23:14:07 +0200 Subject: [PATCH 660/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.79?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 54a4297d7..4b4ebee42 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.79.1 + ### Fixes * 🐛 Fix `jsonable_encoder` using `include` and `exclude` parameters for non-Pydantic objects. PR [#2606](https://github.com/tiangolo/fastapi/pull/2606) by [@xaviml](https://github.com/xaviml). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index e5cdbeb09..abcb219a9 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.79.0" +__version__ = "0.79.1" from starlette import status as status From eb80b79555d98bfbabe812676fae8296130874fd Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 22 Aug 2022 12:44:46 +0000 Subject: [PATCH 661/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4b4ebee42..8e1db01d3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* Translated docs to ru `project_generator.md`, `features.md`, `help-fastapi.md`, upgrade `python-types.md`, `docs/ru/mkdocs.yml`.. PR [#4913](https://github.com/tiangolo/fastapi/pull/4913) by [@Xewus](https://github.com/Xewus). ## 0.79.1 From 6c16d6a4f9776fd61fbfe39d7365c611061c7213 Mon Sep 17 00:00:00 2001 From: Joona Yoon Date: Mon, 22 Aug 2022 23:52:50 +0900 Subject: [PATCH 662/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20missing=20navigato?= =?UTF-8?q?r=20for=20`encoder.md`=20in=20Korean=20translation=20(#5238)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ko/mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml index 70cb419ba..50931e134 100644 --- a/docs/ko/mkdocs.yml +++ b/docs/ko/mkdocs.yml @@ -68,6 +68,7 @@ nav: - tutorial/response-status-code.md - tutorial/request-files.md - tutorial/request-forms-and-files.md + - tutorial/encoder.md markdown_extensions: - toc: permalink: true From 7953353a356bda1112fd60794365a32f72e9d4e3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 22 Aug 2022 14:53:35 +0000 Subject: [PATCH 663/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8e1db01d3..8ff0d3375 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add missing navigator for `encoder.md` in Korean translation. PR [#5238](https://github.com/tiangolo/fastapi/pull/5238) by [@joonas-yoon](https://github.com/joonas-yoon). * Translated docs to ru `project_generator.md`, `features.md`, `help-fastapi.md`, upgrade `python-types.md`, `docs/ru/mkdocs.yml`.. PR [#4913](https://github.com/tiangolo/fastapi/pull/4913) by [@Xewus](https://github.com/Xewus). ## 0.79.1 From 1ff8df6e7fd5c80193c5f7344b6c82c7fc951911 Mon Sep 17 00:00:00 2001 From: 0xflotus <0xflotus@gmail.com> Date: Mon, 22 Aug 2022 20:33:10 +0200 Subject: [PATCH 664/814] =?UTF-8?q?=F0=9F=8C=90=20Fix=20typos=20in=20Germa?= =?UTF-8?q?n=20translation=20for=20`docs/de/docs/features.md`=20(#4533)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/de/docs/features.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/de/docs/features.md b/docs/de/docs/features.md index d99ade402..f825472a9 100644 --- a/docs/de/docs/features.md +++ b/docs/de/docs/features.md @@ -97,7 +97,7 @@ Hierdurch werden Sie nie wieder einen falschen Schlüsselnamen benutzen und spar ### Kompakt -FastAPI nutzt für alles sinnvolle **Standard-Einstellungen**, welche optional überall konfiguriert werden können. Alle Parameter können ganz genau an Ihre Bedürfnisse angepasst werden, sodass sie genau die API definieren können, die sie brauchen. +FastAPI nutzt für alles sensible **Standard-Einstellungen**, welche optional überall konfiguriert werden können. Alle Parameter können ganz genau an Ihre Bedürfnisse angepasst werden, sodass sie genau die API definieren können, die sie brauchen. Aber standardmäßig, **"funktioniert einfach"** alles. @@ -119,9 +119,9 @@ Die gesamte Validierung übernimmt das etablierte und robuste **Pydantic**. ### Sicherheit und Authentifizierung -Sicherheit und Authentifizierung integriert. Ohne einen Kompromiss aufgrund einer Datenbank oder den Datenentitäten. +Integrierte Sicherheit und Authentifizierung. Ohne Kompromisse bei Datenbanken oder Datenmodellen. -Unterstützt alle von OpenAPI definierten Sicherheitsschemata, hierzu gehören: +Unterstützt werden alle von OpenAPI definierten Sicherheitsschemata, hierzu gehören: * HTTP Basis Authentifizierung. * **OAuth2** (auch mit **JWT Zugriffstokens**). Schauen Sie sich hierzu dieses Tutorial an: [OAuth2 mit JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. @@ -142,8 +142,8 @@ FastAPI enthält ein extrem einfaches, aber extrem mächtiges eines der schnellsten Python frameworks, auf Augenhöhe mit **NodeJS** und **Go**. +* Stark beeindruckende Performanz. Es ist eines der schnellsten Python Frameworks, auf Augenhöhe mit **NodeJS** und **Go**. * **WebSocket**-Unterstützung. * Hintergrundaufgaben im selben Prozess. * Ereignisse für das Starten und Herunterfahren. @@ -196,8 +196,8 @@ Mit **FastAPI** bekommen Sie alle Funktionen von **Pydantic** (da FastAPI für d * In Vergleichen ist Pydantic schneller als jede andere getestete Bibliothek. * Validierung von **komplexen Strukturen**: * Benutzung von hierachischen Pydantic Schemata, Python `typing`’s `List` und `Dict`, etc. - * Validierungen erlauben klare und einfache Datenschemadefinition, überprüft und dokumentiert als JSON Schema. + * Validierungen erlauben eine klare und einfache Datenschemadefinition, überprüft und dokumentiert als JSON Schema. * Sie können stark **verschachtelte JSON** Objekte haben und diese sind trotzdem validiert und annotiert. * **Erweiterbar**: - * Pydantic erlaubt die Definition von eigenen Datentypen oder Sie können die Validierung mit einer `validator` dekorierten Methode erweitern.. + * Pydantic erlaubt die Definition von eigenen Datentypen oder sie können die Validierung mit einer `validator` dekorierten Methode erweitern. * 100% Testabdeckung. From a6a39f300989f58062141d58c2581c55b0f0f9c3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 22 Aug 2022 18:35:01 +0000 Subject: [PATCH 665/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8ff0d3375..f57512cc1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix typos in German translation for `docs/de/docs/features.md`. PR [#4533](https://github.com/tiangolo/fastapi/pull/4533) by [@0xflotus](https://github.com/0xflotus). * 🌐 Add missing navigator for `encoder.md` in Korean translation. PR [#5238](https://github.com/tiangolo/fastapi/pull/5238) by [@joonas-yoon](https://github.com/joonas-yoon). * Translated docs to ru `project_generator.md`, `features.md`, `help-fastapi.md`, upgrade `python-types.md`, `docs/ru/mkdocs.yml`.. PR [#4913](https://github.com/tiangolo/fastapi/pull/4913) by [@Xewus](https://github.com/Xewus). From e7b1b96a54af8e6327be1e0cc2172c81d052edda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 22 Aug 2022 20:49:03 +0200 Subject: [PATCH 666/814] =?UTF-8?q?=F0=9F=8E=A8=20Update=20type=20annotati?= =?UTF-8?q?ons=20for=20`response=5Fmodel`,=20allow=20things=20like=20`Unio?= =?UTF-8?q?n[str,=20None]`=20(#5294)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/applications.py | 20 ++++++++++---------- fastapi/routing.py | 22 +++++++++++----------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index 7530ddb9b..ac6050ca4 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -273,7 +273,7 @@ class FastAPI(Starlette): path: str, endpoint: Callable[..., Coroutine[Any, Any, Response]], *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, @@ -331,7 +331,7 @@ class FastAPI(Starlette): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, @@ -434,7 +434,7 @@ class FastAPI(Starlette): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, @@ -489,7 +489,7 @@ class FastAPI(Starlette): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, @@ -544,7 +544,7 @@ class FastAPI(Starlette): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, @@ -599,7 +599,7 @@ class FastAPI(Starlette): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, @@ -654,7 +654,7 @@ class FastAPI(Starlette): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, @@ -709,7 +709,7 @@ class FastAPI(Starlette): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, @@ -764,7 +764,7 @@ class FastAPI(Starlette): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, @@ -819,7 +819,7 @@ class FastAPI(Starlette): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, diff --git a/fastapi/routing.py b/fastapi/routing.py index 6f1a8e900..2e0d2e552 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -315,7 +315,7 @@ class APIRoute(routing.Route): path: str, endpoint: Callable[..., Any], *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -511,7 +511,7 @@ class APIRouter(routing.Router): path: str, endpoint: Callable[..., Any], *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -592,7 +592,7 @@ class APIRouter(routing.Router): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -787,7 +787,7 @@ class APIRouter(routing.Router): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -843,7 +843,7 @@ class APIRouter(routing.Router): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -899,7 +899,7 @@ class APIRouter(routing.Router): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -955,7 +955,7 @@ class APIRouter(routing.Router): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -1011,7 +1011,7 @@ class APIRouter(routing.Router): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -1067,7 +1067,7 @@ class APIRouter(routing.Router): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -1123,7 +1123,7 @@ class APIRouter(routing.Router): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, @@ -1179,7 +1179,7 @@ class APIRouter(routing.Router): self, path: str, *, - response_model: Optional[Type[Any]] = None, + response_model: Any = None, status_code: Optional[int] = None, tags: Optional[List[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, From 12f60cac7a2262231374404c538f0b227f9b9496 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 22 Aug 2022 18:49:42 +0000 Subject: [PATCH 667/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f57512cc1..f5ccf9b26 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🎨 Update type annotations for `response_model`, allow things like `Union[str, None]`. PR [#5294](https://github.com/tiangolo/fastapi/pull/5294) by [@tiangolo](https://github.com/tiangolo). * 🌐 Fix typos in German translation for `docs/de/docs/features.md`. PR [#4533](https://github.com/tiangolo/fastapi/pull/4533) by [@0xflotus](https://github.com/0xflotus). * 🌐 Add missing navigator for `encoder.md` in Korean translation. PR [#5238](https://github.com/tiangolo/fastapi/pull/5238) by [@joonas-yoon](https://github.com/joonas-yoon). * Translated docs to ru `project_generator.md`, `features.md`, `help-fastapi.md`, upgrade `python-types.md`, `docs/ru/mkdocs.yml`.. PR [#4913](https://github.com/tiangolo/fastapi/pull/4913) by [@Xewus](https://github.com/Xewus). From 634cf22584fc4fd9ee53cfdf0ad6d48a2830ac34 Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen <3275109+hukkin@users.noreply.github.com> Date: Mon, 22 Aug 2022 22:17:45 +0300 Subject: [PATCH 668/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20`response=5Fmodel`?= =?UTF-8?q?=20not=20invalidating=20`None`=20(#2725)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Taneli Hukkinen Co-authored-by: Sebastián Ramírez --- fastapi/utils.py | 2 +- tests/test_validate_response.py | 34 ++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/fastapi/utils.py b/fastapi/utils.py index 887d57c90..40750a5b3 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -50,7 +50,7 @@ def create_response_field( type_: Type[Any], class_validators: Optional[Dict[str, Validator]] = None, default: Optional[Any] = None, - required: Union[bool, UndefinedType] = False, + required: Union[bool, UndefinedType] = True, model_config: Type[BaseConfig] = BaseConfig, field_info: Optional[FieldInfo] = None, alias: Optional[str] = None, diff --git a/tests/test_validate_response.py b/tests/test_validate_response.py index 45d303e20..62f51c960 100644 --- a/tests/test_validate_response.py +++ b/tests/test_validate_response.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import List, Optional, Union import pytest from fastapi import FastAPI @@ -19,6 +19,19 @@ def get_invalid(): return {"name": "invalid", "price": "foo"} +@app.get("/items/invalidnone", response_model=Item) +def get_invalid_none(): + return None + + +@app.get("/items/validnone", response_model=Union[Item, None]) +def get_valid_none(send_none: bool = False): + if send_none: + return None + else: + return {"name": "invalid", "price": 3.2} + + @app.get("/items/innerinvalid", response_model=Item) def get_innerinvalid(): return {"name": "double invalid", "price": "foo", "owner_ids": ["foo", "bar"]} @@ -41,6 +54,25 @@ def test_invalid(): client.get("/items/invalid") +def test_invalid_none(): + with pytest.raises(ValidationError): + client.get("/items/invalidnone") + + +def test_valid_none_data(): + response = client.get("/items/validnone") + data = response.json() + assert response.status_code == 200 + assert data == {"name": "invalid", "price": 3.2, "owner_ids": None} + + +def test_valid_none_none(): + response = client.get("/items/validnone", params={"send_none": "true"}) + data = response.json() + assert response.status_code == 200 + assert data is None + + def test_double_invalid(): with pytest.raises(ValidationError): client.get("/items/innerinvalid") From 982911f08f11ceb10ad8bba34ec22095d6018856 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 22 Aug 2022 19:18:24 +0000 Subject: [PATCH 669/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f5ccf9b26..0cab8220a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix `response_model` not invalidating `None`. PR [#2725](https://github.com/tiangolo/fastapi/pull/2725) by [@hukkin](https://github.com/hukkin). * 🎨 Update type annotations for `response_model`, allow things like `Union[str, None]`. PR [#5294](https://github.com/tiangolo/fastapi/pull/5294) by [@tiangolo](https://github.com/tiangolo). * 🌐 Fix typos in German translation for `docs/de/docs/features.md`. PR [#4533](https://github.com/tiangolo/fastapi/pull/4533) by [@0xflotus](https://github.com/0xflotus). * 🌐 Add missing navigator for `encoder.md` in Korean translation. PR [#5238](https://github.com/tiangolo/fastapi/pull/5238) by [@joonas-yoon](https://github.com/joonas-yoon). From b993b4af287e63904b675ba2ee1c232e86f2b072 Mon Sep 17 00:00:00 2001 From: laggardkernel Date: Tue, 23 Aug 2022 21:30:24 +0800 Subject: [PATCH 670/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20cached=20dependenc?= =?UTF-8?q?ies=20when=20using=20a=20dependency=20in=20`Security()`=20and?= =?UTF-8?q?=20other=20places=20(e.g.=20`Depends()`)=20with=20different=20O?= =?UTF-8?q?Auth2=20scopes=20(#2945)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/dependencies/utils.py | 10 +++++++--- tests/test_dependency_cache.py | 25 ++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index f397e333c..f6151f6bd 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -161,7 +161,6 @@ def get_sub_dependant( ) if security_requirement: sub_dependant.security_requirements.append(security_requirement) - sub_dependant.security_scopes = security_scopes return sub_dependant @@ -278,7 +277,13 @@ def get_dependant( path_param_names = get_path_param_names(path) endpoint_signature = get_typed_signature(call) signature_params = endpoint_signature.parameters - dependant = Dependant(call=call, name=name, path=path, use_cache=use_cache) + dependant = Dependant( + call=call, + name=name, + path=path, + security_scopes=security_scopes, + use_cache=use_cache, + ) for param_name, param in signature_params.items(): if isinstance(param.default, params.Depends): sub_dependant = get_param_sub_dependant( @@ -495,7 +500,6 @@ async def solve_dependencies( name=sub_dependant.name, security_scopes=sub_dependant.security_scopes, ) - use_sub_dependant.security_scopes = sub_dependant.security_scopes solved_result = await solve_dependencies( request=request, diff --git a/tests/test_dependency_cache.py b/tests/test_dependency_cache.py index 65ed7f946..08fb9b74f 100644 --- a/tests/test_dependency_cache.py +++ b/tests/test_dependency_cache.py @@ -1,4 +1,4 @@ -from fastapi import Depends, FastAPI +from fastapi import Depends, FastAPI, Security from fastapi.testclient import TestClient app = FastAPI() @@ -35,6 +35,19 @@ async def get_sub_counter_no_cache( return {"counter": count, "subcounter": subcount} +@app.get("/scope-counter") +async def get_scope_counter( + count: int = Security(dep_counter), + scope_count_1: int = Security(dep_counter, scopes=["scope"]), + scope_count_2: int = Security(dep_counter, scopes=["scope"]), +): + return { + "counter": count, + "scope_counter_1": scope_count_1, + "scope_counter_2": scope_count_2, + } + + client = TestClient(app) @@ -66,3 +79,13 @@ def test_sub_counter_no_cache(): response = client.get("/sub-counter-no-cache/") assert response.status_code == 200, response.text assert response.json() == {"counter": 4, "subcounter": 3} + + +def test_security_cache(): + counter_holder["counter"] = 0 + response = client.get("/scope-counter/") + assert response.status_code == 200, response.text + assert response.json() == {"counter": 1, "scope_counter_1": 2, "scope_counter_2": 2} + response = client.get("/scope-counter/") + assert response.status_code == 200, response.text + assert response.json() == {"counter": 3, "scope_counter_1": 4, "scope_counter_2": 4} From f8f5281ef5efa25e780fec97701ed35eec3bcc71 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 23 Aug 2022 13:31:17 +0000 Subject: [PATCH 671/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0cab8220a..f2c455e2f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix cached dependencies when using a dependency in `Security()` and other places (e.g. `Depends()`) with different OAuth2 scopes. PR [#2945](https://github.com/tiangolo/fastapi/pull/2945) by [@laggardkernel](https://github.com/laggardkernel). * 🐛 Fix `response_model` not invalidating `None`. PR [#2725](https://github.com/tiangolo/fastapi/pull/2725) by [@hukkin](https://github.com/hukkin). * 🎨 Update type annotations for `response_model`, allow things like `Union[str, None]`. PR [#5294](https://github.com/tiangolo/fastapi/pull/5294) by [@tiangolo](https://github.com/tiangolo). * 🌐 Fix typos in German translation for `docs/de/docs/features.md`. PR [#4533](https://github.com/tiangolo/fastapi/pull/4533) by [@0xflotus](https://github.com/0xflotus). From f6808e76dcb332aefe16abab37b0480b16e7cdb1 Mon Sep 17 00:00:00 2001 From: Andrey Semakin Date: Tue, 23 Aug 2022 18:47:19 +0500 Subject: [PATCH 672/814] =?UTF-8?q?=E2=99=BB=20Strip=20empty=20whitespace?= =?UTF-8?q?=20from=20description=20extracted=20from=20docstrings=20(#2821)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/routing.py | 2 +- .../test_tutorial004.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fastapi/routing.py b/fastapi/routing.py index 2e0d2e552..80bd53279 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -409,7 +409,7 @@ class APIRoute(routing.Route): self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "") # if a "form feed" character (page break) is found in the description text, # truncate description text to the content preceding the first "form feed" - self.description = self.description.split("\f")[0] + self.description = self.description.split("\f")[0].strip() response_fields = {} for additional_status_code, response in self.responses.items(): assert isinstance(response, dict), "An additional response must be a dict" diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py index 456e509d5..3de19833b 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py @@ -31,7 +31,7 @@ openapi_schema = { }, }, "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\n", + "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": { From 09acce4b2c7f50cdea7c487e9123b88c44a6724f Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 23 Aug 2022 13:48:07 +0000 Subject: [PATCH 673/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f2c455e2f..58ba2fb2c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻ Strip empty whitespace from description extracted from docstrings. PR [#2821](https://github.com/tiangolo/fastapi/pull/2821) by [@and-semakin](https://github.com/and-semakin). * 🐛 Fix cached dependencies when using a dependency in `Security()` and other places (e.g. `Depends()`) with different OAuth2 scopes. PR [#2945](https://github.com/tiangolo/fastapi/pull/2945) by [@laggardkernel](https://github.com/laggardkernel). * 🐛 Fix `response_model` not invalidating `None`. PR [#2725](https://github.com/tiangolo/fastapi/pull/2725) by [@hukkin](https://github.com/hukkin). * 🎨 Update type annotations for `response_model`, allow things like `Union[str, None]`. PR [#5294](https://github.com/tiangolo/fastapi/pull/5294) by [@tiangolo](https://github.com/tiangolo). From ec072d75fe0aae16caec3a8aa3f57ca8d6f05de5 Mon Sep 17 00:00:00 2001 From: Teo Koon Peng Date: Tue, 23 Aug 2022 21:57:25 +0800 Subject: [PATCH 674/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20Swagger=20UI=20co?= =?UTF-8?q?py=20of=20`oauth2-redirect.html`=20to=20include=20fixes=20for?= =?UTF-8?q?=20flavors=20of=20authorization=20code=20flows=20in=20Swagger?= =?UTF-8?q?=20UI=20(#3439)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/openapi/docs.py | 43 +++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py index d6af17a85..b7803b13b 100644 --- a/fastapi/openapi/docs.py +++ b/fastapi/openapi/docs.py @@ -115,12 +115,14 @@ def get_redoc_html( def get_swagger_ui_oauth2_redirect_html() -> HTMLResponse: + # copied from https://github.com/swagger-api/swagger-ui/blob/v4.14.0/dist/oauth2-redirect.html html = """ - + - - - + + Swagger UI: OAuth2 Redirect + + + + """ return HTMLResponse(content=html) From ad65e72d901c12edb5c69c1cded8994fa094f92f Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 23 Aug 2022 13:58:06 +0000 Subject: [PATCH 675/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 58ba2fb2c..97748436f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade Swagger UI copy of `oauth2-redirect.html` to include fixes for flavors of authorization code flows in Swagger UI. PR [#3439](https://github.com/tiangolo/fastapi/pull/3439) by [@koonpeng](https://github.com/koonpeng). * ♻ Strip empty whitespace from description extracted from docstrings. PR [#2821](https://github.com/tiangolo/fastapi/pull/2821) by [@and-semakin](https://github.com/and-semakin). * 🐛 Fix cached dependencies when using a dependency in `Security()` and other places (e.g. `Depends()`) with different OAuth2 scopes. PR [#2945](https://github.com/tiangolo/fastapi/pull/2945) by [@laggardkernel](https://github.com/laggardkernel). * 🐛 Fix `response_model` not invalidating `None`. PR [#2725](https://github.com/tiangolo/fastapi/pull/2725) by [@hukkin](https://github.com/hukkin). From 18819f9850007633f728fcf457db5170f7922001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 23 Aug 2022 16:13:37 +0200 Subject: [PATCH 676/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 78 +++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 97748436f..524da6f42 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,14 +2,86 @@ ## Latest Changes -* ⬆ Upgrade Swagger UI copy of `oauth2-redirect.html` to include fixes for flavors of authorization code flows in Swagger UI. PR [#3439](https://github.com/tiangolo/fastapi/pull/3439) by [@koonpeng](https://github.com/koonpeng). +### Breaking Changes - Fixes + +* 🐛 Fix `response_model` not invalidating `None`. PR [#2725](https://github.com/tiangolo/fastapi/pull/2725) by [@hukkin](https://github.com/hukkin). + +If you are using `response_model` with some type that doesn't include `None` but the function is returning `None`, it will now raise an internal server error, because you are returning invalid data that violates the contract in `response_model`. Before this release it would allow breaking that contract returning `None`. + +For example, if you have an app like this: + +```Python +from fastapi import FastAPI +from pydantic import BaseModel + +class Item(BaseModel): + name: str + price: Optional[float] = None + owner_ids: Optional[List[int]] = None + +app = FastAPI() + +@app.get("/items/invalidnone", response_model=Item) +def get_invalid_none(): + return None +``` + +...calling the path `/items/invalidnone` will raise an error, because `None` is not a valid type for the `response_model` declared with `Item`. + +You could also be implicitly returning `None` without realizing, for example: + +```Python +from fastapi import FastAPI +from pydantic import BaseModel + +class Item(BaseModel): + name: str + price: Optional[float] = None + owner_ids: Optional[List[int]] = None + +app = FastAPI() + +@app.get("/items/invalidnone", response_model=Item) +def get_invalid_none(): + if flag: + return {"name": "foo"} + # if flag is False, at this point the function will implicitly return None +``` + +If you have *path operations* using `response_model` that need to be allowed to return `None`, make it explicit in `response_model` using `Union[Something, None]`: + +```Python +from typing import Union + +from fastapi import FastAPI +from pydantic import BaseModel + +class Item(BaseModel): + name: str + price: Optional[float] = None + owner_ids: Optional[List[int]] = None + +app = FastAPI() + +@app.get("/items/invalidnone", response_model=Union[Item, None]) +def get_invalid_none(): + return None +``` + +This way the data will be correctly validated, you won't have an internal server error, and the documentation will also reflect that this *path operation* could return `None` (or `null` in JSON). + +### Fixes + +* ⬆ Upgrade Swagger UI copy of `oauth2-redirect.html` to include fixes for flavors of authorization code flows in Swagger UI. PR [#3439](https://github.com/tiangolo/fastapi/pull/3439) initial PR by [@koonpeng](https://github.com/koonpeng). * ♻ Strip empty whitespace from description extracted from docstrings. PR [#2821](https://github.com/tiangolo/fastapi/pull/2821) by [@and-semakin](https://github.com/and-semakin). * 🐛 Fix cached dependencies when using a dependency in `Security()` and other places (e.g. `Depends()`) with different OAuth2 scopes. PR [#2945](https://github.com/tiangolo/fastapi/pull/2945) by [@laggardkernel](https://github.com/laggardkernel). -* 🐛 Fix `response_model` not invalidating `None`. PR [#2725](https://github.com/tiangolo/fastapi/pull/2725) by [@hukkin](https://github.com/hukkin). * 🎨 Update type annotations for `response_model`, allow things like `Union[str, None]`. PR [#5294](https://github.com/tiangolo/fastapi/pull/5294) by [@tiangolo](https://github.com/tiangolo). + +### Translations + * 🌐 Fix typos in German translation for `docs/de/docs/features.md`. PR [#4533](https://github.com/tiangolo/fastapi/pull/4533) by [@0xflotus](https://github.com/0xflotus). * 🌐 Add missing navigator for `encoder.md` in Korean translation. PR [#5238](https://github.com/tiangolo/fastapi/pull/5238) by [@joonas-yoon](https://github.com/joonas-yoon). -* Translated docs to ru `project_generator.md`, `features.md`, `help-fastapi.md`, upgrade `python-types.md`, `docs/ru/mkdocs.yml`.. PR [#4913](https://github.com/tiangolo/fastapi/pull/4913) by [@Xewus](https://github.com/Xewus). +* (Empty PR merge by accident) [#4913](https://github.com/tiangolo/fastapi/pull/4913). ## 0.79.1 From 7d6e70791d0d4c5cf271bcd231ba78d1a3c0f582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Tue, 23 Aug 2022 16:14:48 +0200 Subject: [PATCH 677/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.80?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 524da6f42..fc48bf7dd 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.80.0 + ### Breaking Changes - Fixes * 🐛 Fix `response_model` not invalidating `None`. PR [#2725](https://github.com/tiangolo/fastapi/pull/2725) by [@hukkin](https://github.com/hukkin). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index abcb219a9..3dc86cadf 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.79.1" +__version__ = "0.80.0" from starlette import status as status From 68f25120c51545d36832478e508d63fcacdb3903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 24 Aug 2022 10:43:44 +0200 Subject: [PATCH 678/814] =?UTF-8?q?=F0=9F=8D=B1=20Update=20Jina=20banner,?= =?UTF-8?q?=20fix=20typo=20(#5301)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/img/sponsors/docarray-top-banner.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/img/sponsors/docarray-top-banner.svg b/docs/en/docs/img/sponsors/docarray-top-banner.svg index c48a3312b..b2eca3544 100644 --- a/docs/en/docs/img/sponsors/docarray-top-banner.svg +++ b/docs/en/docs/img/sponsors/docarray-top-banner.svg @@ -1 +1 @@ - + From 2201f29be32fd6a584433bcfc7c6310ac043b7f3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 24 Aug 2022 08:44:22 +0000 Subject: [PATCH 679/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fc48bf7dd..6e17be159 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🍱 Update Jina banner, fix typo. PR [#5301](https://github.com/tiangolo/fastapi/pull/5301) by [@tiangolo](https://github.com/tiangolo). ## 0.80.0 From 1835b3f76d6c72629500f971920730c645867168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 24 Aug 2022 16:18:11 +0200 Subject: [PATCH 680/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20docs=20for=20te?= =?UTF-8?q?sting,=20fix=20examples=20with=20relative=20imports=20(#5302)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/async-tests.md | 14 ++++++++-- docs/en/docs/tutorial/testing.md | 38 +++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/docs/en/docs/advanced/async-tests.md b/docs/en/docs/advanced/async-tests.md index d5116233f..e34f48f17 100644 --- a/docs/en/docs/advanced/async-tests.md +++ b/docs/en/docs/advanced/async-tests.md @@ -26,13 +26,23 @@ The important difference for us is that with HTTPX we are not limited to synchro ## Example -For a simple example, let's consider the following `main.py` module: +For a simple example, let's consider a file structure similar to the one described in [Bigger Applications](../tutorial/bigger-applications.md){.internal-link target=_blank} and [Testing](../tutorial/testing.md){.internal-link target=_blank}: + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +│   └── test_main.py +``` + +The file `main.py` would have: ```Python {!../../../docs_src/async_tests/main.py!} ``` -The `test_main.py` module that contains the tests for `main.py` could look like this now: +The file `test_main.py` would have the tests for `main.py`, it could look like this now: ```Python {!../../../docs_src/async_tests/test_main.py!} diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md index 79ea2b1ab..d2ccd7dc7 100644 --- a/docs/en/docs/tutorial/testing.md +++ b/docs/en/docs/tutorial/testing.md @@ -50,7 +50,17 @@ And your **FastAPI** application might also be composed of several files/modules ### **FastAPI** app file -Let's say you have a file `main.py` with your **FastAPI** app: +Let's say you have a file structure as described in [Bigger Applications](./bigger-applications.md){.internal-link target=_blank}: + +``` +. +├── app +│   ├── __init__.py +│   └── main.py +``` + +In the file `main.py` you have your **FastAPI** app: + ```Python {!../../../docs_src/app_testing/main.py!} @@ -58,18 +68,40 @@ Let's say you have a file `main.py` with your **FastAPI** app: ### Testing file -Then you could have a file `test_main.py` with your tests, and import your `app` from the `main` module (`main.py`): +Then you could have a file `test_main.py` with your tests. It could live on the same Python package (the same directory with a `__init__.py` file): -```Python +``` hl_lines="5" +. +├── app +│   ├── __init__.py +│   ├── main.py +│   └── test_main.py +``` + +Because this file is in the same package, you can use relative imports to import the object `app` from the `main` module (`main.py`): + +```Python hl_lines="3" {!../../../docs_src/app_testing/test_main.py!} ``` +...and have the code for the tests just like before. + ## Testing: extended example Now let's extend this example and add more details to see how to test different parts. ### Extended **FastAPI** app file +Let's continue with the same file structure as before: + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +│   └── test_main.py +``` + Let's say that now the file `main.py` with your **FastAPI** app has some other **path operations**. It has a `GET` operation that could return an error. From f90465f5b4e83110722b096306057c54bb211ba7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 24 Aug 2022 14:18:57 +0000 Subject: [PATCH 681/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6e17be159..1b5806741 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update docs for testing, fix examples with relative imports. PR [#5302](https://github.com/tiangolo/fastapi/pull/5302) by [@tiangolo](https://github.com/tiangolo). * 🍱 Update Jina banner, fix typo. PR [#5301](https://github.com/tiangolo/fastapi/pull/5301) by [@tiangolo](https://github.com/tiangolo). ## 0.80.0 From 8c6ad3561534d69a2ccb0d3d0e9e60afc5b388de Mon Sep 17 00:00:00 2001 From: Kevin Tewouda Date: Wed, 24 Aug 2022 16:53:43 +0200 Subject: [PATCH 682/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20docs=20for=20ha?= =?UTF-8?q?ndling=20HTTP=20Basic=20Auth=20with=20`secrets.compare=5Fdigest?= =?UTF-8?q?()`=20to=20account=20for=20non-ASCII=20characters=20(#3536)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: le_woudar Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/security/http-basic-auth.md | 14 ++++++++++---- docs_src/security/tutorial007.py | 14 +++++++++++--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/en/docs/advanced/security/http-basic-auth.md b/docs/en/docs/advanced/security/http-basic-auth.md index 6c589cd9a..90c516808 100644 --- a/docs/en/docs/advanced/security/http-basic-auth.md +++ b/docs/en/docs/advanced/security/http-basic-auth.md @@ -34,13 +34,19 @@ Here's a more complete example. Use a dependency to check if the username and password are correct. -For this, use the Python standard module `secrets` to check the username and password: +For this, use the Python standard module `secrets` to check the username and password. -```Python hl_lines="1 11-13" +`secrets.compare_digest()` needs to take `bytes` or a `str` that only contains ASCII characters (the ones in English), this means it wouldn't work with characters like `á`, as in `Sebastián`. + +To handle that, we first convert the `username` and `password` to `bytes` encoding them with UTF-8. + +Then we can use `secrets.compare_digest()` to ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`. + +```Python hl_lines="1 11-21" {!../../../docs_src/security/tutorial007.py!} ``` -This will ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`. This would be similar to: +This would be similar to: ```Python if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"): @@ -102,6 +108,6 @@ That way, using `secrets.compare_digest()` in your application code, it will be After detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again: -```Python hl_lines="15-19" +```Python hl_lines="23-27" {!../../../docs_src/security/tutorial007.py!} ``` diff --git a/docs_src/security/tutorial007.py b/docs_src/security/tutorial007.py index 90b9ac054..790ee10bc 100644 --- a/docs_src/security/tutorial007.py +++ b/docs_src/security/tutorial007.py @@ -9,9 +9,17 @@ security = HTTPBasic() def get_current_username(credentials: HTTPBasicCredentials = Depends(security)): - correct_username = secrets.compare_digest(credentials.username, "stanleyjobson") - correct_password = secrets.compare_digest(credentials.password, "swordfish") - if not (correct_username and correct_password): + current_username_bytes = credentials.username.encode("utf8") + correct_username_bytes = b"stanleyjobson" + is_correct_username = secrets.compare_digest( + current_username_bytes, correct_username_bytes + ) + current_password_bytes = credentials.password.encode("utf8") + correct_password_bytes = b"swordfish" + is_correct_password = secrets.compare_digest( + current_password_bytes, correct_password_bytes + ) + if not (is_correct_username and is_correct_password): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect email or password", From 39319a7ede38a57d8b2dbd1c376850fcf8ae5a17 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 24 Aug 2022 14:54:27 +0000 Subject: [PATCH 683/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1b5806741..806127162 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update docs for handling HTTP Basic Auth with `secrets.compare_digest()` to account for non-ASCII characters. PR [#3536](https://github.com/tiangolo/fastapi/pull/3536) by [@lewoudar](https://github.com/lewoudar). * 📝 Update docs for testing, fix examples with relative imports. PR [#5302](https://github.com/tiangolo/fastapi/pull/5302) by [@tiangolo](https://github.com/tiangolo). * 🍱 Update Jina banner, fix typo. PR [#5301](https://github.com/tiangolo/fastapi/pull/5301) by [@tiangolo](https://github.com/tiangolo). From 438656395afcc78e06ba2c7c0655e0156dfdc20d Mon Sep 17 00:00:00 2001 From: Caleb Renfroe <35737053+ccrenfroe@users.noreply.github.com> Date: Wed, 24 Aug 2022 17:35:30 -0400 Subject: [PATCH 684/814] =?UTF-8?q?=E2=9C=8F=20Reword=20confusing=20senten?= =?UTF-8?q?ce=20in=20docs=20file=20`typo-fix-path-params-numeric-validatio?= =?UTF-8?q?ns.md`=20(#3219)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/path-params-numeric-validations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/tutorial/path-params-numeric-validations.md b/docs/en/docs/tutorial/path-params-numeric-validations.md index 29235c6e2..4b2e3f973 100644 --- a/docs/en/docs/tutorial/path-params-numeric-validations.md +++ b/docs/en/docs/tutorial/path-params-numeric-validations.md @@ -122,9 +122,9 @@ And you can also declare numeric validations: * `le`: `l`ess than or `e`qual !!! info - `Query`, `Path`, and others you will see later are subclasses of a common `Param` class (that you don't need to use). + `Query`, `Path`, and other classes you will see later are subclasses of a common `Param` class. - And all of them share the same all these same parameters of additional validation and metadata you have seen. + All of them share the same parameters for additional validation and metadata you have seen. !!! note "Technical Details" When you import `Query`, `Path` and others from `fastapi`, they are actually functions. From afaa0391a59e54ff59e1d3d1b49785aecd78ee11 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 24 Aug 2022 21:36:15 +0000 Subject: [PATCH 685/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 806127162..7418fae6a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Reword confusing sentence in docs file `typo-fix-path-params-numeric-validations.md`. PR [#3219](https://github.com/tiangolo/fastapi/pull/3219) by [@ccrenfroe](https://github.com/ccrenfroe). * 📝 Update docs for handling HTTP Basic Auth with `secrets.compare_digest()` to account for non-ASCII characters. PR [#3536](https://github.com/tiangolo/fastapi/pull/3536) by [@lewoudar](https://github.com/lewoudar). * 📝 Update docs for testing, fix examples with relative imports. PR [#5302](https://github.com/tiangolo/fastapi/pull/5302) by [@tiangolo](https://github.com/tiangolo). * 🍱 Update Jina banner, fix typo. PR [#5301](https://github.com/tiangolo/fastapi/pull/5301) by [@tiangolo](https://github.com/tiangolo). From 9359a8d65fdff4460d01d652ccafd31507c6c426 Mon Sep 17 00:00:00 2001 From: Sidharth Ajithkumar Date: Thu, 25 Aug 2022 15:25:53 +0530 Subject: [PATCH 686/814] =?UTF-8?q?=E2=9C=A8=20Preserve=20`json.JSONDecode?= =?UTF-8?q?Error`=20information=20when=20handling=20invalid=20JSON=20in=20?= =?UTF-8?q?request=20body,=20to=20support=20custom=20exception=20handlers?= =?UTF-8?q?=20that=20use=20its=20information=20(#4057)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- fastapi/routing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fastapi/routing.py b/fastapi/routing.py index 80bd53279..8f4d0fa7e 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -209,7 +209,9 @@ def get_request_handler( else: body = body_bytes except json.JSONDecodeError as e: - raise RequestValidationError([ErrorWrapper(e, ("body", e.pos))], body=e.doc) + raise RequestValidationError( + [ErrorWrapper(e, ("body", e.pos))], body=e.doc + ) from e except Exception as e: raise HTTPException( status_code=400, detail="There was an error parsing the body" From 5215b39d5081dab2145fb682d832a93649d26063 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 25 Aug 2022 09:56:40 +0000 Subject: [PATCH 687/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7418fae6a..337149972 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Preserve `json.JSONDecodeError` information when handling invalid JSON in request body, to support custom exception handlers that use its information. PR [#4057](https://github.com/tiangolo/fastapi/pull/4057) by [@UKnowWhoIm](https://github.com/UKnowWhoIm). * ✏ Reword confusing sentence in docs file `typo-fix-path-params-numeric-validations.md`. PR [#3219](https://github.com/tiangolo/fastapi/pull/3219) by [@ccrenfroe](https://github.com/ccrenfroe). * 📝 Update docs for handling HTTP Basic Auth with `secrets.compare_digest()` to account for non-ASCII characters. PR [#3536](https://github.com/tiangolo/fastapi/pull/3536) by [@lewoudar](https://github.com/lewoudar). * 📝 Update docs for testing, fix examples with relative imports. PR [#5302](https://github.com/tiangolo/fastapi/pull/5302) by [@tiangolo](https://github.com/tiangolo). From eb3ab337ab49d1904f027c0a523456cfe40d582d Mon Sep 17 00:00:00 2001 From: Andy Challis Date: Fri, 26 Aug 2022 07:44:40 +1000 Subject: [PATCH 688/814] =?UTF-8?q?=E2=9C=A8=20Allow=20custom=20middleware?= =?UTF-8?q?s=20to=20raise=20`HTTPException`s=20and=20propagate=20them=20(#?= =?UTF-8?q?2036)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- fastapi/routing.py | 2 + tests/test_custom_middleware_exception.py | 95 +++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 tests/test_custom_middleware_exception.py diff --git a/fastapi/routing.py b/fastapi/routing.py index 8f4d0fa7e..1ac4b3880 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -212,6 +212,8 @@ def get_request_handler( raise RequestValidationError( [ErrorWrapper(e, ("body", e.pos))], body=e.doc ) from e + except HTTPException: + raise except Exception as e: raise HTTPException( status_code=400, detail="There was an error parsing the body" diff --git a/tests/test_custom_middleware_exception.py b/tests/test_custom_middleware_exception.py new file mode 100644 index 000000000..d9b81e7c2 --- /dev/null +++ b/tests/test_custom_middleware_exception.py @@ -0,0 +1,95 @@ +from pathlib import Path +from typing import Optional + +from fastapi import APIRouter, FastAPI, File, UploadFile +from fastapi.exceptions import HTTPException +from fastapi.testclient import TestClient + +app = FastAPI() + +router = APIRouter() + + +class ContentSizeLimitMiddleware: + """Content size limiting middleware for ASGI applications + Args: + app (ASGI application): ASGI application + max_content_size (optional): the maximum content size allowed in bytes, None for no limit + """ + + def __init__(self, app: APIRouter, max_content_size: Optional[int] = None): + self.app = app + self.max_content_size = max_content_size + + def receive_wrapper(self, receive): + received = 0 + + async def inner(): + nonlocal received + message = await receive() + if message["type"] != "http.request": + return message # pragma: no cover + + body_len = len(message.get("body", b"")) + received += body_len + if received > self.max_content_size: + raise HTTPException( + 422, + detail={ + "name": "ContentSizeLimitExceeded", + "code": 999, + "message": "File limit exceeded", + }, + ) + return message + + return inner + + async def __call__(self, scope, receive, send): + if scope["type"] != "http" or self.max_content_size is None: + await self.app(scope, receive, send) + return + + wrapper = self.receive_wrapper(receive) + await self.app(scope, wrapper, send) + + +@router.post("/middleware") +def run_middleware(file: UploadFile = File(..., description="Big File")): + return {"message": "OK"} + + +app.include_router(router) +app.add_middleware(ContentSizeLimitMiddleware, max_content_size=2**8) + + +client = TestClient(app) + + +def test_custom_middleware_exception(tmp_path: Path): + default_pydantic_max_size = 2**16 + path = tmp_path / "test.txt" + path.write_bytes(b"x" * (default_pydantic_max_size + 1)) + + with client: + with open(path, "rb") as file: + response = client.post("/middleware", files={"file": file}) + assert response.status_code == 422, response.text + assert response.json() == { + "detail": { + "name": "ContentSizeLimitExceeded", + "code": 999, + "message": "File limit exceeded", + } + } + + +def test_custom_middleware_exception_not_raised(tmp_path: Path): + path = tmp_path / "test.txt" + path.write_bytes(b"") + + with client: + with open(path, "rb") as file: + response = client.post("/middleware", files={"file": file}) + assert response.status_code == 200, response.text + assert response.json() == {"message": "OK"} From af3a6ef78b01fcef5060dad63da2f4ee22a0b618 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 25 Aug 2022 21:45:33 +0000 Subject: [PATCH 689/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 337149972..0d179cb31 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Allow custom middlewares to raise `HTTPException`s and propagate them. PR [#2036](https://github.com/tiangolo/fastapi/pull/2036) by [@ghandic](https://github.com/ghandic). * ✨ Preserve `json.JSONDecodeError` information when handling invalid JSON in request body, to support custom exception handlers that use its information. PR [#4057](https://github.com/tiangolo/fastapi/pull/4057) by [@UKnowWhoIm](https://github.com/UKnowWhoIm). * ✏ Reword confusing sentence in docs file `typo-fix-path-params-numeric-validations.md`. PR [#3219](https://github.com/tiangolo/fastapi/pull/3219) by [@ccrenfroe](https://github.com/ccrenfroe). * 📝 Update docs for handling HTTP Basic Auth with `secrets.compare_digest()` to account for non-ASCII characters. PR [#3536](https://github.com/tiangolo/fastapi/pull/3536) by [@lewoudar](https://github.com/lewoudar). From ca2fae0588260f93f886aa59f689e3018e934a27 Mon Sep 17 00:00:00 2001 From: juntatalor Date: Fri, 26 Aug 2022 00:52:53 +0300 Subject: [PATCH 690/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20`Froz?= =?UTF-8?q?enSet`=20in=20parameters=20(e.g.=20query)=20(#2938)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: saborisov Co-authored-by: Sebastián Ramírez --- fastapi/dependencies/utils.py | 2 ++ tests/main.py | 7 ++++++- tests/test_application.py | 35 +++++++++++++++++++++++++++++++++++ tests/test_query.py | 1 + 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index f6151f6bd..d781fdb62 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -34,6 +34,7 @@ from pydantic import BaseModel, create_model from pydantic.error_wrappers import ErrorWrapper from pydantic.errors import MissingError from pydantic.fields import ( + SHAPE_FROZENSET, SHAPE_LIST, SHAPE_SEQUENCE, SHAPE_SET, @@ -58,6 +59,7 @@ from starlette.websockets import WebSocket sequence_shapes = { SHAPE_LIST, SHAPE_SET, + SHAPE_FROZENSET, SHAPE_TUPLE, SHAPE_SEQUENCE, SHAPE_TUPLE_ELLIPSIS, diff --git a/tests/main.py b/tests/main.py index f70496db8..fce665704 100644 --- a/tests/main.py +++ b/tests/main.py @@ -1,5 +1,5 @@ import http -from typing import Optional +from typing import FrozenSet, Optional from fastapi import FastAPI, Path, Query @@ -192,3 +192,8 @@ def get_query_param_required_type(query: int = Query()): @app.get("/enum-status-code", status_code=http.HTTPStatus.CREATED) def get_enum_status_code(): return "foo bar" + + +@app.get("/query/frozenset") +def get_query_type_frozenset(query: FrozenSet[int] = Query(...)): + return ",".join(map(str, sorted(query))) diff --git a/tests/test_application.py b/tests/test_application.py index d9194c15c..b7d72f9ad 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -1090,6 +1090,41 @@ openapi_schema = { "operationId": "get_enum_status_code_enum_status_code_get", } }, + "/query/frozenset": { + "get": { + "summary": "Get Query Type Frozenset", + "operationId": "get_query_type_frozenset_query_frozenset_get", + "parameters": [ + { + "required": True, + "schema": { + "title": "Query", + "uniqueItems": True, + "type": "array", + "items": {"type": "integer"}, + }, + "name": "query", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, }, "components": { "schemas": { diff --git a/tests/test_query.py b/tests/test_query.py index cdbdd1ccd..0c73eb665 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -53,6 +53,7 @@ response_not_valid_int = { ("/query/param-required/int", 422, response_missing), ("/query/param-required/int?query=50", 200, "foo bar 50"), ("/query/param-required/int?query=foo", 422, response_not_valid_int), + ("/query/frozenset/?query=1&query=1&query=2", 200, "1,2"), ], ) def test_get_path(path, expected_status, expected_response): From 92181ef1822920c746009d035d53009be9bab65c Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 25 Aug 2022 21:53:36 +0000 Subject: [PATCH 691/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0d179cb31..56253c873 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for `FrozenSet` in parameters (e.g. query). PR [#2938](https://github.com/tiangolo/fastapi/pull/2938) by [@juntatalor](https://github.com/juntatalor). * ✨ Allow custom middlewares to raise `HTTPException`s and propagate them. PR [#2036](https://github.com/tiangolo/fastapi/pull/2036) by [@ghandic](https://github.com/ghandic). * ✨ Preserve `json.JSONDecodeError` information when handling invalid JSON in request body, to support custom exception handlers that use its information. PR [#4057](https://github.com/tiangolo/fastapi/pull/4057) by [@UKnowWhoIm](https://github.com/UKnowWhoIm). * ✏ Reword confusing sentence in docs file `typo-fix-path-params-numeric-validations.md`. PR [#3219](https://github.com/tiangolo/fastapi/pull/3219) by [@ccrenfroe](https://github.com/ccrenfroe). From 880c8b37cf8ba88a7f4de40cf18dec49c9e71454 Mon Sep 17 00:00:00 2001 From: Ori Levari Date: Fri, 26 Aug 2022 02:26:20 -0700 Subject: [PATCH 692/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20support=20for=20ex?= =?UTF-8?q?tending=20`openapi=5Fextras`=20with=20parameter=20lists=20(#426?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/utils.py | 6 + .../test_openapi_query_parameter_extension.py | 127 ++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 tests/test_openapi_query_parameter_extension.py diff --git a/fastapi/utils.py b/fastapi/utils.py index 40750a5b3..0163fd95f 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -161,6 +161,12 @@ def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) -> and isinstance(value, dict) ): deep_dict_update(main_dict[key], value) + elif ( + key in main_dict + and isinstance(main_dict[key], list) + and isinstance(update_dict[key], list) + ): + main_dict[key] = main_dict[key] + update_dict[key] else: main_dict[key] = value diff --git a/tests/test_openapi_query_parameter_extension.py b/tests/test_openapi_query_parameter_extension.py new file mode 100644 index 000000000..d3996f26e --- /dev/null +++ b/tests/test_openapi_query_parameter_extension.py @@ -0,0 +1,127 @@ +from typing import Optional + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +app = FastAPI() + + +@app.get( + "/", + openapi_extra={ + "parameters": [ + { + "required": False, + "schema": {"title": "Extra Param 1"}, + "name": "extra_param_1", + "in": "query", + }, + { + "required": True, + "schema": {"title": "Extra Param 2"}, + "name": "extra_param_2", + "in": "query", + }, + ] + }, +) +def route_with_extra_query_parameters(standard_query_param: Optional[int] = 50): + return {} + + +client = TestClient(app) + + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "get": { + "summary": "Route With Extra Query Parameters", + "operationId": "route_with_extra_query_parameters__get", + "parameters": [ + { + "required": False, + "schema": { + "title": "Standard Query Param", + "type": "integer", + "default": 50, + }, + "name": "standard_query_param", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Extra Param 1"}, + "name": "extra_param_1", + "in": "query", + }, + { + "required": True, + "schema": {"title": "Extra Param 2"}, + "name": "extra_param_2", + "in": "query", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "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"}, + }, + }, + } + }, +} + + +def test_openapi(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_get_route(): + response = client.get("/") + assert response.status_code == 200, response.text + assert response.json() == {} From 0968329ed7aa07e66b6a55f1f5f71e4232085f4a Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 09:26:59 +0000 Subject: [PATCH 693/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 56253c873..a30e397a5 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix support for extending `openapi_extras` with parameter lists. PR [#4267](https://github.com/tiangolo/fastapi/pull/4267) by [@orilevari](https://github.com/orilevari). * ✨ Add support for `FrozenSet` in parameters (e.g. query). PR [#2938](https://github.com/tiangolo/fastapi/pull/2938) by [@juntatalor](https://github.com/juntatalor). * ✨ Allow custom middlewares to raise `HTTPException`s and propagate them. PR [#2036](https://github.com/tiangolo/fastapi/pull/2036) by [@ghandic](https://github.com/ghandic). * ✨ Preserve `json.JSONDecodeError` information when handling invalid JSON in request body, to support custom exception handlers that use its information. PR [#4057](https://github.com/tiangolo/fastapi/pull/4057) by [@UKnowWhoIm](https://github.com/UKnowWhoIm). From d5c84594cb816bc17b044fd1063a3bda3f728726 Mon Sep 17 00:00:00 2001 From: James Curtin Date: Fri, 26 Aug 2022 05:41:23 -0400 Subject: [PATCH 694/814] =?UTF-8?q?=E2=AC=86=20Upgrade=20version=20pin=20a?= =?UTF-8?q?ccepted=20for=20Flake8,=20for=20internal=20code,=20to=20`flake8?= =?UTF-8?q?=20>=3D3.8.3,<6.0.0`=20(#4097)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5ffdf93ad..9263985ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ test = [ "pytest >=6.2.4,<7.0.0", "pytest-cov >=2.12.0,<4.0.0", "mypy ==0.910", - "flake8 >=3.8.3,<4.0.0", + "flake8 >=3.8.3,<6.0.0", "black == 22.3.0", "isort >=5.0.6,<6.0.0", "requests >=2.24.0,<3.0.0", @@ -83,7 +83,7 @@ dev = [ "python-jose[cryptography] >=3.3.0,<4.0.0", "passlib[bcrypt] >=1.7.2,<2.0.0", "autoflake >=1.4.0,<2.0.0", - "flake8 >=3.8.3,<4.0.0", + "flake8 >=3.8.3,<6.0.0", "uvicorn[standard] >=0.12.0,<0.18.0", "pre-commit >=2.17.0,<3.0.0", ] From f928f3390ca3ff5fdb3575fb26f458cb93c7416c Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 09:42:03 +0000 Subject: [PATCH 695/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a30e397a5..a3186b150 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Upgrade version pin accepted for Flake8, for internal code, to `flake8 >=3.8.3,<6.0.0`. PR [#4097](https://github.com/tiangolo/fastapi/pull/4097) by [@jamescurtin](https://github.com/jamescurtin). * 🐛 Fix support for extending `openapi_extras` with parameter lists. PR [#4267](https://github.com/tiangolo/fastapi/pull/4267) by [@orilevari](https://github.com/orilevari). * ✨ Add support for `FrozenSet` in parameters (e.g. query). PR [#2938](https://github.com/tiangolo/fastapi/pull/2938) by [@juntatalor](https://github.com/juntatalor). * ✨ Allow custom middlewares to raise `HTTPException`s and propagate them. PR [#2036](https://github.com/tiangolo/fastapi/pull/2036) by [@ghandic](https://github.com/ghandic). From bb53d0b0eaad0b16a7defa640291c1ef35c95e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joon=20Hwan=20=EA=B9=80=EC=A4=80=ED=99=98?= Date: Fri, 26 Aug 2022 22:04:48 +0900 Subject: [PATCH 696/814] =?UTF-8?q?=F0=9F=8E=A8=20Fix=20syntax=20highlight?= =?UTF-8?q?ing=20in=20docs=20for=20OpenAPI=20Callbacks=20(#4368)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/openapi-callbacks.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en/docs/advanced/openapi-callbacks.md b/docs/en/docs/advanced/openapi-callbacks.md index 138c90dd7..656ddbb3f 100644 --- a/docs/en/docs/advanced/openapi-callbacks.md +++ b/docs/en/docs/advanced/openapi-callbacks.md @@ -31,7 +31,7 @@ It will have a *path operation* that will receive an `Invoice` body, and a query This part is pretty normal, most of the code is probably already familiar to you: -```Python hl_lines="10-14 37-54" +```Python hl_lines="9-13 36-53" {!../../../docs_src/openapi_callbacks/tutorial001.py!} ``` @@ -83,7 +83,7 @@ So we are going to use that same knowledge to document how the *external API* sh First create a new `APIRouter` that will contain one or more callbacks. -```Python hl_lines="5 26" +```Python hl_lines="3 25" {!../../../docs_src/openapi_callbacks/tutorial001.py!} ``` @@ -96,7 +96,7 @@ It should look just like a normal FastAPI *path operation*: * It should probably have a declaration of the body it should receive, e.g. `body: InvoiceEvent`. * And it could also have a declaration of the response it should return, e.g. `response_model=InvoiceEventReceived`. -```Python hl_lines="17-19 22-23 29-33" +```Python hl_lines="16-18 21-22 28-32" {!../../../docs_src/openapi_callbacks/tutorial001.py!} ``` @@ -163,7 +163,7 @@ At this point you have the *callback path operation(s)* needed (the one(s) that Now use the parameter `callbacks` in *your API's path operation decorator* to pass the attribute `.routes` (that's actually just a `list` of routes/*path operations*) from that callback router: -```Python hl_lines="36" +```Python hl_lines="35" {!../../../docs_src/openapi_callbacks/tutorial001.py!} ``` From 75792eb82b47a3a6bb4a971d9694456cc2760865 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:05:26 +0000 Subject: [PATCH 697/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a3186b150..bd4fa0ba4 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🎨 Fix syntax highlighting in docs for OpenAPI Callbacks. PR [#4368](https://github.com/tiangolo/fastapi/pull/4368) by [@xncbf](https://github.com/xncbf). * ⬆ Upgrade version pin accepted for Flake8, for internal code, to `flake8 >=3.8.3,<6.0.0`. PR [#4097](https://github.com/tiangolo/fastapi/pull/4097) by [@jamescurtin](https://github.com/jamescurtin). * 🐛 Fix support for extending `openapi_extras` with parameter lists. PR [#4267](https://github.com/tiangolo/fastapi/pull/4267) by [@orilevari](https://github.com/orilevari). * ✨ Add support for `FrozenSet` in parameters (e.g. query). PR [#2938](https://github.com/tiangolo/fastapi/pull/2938) by [@juntatalor](https://github.com/juntatalor). From c8124496fc34c024e411f293d3893219005d409f Mon Sep 17 00:00:00 2001 From: Muzaffer Cikay Date: Fri, 26 Aug 2022 16:16:17 +0300 Subject: [PATCH 698/814] =?UTF-8?q?=E2=99=BB=20Simplify=20conditional=20as?= =?UTF-8?q?signment=20in=20`fastapi/dependencies/utils.py`=20(#4597)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/dependencies/utils.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index d781fdb62..d098b65f1 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -302,10 +302,7 @@ def get_dependant( assert is_scalar_field( field=param_field ), "Path params must be of one of the supported types" - if isinstance(param.default, params.Path): - ignore_default = False - else: - ignore_default = True + ignore_default = not isinstance(param.default, params.Path) param_field = get_param_field( param=param, param_name=param_name, From a64387c3fc03120e3424fb12bfa64df8d949da43 Mon Sep 17 00:00:00 2001 From: Guillermo Quintana Pelayo <36505071+GuilleQP@users.noreply.github.com> Date: Fri, 26 Aug 2022 15:16:44 +0200 Subject: [PATCH 699/814] =?UTF-8?q?=E2=99=BB=20Move=20internal=20variable?= =?UTF-8?q?=20for=20errors=20in=20`jsonable=5Fencoder`=20to=20put=20relate?= =?UTF-8?q?d=20code=20closer=20(#4560)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/encoders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi/encoders.py b/fastapi/encoders.py index b1fde73ce..6f571edb2 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -137,10 +137,10 @@ def jsonable_encoder( if isinstance(obj, classes_tuple): return encoder(obj) - errors: List[Exception] = [] try: data = dict(obj) except Exception as e: + errors: List[Exception] = [] errors.append(e) try: data = vars(obj) From 923e0ac0c16b782f41bc906f4e883fa0b687fa06 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:17:04 +0000 Subject: [PATCH 700/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bd4fa0ba4..ed67fab04 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻ Simplify conditional assignment in `fastapi/dependencies/utils.py`. PR [#4597](https://github.com/tiangolo/fastapi/pull/4597) by [@cikay](https://github.com/cikay). * 🎨 Fix syntax highlighting in docs for OpenAPI Callbacks. PR [#4368](https://github.com/tiangolo/fastapi/pull/4368) by [@xncbf](https://github.com/xncbf). * ⬆ Upgrade version pin accepted for Flake8, for internal code, to `flake8 >=3.8.3,<6.0.0`. PR [#4097](https://github.com/tiangolo/fastapi/pull/4097) by [@jamescurtin](https://github.com/jamescurtin). * 🐛 Fix support for extending `openapi_extras` with parameter lists. PR [#4267](https://github.com/tiangolo/fastapi/pull/4267) by [@orilevari](https://github.com/orilevari). From ae56590c515e0ece83de951c4656c5c7d7e523c2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:17:25 +0000 Subject: [PATCH 701/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ed67fab04..74efd542f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻ Move internal variable for errors in `jsonable_encoder` to put related code closer. PR [#4560](https://github.com/tiangolo/fastapi/pull/4560) by [@GuilleQP](https://github.com/GuilleQP). * ♻ Simplify conditional assignment in `fastapi/dependencies/utils.py`. PR [#4597](https://github.com/tiangolo/fastapi/pull/4597) by [@cikay](https://github.com/cikay). * 🎨 Fix syntax highlighting in docs for OpenAPI Callbacks. PR [#4368](https://github.com/tiangolo/fastapi/pull/4368) by [@xncbf](https://github.com/xncbf). * ⬆ Upgrade version pin accepted for Flake8, for internal code, to `flake8 >=3.8.3,<6.0.0`. PR [#4097](https://github.com/tiangolo/fastapi/pull/4097) by [@jamescurtin](https://github.com/jamescurtin). From 00bdf533ef387b85a85df298de8537992c7d7c45 Mon Sep 17 00:00:00 2001 From: Shahriyar Rzayev Date: Fri, 26 Aug 2022 17:23:25 +0400 Subject: [PATCH 702/814] =?UTF-8?q?=E2=99=BB=20Change=20a=20`dict()`=20for?= =?UTF-8?q?=20`{}`=20in=20`fastapi/utils.py`=20(#3138)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi/utils.py b/fastapi/utils.py index 0163fd95f..b7da3e484 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -87,7 +87,7 @@ def create_cloned_field( ) -> ModelField: # _cloned_types has already cloned types, to support recursive models if cloned_types is None: - cloned_types = dict() + cloned_types = {} original_type = field.type_ if is_dataclass(original_type) and hasattr(original_type, "__pydantic_model__"): original_type = original_type.__pydantic_model__ From f3e9dcd891342c3818781ebccb72f43edd71d9a6 Mon Sep 17 00:00:00 2001 From: Micael Jarniac Date: Fri, 26 Aug 2022 10:24:04 -0300 Subject: [PATCH 703/814] =?UTF-8?q?=E2=9C=8F=20Fix=20typo=20in=20`docs/en/?= =?UTF-8?q?docs/python-types.md`=20(#4886)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/python-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index 3b0ee4cf6..87fdd6d8d 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -158,7 +158,7 @@ The syntax using `typing` is **compatible** with all versions, from Python 3.6 t As Python advances, **newer versions** come with improved support for these type annotations and in many cases you won't even need to import and use the `typing` module to declare the type annotations. -If you can chose a more recent version of Python for your project, you will be able to take advantage of that extra simplicity. See some examples below. +If you can choose a more recent version of Python for your project, you will be able to take advantage of that extra simplicity. See some examples below. #### List From 3df68694c01b4f897519c63dddf2cd230fc17e40 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:24:10 +0000 Subject: [PATCH 704/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 74efd542f..9e3dba5e8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻ Change a `dict()` for `{}` in `fastapi/utils.py`. PR [#3138](https://github.com/tiangolo/fastapi/pull/3138) by [@ShahriyarR](https://github.com/ShahriyarR). * ♻ Move internal variable for errors in `jsonable_encoder` to put related code closer. PR [#4560](https://github.com/tiangolo/fastapi/pull/4560) by [@GuilleQP](https://github.com/GuilleQP). * ♻ Simplify conditional assignment in `fastapi/dependencies/utils.py`. PR [#4597](https://github.com/tiangolo/fastapi/pull/4597) by [@cikay](https://github.com/cikay). * 🎨 Fix syntax highlighting in docs for OpenAPI Callbacks. PR [#4368](https://github.com/tiangolo/fastapi/pull/4368) by [@xncbf](https://github.com/xncbf). From 26097421d3aeef032cbc97b9117594fdd31af6a5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:24:42 +0000 Subject: [PATCH 705/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9e3dba5e8..fc4523537 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#4886](https://github.com/tiangolo/fastapi/pull/4886) by [@MicaelJarniac](https://github.com/MicaelJarniac). * ♻ Change a `dict()` for `{}` in `fastapi/utils.py`. PR [#3138](https://github.com/tiangolo/fastapi/pull/3138) by [@ShahriyarR](https://github.com/ShahriyarR). * ♻ Move internal variable for errors in `jsonable_encoder` to put related code closer. PR [#4560](https://github.com/tiangolo/fastapi/pull/4560) by [@GuilleQP](https://github.com/GuilleQP). * ♻ Simplify conditional assignment in `fastapi/dependencies/utils.py`. PR [#4597](https://github.com/tiangolo/fastapi/pull/4597) by [@cikay](https://github.com/cikay). From 8cd8aa4b67f06255bb0016cb478b7541766a8e31 Mon Sep 17 00:00:00 2001 From: Michael Oliver Date: Fri, 26 Aug 2022 14:25:02 +0100 Subject: [PATCH 706/814] =?UTF-8?q?=F0=9F=94=A7=20Update=20mypy=20config,?= =?UTF-8?q?=20use=20`strict=20=3D=20true`=20instead=20of=20manual=20config?= =?UTF-8?q?s=20(#4605)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- pyproject.toml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9263985ce..3b77b113b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -104,21 +104,7 @@ profile = "black" known_third_party = ["fastapi", "pydantic", "starlette"] [tool.mypy] -# --strict -disallow_any_generics = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_defs = true -disallow_incomplete_defs = true -check_untyped_defs = true -disallow_untyped_decorators = true -no_implicit_optional = true -warn_redundant_casts = true -warn_unused_ignores = true -warn_return_any = true -implicit_reexport = false -strict_equality = true -# --strict end +strict = true [[tool.mypy.overrides]] module = "fastapi.concurrency" From afe44f0b258d44822e77f9a9db965933b38add05 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:25:48 +0000 Subject: [PATCH 707/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fc4523537..ff2a7120a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update mypy config, use `strict = true` instead of manual configs. PR [#4605](https://github.com/tiangolo/fastapi/pull/4605) by [@michaeloliverx](https://github.com/michaeloliverx). * ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#4886](https://github.com/tiangolo/fastapi/pull/4886) by [@MicaelJarniac](https://github.com/MicaelJarniac). * ♻ Change a `dict()` for `{}` in `fastapi/utils.py`. PR [#3138](https://github.com/tiangolo/fastapi/pull/3138) by [@ShahriyarR](https://github.com/ShahriyarR). * ♻ Move internal variable for errors in `jsonable_encoder` to put related code closer. PR [#4560](https://github.com/tiangolo/fastapi/pull/4560) by [@GuilleQP](https://github.com/GuilleQP). From e3c055ba8f1339faa1b0d931069c028b4e36fa17 Mon Sep 17 00:00:00 2001 From: Micael Jarniac Date: Fri, 26 Aug 2022 10:26:03 -0300 Subject: [PATCH 708/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20docs,=20compare?= =?UTF-8?q?=20enums=20with=20identity=20instead=20of=20equality=20(#4905)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs_src/path_params/tutorial005.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs_src/path_params/tutorial005.py b/docs_src/path_params/tutorial005.py index 8e3767744..9a24a4963 100644 --- a/docs_src/path_params/tutorial005.py +++ b/docs_src/path_params/tutorial005.py @@ -14,7 +14,7 @@ app = FastAPI() @app.get("/models/{model_name}") async def get_model(model_name: ModelName): - if model_name == ModelName.alexnet: + if model_name is ModelName.alexnet: return {"model_name": model_name, "message": "Deep Learning FTW!"} if model_name.value == "lenet": From aaf5a380df524a3254f7acb70dd17e160220b5b4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:27:07 +0000 Subject: [PATCH 709/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ff2a7120a..cab55390e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update docs, compare enums with identity instead of equality. PR [#4905](https://github.com/tiangolo/fastapi/pull/4905) by [@MicaelJarniac](https://github.com/MicaelJarniac). * 🔧 Update mypy config, use `strict = true` instead of manual configs. PR [#4605](https://github.com/tiangolo/fastapi/pull/4605) by [@michaeloliverx](https://github.com/michaeloliverx). * ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#4886](https://github.com/tiangolo/fastapi/pull/4886) by [@MicaelJarniac](https://github.com/MicaelJarniac). * ♻ Change a `dict()` for `{}` in `fastapi/utils.py`. PR [#3138](https://github.com/tiangolo/fastapi/pull/3138) by [@ShahriyarR](https://github.com/ShahriyarR). From 0539dd9cd35b7eb3b19945c19c1dc569440c0ec1 Mon Sep 17 00:00:00 2001 From: David Kim Date: Fri, 26 Aug 2022 22:29:50 +0900 Subject: [PATCH 710/814] =?UTF-8?q?=F0=9F=94=A7=20Fix=20Type=20hint=20of?= =?UTF-8?q?=20`auto=5Ferror`=20which=20does=20not=20need=20to=20be=20`Opti?= =?UTF-8?q?onal[bool]`=20(#4933)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/security/oauth2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py index 888208c15..653c3010e 100644 --- a/fastapi/security/oauth2.py +++ b/fastapi/security/oauth2.py @@ -119,7 +119,7 @@ class OAuth2(SecurityBase): flows: Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]] = OAuthFlowsModel(), scheme_name: Optional[str] = None, description: Optional[str] = None, - auto_error: Optional[bool] = True + auto_error: bool = True ): self.model = OAuth2Model(flows=flows, description=description) self.scheme_name = scheme_name or self.__class__.__name__ From 96c3f44a0e2063199d798c685f562b15422f61e2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:30:28 +0000 Subject: [PATCH 711/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index cab55390e..e90ff2463 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Fix Type hint of `auto_error` which does not need to be `Optional[bool]`. PR [#4933](https://github.com/tiangolo/fastapi/pull/4933) by [@DavidKimDY](https://github.com/DavidKimDY). * 📝 Update docs, compare enums with identity instead of equality. PR [#4905](https://github.com/tiangolo/fastapi/pull/4905) by [@MicaelJarniac](https://github.com/MicaelJarniac). * 🔧 Update mypy config, use `strict = true` instead of manual configs. PR [#4605](https://github.com/tiangolo/fastapi/pull/4605) by [@michaeloliverx](https://github.com/michaeloliverx). * ✏ Fix typo in `docs/en/docs/python-types.md`. PR [#4886](https://github.com/tiangolo/fastapi/pull/4886) by [@MicaelJarniac](https://github.com/MicaelJarniac). From dde140d8e35e82d56f5aa0064942da1e6c9cf238 Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Fri, 26 Aug 2022 08:32:30 -0500 Subject: [PATCH 712/814] =?UTF-8?q?=F0=9F=93=9D=20Simplify=20example=20for?= =?UTF-8?q?=20docs=20for=20Additional=20Responses,=20remove=20unnecessary?= =?UTF-8?q?=20`else`=20(#4693)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/additional-responses.md | 2 +- docs_src/additional_responses/tutorial001.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/en/docs/advanced/additional-responses.md b/docs/en/docs/advanced/additional-responses.md index 5d136da41..dca5f6a98 100644 --- a/docs/en/docs/advanced/additional-responses.md +++ b/docs/en/docs/advanced/additional-responses.md @@ -23,7 +23,7 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write: -```Python hl_lines="18 23" +```Python hl_lines="18 22" {!../../../docs_src/additional_responses/tutorial001.py!} ``` diff --git a/docs_src/additional_responses/tutorial001.py b/docs_src/additional_responses/tutorial001.py index 79dcc2efe..ffa821b91 100644 --- a/docs_src/additional_responses/tutorial001.py +++ b/docs_src/additional_responses/tutorial001.py @@ -19,5 +19,4 @@ app = FastAPI() async def read_item(item_id: str): if item_id == "foo": return {"id": "foo", "value": "there goes my hero"} - else: - return JSONResponse(status_code=404, content={"message": "Item not found"}) + return JSONResponse(status_code=404, content={"message": "Item not found"}) From d80b065b5e696d65fbd139c539266276e0d0817d Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:33:08 +0000 Subject: [PATCH 713/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e90ff2463..9c61b19d8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Simplify example for docs for Additional Responses, remove unnecessary `else`. PR [#4693](https://github.com/tiangolo/fastapi/pull/4693) by [@adriangb](https://github.com/adriangb). * 🔧 Fix Type hint of `auto_error` which does not need to be `Optional[bool]`. PR [#4933](https://github.com/tiangolo/fastapi/pull/4933) by [@DavidKimDY](https://github.com/DavidKimDY). * 📝 Update docs, compare enums with identity instead of equality. PR [#4905](https://github.com/tiangolo/fastapi/pull/4905) by [@MicaelJarniac](https://github.com/MicaelJarniac). * 🔧 Update mypy config, use `strict = true` instead of manual configs. PR [#4605](https://github.com/tiangolo/fastapi/pull/4605) by [@michaeloliverx](https://github.com/michaeloliverx). From 1f2070af20f889c956b13aa79313532cf0956b71 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:44:50 +0000 Subject: [PATCH 715/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9c61b19d8..fe3a0961b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Update `ko/mkdocs.yml` for a missing link. PR [#5020](https://github.com/tiangolo/fastapi/pull/5020) by [@dalinaum](https://github.com/dalinaum). * 📝 Simplify example for docs for Additional Responses, remove unnecessary `else`. PR [#4693](https://github.com/tiangolo/fastapi/pull/4693) by [@adriangb](https://github.com/adriangb). * 🔧 Fix Type hint of `auto_error` which does not need to be `Optional[bool]`. PR [#4933](https://github.com/tiangolo/fastapi/pull/4933) by [@DavidKimDY](https://github.com/DavidKimDY). * 📝 Update docs, compare enums with identity instead of equality. PR [#4905](https://github.com/tiangolo/fastapi/pull/4905) by [@MicaelJarniac](https://github.com/MicaelJarniac). From dc10b81d05fc4438038d74543333661073bf7c8a Mon Sep 17 00:00:00 2001 From: pylounge <78209508+pylounge@users.noreply.github.com> Date: Fri, 26 Aug 2022 16:46:22 +0300 Subject: [PATCH 716/814] =?UTF-8?q?=E2=99=BB=20Simplify=20internal=20RegEx?= =?UTF-8?q?=20in=20`fastapi/utils.py`=20(#5057)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- fastapi/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastapi/utils.py b/fastapi/utils.py index b7da3e484..0ced01252 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -140,14 +140,14 @@ def generate_operation_id_for_path( stacklevel=2, ) operation_id = name + path - operation_id = re.sub("[^0-9a-zA-Z_]", "_", operation_id) + operation_id = re.sub(r"\W", "_", operation_id) operation_id = operation_id + "_" + method.lower() return operation_id def generate_unique_id(route: "APIRoute") -> str: operation_id = route.name + route.path_format - operation_id = re.sub("[^0-9a-zA-Z_]", "_", operation_id) + operation_id = re.sub(r"\W", "_", operation_id) assert route.methods operation_id = operation_id + "_" + list(route.methods)[0].lower() return operation_id From 26c68c6e0d95ff7b915365c9e78c2da93538f011 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 26 Aug 2022 13:47:11 +0000 Subject: [PATCH 717/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fe3a0961b..bd2d78fa1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻ Simplify internal RegEx in `fastapi/utils.py`. PR [#5057](https://github.com/tiangolo/fastapi/pull/5057) by [@pylounge](https://github.com/pylounge). * 🌐 Update `ko/mkdocs.yml` for a missing link. PR [#5020](https://github.com/tiangolo/fastapi/pull/5020) by [@dalinaum](https://github.com/dalinaum). * 📝 Simplify example for docs for Additional Responses, remove unnecessary `else`. PR [#4693](https://github.com/tiangolo/fastapi/pull/4693) by [@adriangb](https://github.com/adriangb). * 🔧 Fix Type hint of `auto_error` which does not need to be `Optional[bool]`. PR [#4933](https://github.com/tiangolo/fastapi/pull/4933) by [@DavidKimDY](https://github.com/DavidKimDY). From de6ccd77544b0c6e5bdcf2f470e6fd1a068344ef Mon Sep 17 00:00:00 2001 From: Erik Vroon Date: Fri, 26 Aug 2022 06:56:07 -0700 Subject: [PATCH 718/814] =?UTF-8?q?=E2=9C=A8=20Add=20ReDoc=20`
-
+
From 173b8916034d15bd96084e60b05f7713f3e92713 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Sep 2022 09:53:06 +0000 Subject: [PATCH 761/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1e5dd927f..242327787 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Update sponsors, disable ImgWhale. PR [#5338](https://github.com/tiangolo/fastapi/pull/5338) by [@tiangolo](https://github.com/tiangolo). * 📝 Update docs for `ORJSONResponse` with details about improving performance. PR [#2615](https://github.com/tiangolo/fastapi/pull/2615) by [@falkben](https://github.com/falkben). * 📝 Add docs for creating a custom Response class. PR [#5331](https://github.com/tiangolo/fastapi/pull/5331) by [@tiangolo](https://github.com/tiangolo). * 📝 Add tip about using alias for form data fields. PR [#5329](https://github.com/tiangolo/fastapi/pull/5329) by [@tiangolo](https://github.com/tiangolo). From 7250c194da6fae6155817c4b30bcdd112acce655 Mon Sep 17 00:00:00 2001 From: "abc.zxy" Date: Fri, 2 Sep 2022 18:17:31 +0800 Subject: [PATCH 762/814] =?UTF-8?q?=E2=9C=A8=20Update=20`ORJSONResponse`?= =?UTF-8?q?=20to=20support=20non=20`str`=20keys=20and=20serializing=20Nump?= =?UTF-8?q?y=20arrays=20(#3892)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- fastapi/responses.py | 4 +++- tests/test_orjson_response_class.py | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/test_orjson_response_class.py diff --git a/fastapi/responses.py b/fastapi/responses.py index 6cd793157..88dba96e8 100644 --- a/fastapi/responses.py +++ b/fastapi/responses.py @@ -31,4 +31,6 @@ class ORJSONResponse(JSONResponse): def render(self, content: Any) -> bytes: assert orjson is not None, "orjson must be installed to use ORJSONResponse" - return orjson.dumps(content) + return orjson.dumps( + content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY + ) diff --git a/tests/test_orjson_response_class.py b/tests/test_orjson_response_class.py new file mode 100644 index 000000000..6fe62daf9 --- /dev/null +++ b/tests/test_orjson_response_class.py @@ -0,0 +1,21 @@ +from fastapi import FastAPI +from fastapi.responses import ORJSONResponse +from fastapi.testclient import TestClient +from sqlalchemy.sql.elements import quoted_name + +app = FastAPI(default_response_class=ORJSONResponse) + + +@app.get("/orjson_non_str_keys") +def get_orjson_non_str_keys(): + key = quoted_name(value="msg", quote=False) + return {key: "Hello World", 1: 1} + + +client = TestClient(app) + + +def test_orjson_non_str_keys(): + with client: + response = client.get("/orjson_non_str_keys") + assert response.json() == {"msg": "Hello World", "1": 1} From b1d0f1e9703b8f163896864e1eef7faf4a7ce661 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Sep 2022 10:18:09 +0000 Subject: [PATCH 763/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 242327787..7ce9a74e9 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Update `ORJSONResponse` to support non `str` keys and serializing Numpy arrays. PR [#3892](https://github.com/tiangolo/fastapi/pull/3892) by [@baby5](https://github.com/baby5). * 🔧 Update sponsors, disable ImgWhale. PR [#5338](https://github.com/tiangolo/fastapi/pull/5338) by [@tiangolo](https://github.com/tiangolo). * 📝 Update docs for `ORJSONResponse` with details about improving performance. PR [#2615](https://github.com/tiangolo/fastapi/pull/2615) by [@falkben](https://github.com/falkben). * 📝 Add docs for creating a custom Response class. PR [#5331](https://github.com/tiangolo/fastapi/pull/5331) by [@tiangolo](https://github.com/tiangolo). From 30b3905ef38532c867036c1b650a9ceef5bfb1cc Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 2 Sep 2022 14:43:21 +0200 Subject: [PATCH 764/814] =?UTF-8?q?=E2=9C=A8=20Support=20Python=20internal?= =?UTF-8?q?=20description=20on=20Pydantic=20model's=20docstring=20(#3032)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fastapi/utils.py b/fastapi/utils.py index 0ced01252..89f54453b 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -37,6 +37,8 @@ def get_model_definitions( ) definitions.update(m_definitions) model_name = model_name_map[model] + if "description" in m_schema: + m_schema["description"] = m_schema["description"].split("\f")[0] definitions[model_name] = m_schema return definitions From e7e6404faf41836bc74978714381c2587b53c0c3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Sep 2022 12:44:09 +0000 Subject: [PATCH 765/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7ce9a74e9..7f2cc6df2 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Support Python internal description on Pydantic model's docstring. PR [#3032](https://github.com/tiangolo/fastapi/pull/3032) by [@Kludex](https://github.com/Kludex). * ✨ Update `ORJSONResponse` to support non `str` keys and serializing Numpy arrays. PR [#3892](https://github.com/tiangolo/fastapi/pull/3892) by [@baby5](https://github.com/baby5). * 🔧 Update sponsors, disable ImgWhale. PR [#5338](https://github.com/tiangolo/fastapi/pull/5338) by [@tiangolo](https://github.com/tiangolo). * 📝 Update docs for `ORJSONResponse` with details about improving performance. PR [#2615](https://github.com/tiangolo/fastapi/pull/2615) by [@falkben](https://github.com/falkben). From 52b5b08910356b22cb9837bda88f73f517dd8652 Mon Sep 17 00:00:00 2001 From: Junghoon Yang Date: Fri, 2 Sep 2022 22:36:00 +0900 Subject: [PATCH 766/814] =?UTF-8?q?=E2=99=BB=20Internal=20small=20refactor?= =?UTF-8?q?,=20move=20`operation=5Fid`=20parameter=20position=20in=20delet?= =?UTF-8?q?e=20method=20for=20consistency=20with=20the=20code=20(#4474)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/applications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index ac6050ca4..a242c504c 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -635,10 +635,10 @@ class FastAPI(Starlette): response_description=response_description, responses=responses, deprecated=deprecated, + operation_id=operation_id, response_model_include=response_model_include, response_model_exclude=response_model_exclude, response_model_by_alias=response_model_by_alias, - operation_id=operation_id, response_model_exclude_unset=response_model_exclude_unset, response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, From fbe1a803fc98901a273177d06c4fa8ccb2bcd635 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 Sep 2022 13:36:48 +0000 Subject: [PATCH 767/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7f2cc6df2..7b956f3f7 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻ Internal small refactor, move `operation_id` parameter position in delete method for consistency with the code. PR [#4474](https://github.com/tiangolo/fastapi/pull/4474) by [@hiel](https://github.com/hiel). * ✨ Support Python internal description on Pydantic model's docstring. PR [#3032](https://github.com/tiangolo/fastapi/pull/3032) by [@Kludex](https://github.com/Kludex). * ✨ Update `ORJSONResponse` to support non `str` keys and serializing Numpy arrays. PR [#3892](https://github.com/tiangolo/fastapi/pull/3892) by [@baby5](https://github.com/baby5). * 🔧 Update sponsors, disable ImgWhale. PR [#5338](https://github.com/tiangolo/fastapi/pull/5338) by [@tiangolo](https://github.com/tiangolo). From 56f887de15f25157114820d0d5c5ed5e606d53f0 Mon Sep 17 00:00:00 2001 From: Charlie DiGiovanna Date: Sat, 3 Sep 2022 13:12:41 -0400 Subject: [PATCH 768/814] =?UTF-8?q?=F0=9F=90=9B=20Make=20sure=20a=20parame?= =?UTF-8?q?ter=20defined=20as=20required=20is=20kept=20required=20in=20Ope?= =?UTF-8?q?nAPI=20even=20if=20defined=20as=20optional=20in=20another=20dep?= =?UTF-8?q?endency=20(#4319)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/openapi/utils.py | 17 ++- tests/test_enforce_once_required_parameter.py | 111 ++++++++++++++++++ 2 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 tests/test_enforce_once_required_parameter.py diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 4d5741f30..86e15b46d 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -222,11 +222,18 @@ def get_openapi_path( ) parameters.extend(operation_parameters) if parameters: - operation["parameters"] = list( - { - (param["in"], param["name"]): param for param in parameters - }.values() - ) + all_parameters = { + (param["in"], param["name"]): param for param in parameters + } + required_parameters = { + (param["in"], param["name"]): param + for param in parameters + if param.get("required") + } + # Make sure required definitions of the same parameter take precedence + # over non-required definitions + all_parameters.update(required_parameters) + operation["parameters"] = list(all_parameters.values()) if method in METHODS_WITH_BODY: request_body_oai = get_openapi_operation_request_body( body_field=route.body_field, model_name_map=model_name_map diff --git a/tests/test_enforce_once_required_parameter.py b/tests/test_enforce_once_required_parameter.py new file mode 100644 index 000000000..ba8c7353f --- /dev/null +++ b/tests/test_enforce_once_required_parameter.py @@ -0,0 +1,111 @@ +from typing import Optional + +from fastapi import Depends, FastAPI, Query, status +from fastapi.testclient import TestClient + +app = FastAPI() + + +def _get_client_key(client_id: str = Query(...)) -> str: + return f"{client_id}_key" + + +def _get_client_tag(client_id: Optional[str] = Query(None)) -> Optional[str]: + if client_id is None: + return None + return f"{client_id}_tag" + + +@app.get("/foo") +def foo_handler( + client_key: str = Depends(_get_client_key), + client_tag: Optional[str] = Depends(_get_client_tag), +): + return {"client_id": client_key, "client_tag": client_tag} + + +client = TestClient(app) + +expected_schema = { + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "title": "Detail", + "type": "array", + } + }, + "title": "HTTPValidationError", + "type": "object", + }, + "ValidationError": { + "properties": { + "loc": { + "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, + "title": "Location", + "type": "array", + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error " "Type", "type": "string"}, + }, + "required": ["loc", "msg", "type"], + "title": "ValidationError", + "type": "object", + }, + } + }, + "info": {"title": "FastAPI", "version": "0.1.0"}, + "openapi": "3.0.2", + "paths": { + "/foo": { + "get": { + "operationId": "foo_handler_foo_get", + "parameters": [ + { + "in": "query", + "name": "client_id", + "required": True, + "schema": {"title": "Client Id", "type": "string"}, + }, + ], + "responses": { + "200": { + "content": {"application/json": {"schema": {}}}, + "description": "Successful " "Response", + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation " "Error", + }, + }, + "summary": "Foo Handler", + } + } + }, +} + + +def test_schema(): + response = client.get("/openapi.json") + assert response.status_code == status.HTTP_200_OK + actual_schema = response.json() + assert actual_schema == expected_schema + + +def test_get_invalid(): + response = client.get("/foo", params={"client_id": None}) + assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY + + +def test_get_valid(): + response = client.get("/foo", params={"client_id": "bar"}) + assert response.status_code == 200 + assert response.json() == {"client_id": "bar_key", "client_tag": "bar_tag"} From dbb43da9c00380d4cfee6e6fb01853eb2dfb0189 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 3 Sep 2022 17:13:24 +0000 Subject: [PATCH 769/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7b956f3f7..8acf8d004 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Make sure a parameter defined as required is kept required in OpenAPI even if defined as optional in another dependency. PR [#4319](https://github.com/tiangolo/fastapi/pull/4319) by [@cd17822](https://github.com/cd17822). * ♻ Internal small refactor, move `operation_id` parameter position in delete method for consistency with the code. PR [#4474](https://github.com/tiangolo/fastapi/pull/4474) by [@hiel](https://github.com/hiel). * ✨ Support Python internal description on Pydantic model's docstring. PR [#3032](https://github.com/tiangolo/fastapi/pull/3032) by [@Kludex](https://github.com/Kludex). * ✨ Update `ORJSONResponse` to support non `str` keys and serializing Numpy arrays. PR [#3892](https://github.com/tiangolo/fastapi/pull/3892) by [@baby5](https://github.com/baby5). From 0e7478d39c503a6ed472503a24a06d7ec9bbf013 Mon Sep 17 00:00:00 2001 From: sjyothi54 <99384747+sjyothi54@users.noreply.github.com> Date: Sun, 4 Sep 2022 18:31:08 +0530 Subject: [PATCH 770/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20link=20to=20New=20?= =?UTF-8?q?Relic=20article:=20"How=20to=20monitor=20FastAPI=20application?= =?UTF-8?q?=20performance=20using=20Python=20agent"=20(#5260)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/data/external_links.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index e7bd0530b..e9c4ef2f2 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,9 @@ articles: english: + - author: New Relic + author_link: https://newrelic.com + link: https://newrelic.com/instant-observability/fastapi/e559ec64-f765-4470-a15f-1901fcebb468 + title: How to monitor FastAPI application performance using Python agent - author: Jean-Baptiste Rocher author_link: https://hashnode.com/@jibrocher link: https://dev.indooroutdoor.io/series/fastapi-react-poll-app From fae28a9bd7f806d1bd2c01f053ea6c9a297fd4a6 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 13:01:40 +0000 Subject: [PATCH 771/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8acf8d004..f9b90f05c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add link to New Relic article: "How to monitor FastAPI application performance using Python agent". PR [#5260](https://github.com/tiangolo/fastapi/pull/5260) by [@sjyothi54](https://github.com/sjyothi54). * 🐛 Make sure a parameter defined as required is kept required in OpenAPI even if defined as optional in another dependency. PR [#4319](https://github.com/tiangolo/fastapi/pull/4319) by [@cd17822](https://github.com/cd17822). * ♻ Internal small refactor, move `operation_id` parameter position in delete method for consistency with the code. PR [#4474](https://github.com/tiangolo/fastapi/pull/4474) by [@hiel](https://github.com/hiel). * ✨ Support Python internal description on Pydantic model's docstring. PR [#3032](https://github.com/tiangolo/fastapi/pull/3032) by [@Kludex](https://github.com/Kludex). From d3ff7c620aa7b07acec0eedd1139f24ffa86b97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=9E=E6=B3=95=E6=93=8D=E4=BD=9C?= Date: Sun, 4 Sep 2022 21:18:08 +0800 Subject: [PATCH 772/814] =?UTF-8?q?=E2=9C=8F=20Fix=20a=20small=20code=20hi?= =?UTF-8?q?ghlight=20line=20error=20(#5256)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/tutorial/query-params-str-validations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/query-params-str-validations.md b/docs/en/docs/tutorial/query-params-str-validations.md index c5fc35b88..060e1d58a 100644 --- a/docs/en/docs/tutorial/query-params-str-validations.md +++ b/docs/en/docs/tutorial/query-params-str-validations.md @@ -216,7 +216,7 @@ To do that, you can declare that `None` is a valid type but still use `default=. === "Python 3.6 and above" - ```Python hl_lines="8" + ```Python hl_lines="9" {!> ../../../docs_src/query_params_str_validations/tutorial006c.py!} ``` From c00e1ec6bff30c98201d823467c67db51d1479ea Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 13:18:44 +0000 Subject: [PATCH 773/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f9b90f05c..224ac9a52 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Fix a small code highlight line error. PR [#5256](https://github.com/tiangolo/fastapi/pull/5256) by [@hjlarry](https://github.com/hjlarry). * 📝 Add link to New Relic article: "How to monitor FastAPI application performance using Python agent". PR [#5260](https://github.com/tiangolo/fastapi/pull/5260) by [@sjyothi54](https://github.com/sjyothi54). * 🐛 Make sure a parameter defined as required is kept required in OpenAPI even if defined as optional in another dependency. PR [#4319](https://github.com/tiangolo/fastapi/pull/4319) by [@cd17822](https://github.com/cd17822). * ♻ Internal small refactor, move `operation_id` parameter position in delete method for consistency with the code. PR [#4474](https://github.com/tiangolo/fastapi/pull/4474) by [@hiel](https://github.com/hiel). From 68e04f653143ea4836a2b536cd74d0b36af36693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Victor=20Ribeiro=20Silva?= Date: Sun, 4 Sep 2022 10:23:34 -0300 Subject: [PATCH 774/814] =?UTF-8?q?=F0=9F=8C=90=20Fix=20MkDocs=20file=20li?= =?UTF-8?q?ne=20for=20Portuguese=20translation=20of=20`background-task.md`?= =?UTF-8?q?=20(#5242)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/pt/mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml index 5e4ceb66f..59ee3cc88 100644 --- a/docs/pt/mkdocs.yml +++ b/docs/pt/mkdocs.yml @@ -74,6 +74,7 @@ nav: - tutorial/handling-errors.md - Segurança: - tutorial/security/index.md + - tutorial/background-tasks.md - Guia de Usuário Avançado: - advanced/index.md - Implantação: From 198b7ef2cb9bf6e5ab0b13819197b39aa80229ca Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 13:24:23 +0000 Subject: [PATCH 775/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 224ac9a52..5d359dddc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix MkDocs file line for Portuguese translation of `background-task.md`. PR [#5242](https://github.com/tiangolo/fastapi/pull/5242) by [@ComicShrimp](https://github.com/ComicShrimp). * ✏ Fix a small code highlight line error. PR [#5256](https://github.com/tiangolo/fastapi/pull/5256) by [@hjlarry](https://github.com/hjlarry). * 📝 Add link to New Relic article: "How to monitor FastAPI application performance using Python agent". PR [#5260](https://github.com/tiangolo/fastapi/pull/5260) by [@sjyothi54](https://github.com/sjyothi54). * 🐛 Make sure a parameter defined as required is kept required in OpenAPI even if defined as optional in another dependency. PR [#4319](https://github.com/tiangolo/fastapi/pull/4319) by [@cd17822](https://github.com/cd17822). From ae369d879af021fa3477a39155981f346578a078 Mon Sep 17 00:00:00 2001 From: MendyLanda <54242706+MendyLanda@users.noreply.github.com> Date: Sun, 4 Sep 2022 09:29:06 -0400 Subject: [PATCH 776/814] =?UTF-8?q?=F0=9F=93=9D=20Add=20note=20about=20Pyt?= =?UTF-8?q?hon=203.10=20`X=20|=20Y`=20operator=20in=20explanation=20about?= =?UTF-8?q?=20Response=20Models=20(#5307)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/tutorial/response-model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md index 2bbd4d4fd..ab68314e8 100644 --- a/docs/en/docs/tutorial/response-model.md +++ b/docs/en/docs/tutorial/response-model.md @@ -168,7 +168,7 @@ Your response model could have default values, like: {!> ../../../docs_src/response_model/tutorial004_py310.py!} ``` -* `description: Union[str, None] = None` has a default of `None`. +* `description: Union[str, None] = None` (or `str | None = None` in Python 3.10) has a default of `None`. * `tax: float = 10.5` has a default of `10.5`. * `tags: List[str] = []` as a default of an empty list: `[]`. From 697ec94a7e90a0798cdcd3c83fa230aba0b2a3a2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 13:29:46 +0000 Subject: [PATCH 777/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5d359dddc..ab431c379 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add note about Python 3.10 `X | Y` operator in explanation about Response Models. PR [#5307](https://github.com/tiangolo/fastapi/pull/5307) by [@MendyLanda](https://github.com/MendyLanda). * 🌐 Fix MkDocs file line for Portuguese translation of `background-task.md`. PR [#5242](https://github.com/tiangolo/fastapi/pull/5242) by [@ComicShrimp](https://github.com/ComicShrimp). * ✏ Fix a small code highlight line error. PR [#5256](https://github.com/tiangolo/fastapi/pull/5256) by [@hjlarry](https://github.com/hjlarry). * 📝 Add link to New Relic article: "How to monitor FastAPI application performance using Python agent". PR [#5260](https://github.com/tiangolo/fastapi/pull/5260) by [@sjyothi54](https://github.com/sjyothi54). From f266dc17d7a3e6e9d2de0ff3d5b54bea8b7874ba Mon Sep 17 00:00:00 2001 From: Peter Fackeldey Date: Sun, 4 Sep 2022 15:37:47 +0200 Subject: [PATCH 778/814] =?UTF-8?q?=E2=9C=8F=20Tweak=20wording=20in=20`doc?= =?UTF-8?q?s/en/docs/advanced/dataclasses.md`=20(#3698)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/dataclasses.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/advanced/dataclasses.md b/docs/en/docs/advanced/dataclasses.md index 80a063bb8..72daca06a 100644 --- a/docs/en/docs/advanced/dataclasses.md +++ b/docs/en/docs/advanced/dataclasses.md @@ -8,7 +8,7 @@ But FastAPI also supports using internal support for `dataclasses`. +This is still supported thanks to **Pydantic**, as it has internal support for `dataclasses`. So, even with the code above that doesn't use Pydantic explicitly, FastAPI is using Pydantic to convert those standard dataclasses to Pydantic's own flavor of dataclasses. From 89839eb83470b42b96cd285c2764577b9409aade Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 13:38:49 +0000 Subject: [PATCH 779/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ab431c379..9f3e2f7b5 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Tweak wording in `docs/en/docs/advanced/dataclasses.md`. PR [#3698](https://github.com/tiangolo/fastapi/pull/3698) by [@pfackeldey](https://github.com/pfackeldey). * 📝 Add note about Python 3.10 `X | Y` operator in explanation about Response Models. PR [#5307](https://github.com/tiangolo/fastapi/pull/5307) by [@MendyLanda](https://github.com/MendyLanda). * 🌐 Fix MkDocs file line for Portuguese translation of `background-task.md`. PR [#5242](https://github.com/tiangolo/fastapi/pull/5242) by [@ComicShrimp](https://github.com/ComicShrimp). * ✏ Fix a small code highlight line error. PR [#5256](https://github.com/tiangolo/fastapi/pull/5256) by [@hjlarry](https://github.com/hjlarry). From 0d43b6552b30bb81d2f62536cc4faa5aa4251e64 Mon Sep 17 00:00:00 2001 From: Zssaer <45691504+Zssaer@users.noreply.github.com> Date: Sun, 4 Sep 2022 21:39:06 +0800 Subject: [PATCH 780/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translat?= =?UTF-8?q?ion=20for=20`docs/zh/docs/tutorial/encoder.md`=20(#4969)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zh/docs/tutorial/encoder.md | 42 ++++++++++++++++++++++++++++++++ docs/zh/mkdocs.yml | 1 + 2 files changed, 43 insertions(+) create mode 100644 docs/zh/docs/tutorial/encoder.md diff --git a/docs/zh/docs/tutorial/encoder.md b/docs/zh/docs/tutorial/encoder.md new file mode 100644 index 000000000..cb813940c --- /dev/null +++ b/docs/zh/docs/tutorial/encoder.md @@ -0,0 +1,42 @@ +# JSON 兼容编码器 + +在某些情况下,您可能需要将数据类型(如Pydantic模型)转换为与JSON兼容的数据类型(如`dict`、`list`等)。 + +比如,如果您需要将其存储在数据库中。 + +对于这种要求, **FastAPI**提供了`jsonable_encoder()`函数。 + +## 使用`jsonable_encoder` + +让我们假设你有一个数据库名为`fake_db`,它只能接收与JSON兼容的数据。 + +例如,它不接收`datetime`这类的对象,因为这些对象与JSON不兼容。 + +因此,`datetime`对象必须将转换为包含ISO格式化的`str`类型对象。 + +同样,这个数据库也不会接收Pydantic模型(带有属性的对象),而只接收`dict`。 + +对此你可以使用`jsonable_encoder`。 + +它接收一个对象,比如Pydantic模型,并会返回一个JSON兼容的版本: + +=== "Python 3.6 and above" + + ```Python hl_lines="5 22" + {!> ../../../docs_src/encoder/tutorial001.py!} + ``` + +=== "Python 3.10 and above" + + ```Python hl_lines="4 21" + {!> ../../../docs_src/encoder/tutorial001_py310.py!} + ``` + +在这个例子中,它将Pydantic模型转换为`dict`,并将`datetime`转换为`str`。 + +调用它的结果后就可以使用Python标准编码中的`json.dumps()`。 + +这个操作不会返回一个包含JSON格式(作为字符串)数据的庞大的`str`。它将返回一个Python标准数据结构(例如`dict`),其值和子值都与JSON兼容。 + +!!! note + `jsonable_encoder`实际上是FastAPI内部用来转换数据的。但是它在许多其他场景中也很有用。 diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index b60a0b7a1..ac8679dc0 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -85,6 +85,7 @@ nav: - tutorial/request-forms-and-files.md - tutorial/handling-errors.md - tutorial/path-operation-configuration.md + - tutorial/encoder.md - tutorial/body-updates.md - 依赖项: - tutorial/dependencies/index.md From fc559b5fcdfb0676e4534fb47a319f015db3cb43 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 13:39:50 +0000 Subject: [PATCH 781/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9f3e2f7b5..755f315dc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for `docs/zh/docs/tutorial/encoder.md`. PR [#4969](https://github.com/tiangolo/fastapi/pull/4969) by [@Zssaer](https://github.com/Zssaer). * ✏ Tweak wording in `docs/en/docs/advanced/dataclasses.md`. PR [#3698](https://github.com/tiangolo/fastapi/pull/3698) by [@pfackeldey](https://github.com/pfackeldey). * 📝 Add note about Python 3.10 `X | Y` operator in explanation about Response Models. PR [#5307](https://github.com/tiangolo/fastapi/pull/5307) by [@MendyLanda](https://github.com/MendyLanda). * 🌐 Fix MkDocs file line for Portuguese translation of `background-task.md`. PR [#5242](https://github.com/tiangolo/fastapi/pull/5242) by [@ComicShrimp](https://github.com/ComicShrimp). From dc1534736d37a03b352eedd22e5d76e55209fb49 Mon Sep 17 00:00:00 2001 From: ASpathfinder <31813636+ASpathfinder@users.noreply.github.com> Date: Sun, 4 Sep 2022 21:40:14 +0800 Subject: [PATCH 782/814] =?UTF-8?q?=F0=9F=8C=90=20Update=20Chinese=20trans?= =?UTF-8?q?lation=20for=20`docs/zh/docs/tutorial/request-files.md`=20(#452?= =?UTF-8?q?9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: KellyAlsa-massive-win Co-authored-by: Sebastián Ramírez --- docs/zh/docs/tutorial/request-files.md | 67 +++++++++++++++++++++----- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/docs/zh/docs/tutorial/request-files.md b/docs/zh/docs/tutorial/request-files.md index 25657d93b..e18d6fc9f 100644 --- a/docs/zh/docs/tutorial/request-files.md +++ b/docs/zh/docs/tutorial/request-files.md @@ -44,9 +44,9 @@ 不过,很多情况下,`UploadFile` 更好用。 -## 含 `UploadFile` 的 `File` 参数 +## 含 `UploadFile` 的文件参数 -定义 `File` 参数时使用 `UploadFile`: +定义文件参数时使用 `UploadFile`: ```Python hl_lines="12" {!../../../docs_src/request_files/tutorial001.py!} @@ -94,7 +94,7 @@ contents = myfile.file.read() !!! note "`async` 技术细节" - 使用 `async` 方法时,**FastAPI** 在线程池中执行文件方法,并 `awiat` 操作完成。 + 使用 `async` 方法时,**FastAPI** 在线程池中执行文件方法,并 `await` 操作完成。 !!! note "Starlette 技术细节" @@ -120,6 +120,30 @@ contents = myfile.file.read() 这不是 **FastAPI** 的问题,而是 HTTP 协议的规定。 +## 可选文件上传 + +您可以通过使用标准类型注解并将 None 作为默认值的方式将一个文件参数设为可选: + +=== "Python 3.6 及以上版本" + + ```Python hl_lines="9 17" + {!> ../../../docs_src/request_files/tutorial001_02.py!} + ``` + +=== "Python 3.9 及以上版本" + + ```Python hl_lines="7 14" + {!> ../../../docs_src/request_files/tutorial001_02_py310.py!} + ``` + +## 带有额外元数据的 `UploadFile` + +您也可以将 `File()` 与 `UploadFile` 一起使用,例如,设置额外的元数据: + +```Python hl_lines="13" +{!../../../docs_src/request_files/tutorial001_03.py!} +``` + ## 多文件上传 FastAPI 支持同时上传多个文件。 @@ -128,19 +152,20 @@ FastAPI 支持同时上传多个文件。 上传多个文件时,要声明含 `bytes` 或 `UploadFile` 的列表(`List`): -```Python hl_lines="10 15" -{!../../../docs_src/request_files/tutorial002.py!} -``` +=== "Python 3.6 及以上版本" + + ```Python hl_lines="10 15" + {!> ../../../docs_src/request_files/tutorial002.py!} + ``` + +=== "Python 3.9 及以上版本" + + ```Python hl_lines="8 13" + {!> ../../../docs_src/request_files/tutorial002_py39.py!} + ``` 接收的也是含 `bytes` 或 `UploadFile` 的列表(`list`)。 -!!! note "笔记" - - 注意,截至 2019 年 4 月 14 日,Swagger UI 不支持在同一个表单字段中上传多个文件。详见 #4276#3641. - - 不过,**FastAPI** 已通过 OpenAPI 标准与之兼容。 - - 因此,只要 Swagger UI 或任何其他支持 OpenAPI 的工具支持多文件上传,都将与 **FastAPI** 兼容。 !!! note "技术细节" @@ -148,6 +173,22 @@ FastAPI 支持同时上传多个文件。 `fastapi.responses` 其实与 `starlette.responses` 相同,只是为了方便开发者调用。实际上,大多数 **FastAPI** 的响应都直接从 Starlette 调用。 +### 带有额外元数据的多文件上传 + +和之前的方式一样, 您可以为 `File()` 设置额外参数, 即使是 `UploadFile`: + +=== "Python 3.6 及以上版本" + + ```Python hl_lines="18" + {!> ../../../docs_src/request_files/tutorial003.py!} + ``` + +=== "Python 3.9 及以上版本" + + ```Python hl_lines="16" + {!> ../../../docs_src/request_files/tutorial003_py39.py!} + ``` + ## 小结 本节介绍了如何用 `File` 把上传文件声明为(表单数据的)输入参数。 From 5a79564dabff2850b04e747ad85b38ecd15e0718 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 13:40:56 +0000 Subject: [PATCH 783/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 755f315dc..7a74b7f92 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Update Chinese translation for `docs/zh/docs/tutorial/request-files.md`. PR [#4529](https://github.com/tiangolo/fastapi/pull/4529) by [@ASpathfinder](https://github.com/ASpathfinder). * 🌐 Add Chinese translation for `docs/zh/docs/tutorial/encoder.md`. PR [#4969](https://github.com/tiangolo/fastapi/pull/4969) by [@Zssaer](https://github.com/Zssaer). * ✏ Tweak wording in `docs/en/docs/advanced/dataclasses.md`. PR [#3698](https://github.com/tiangolo/fastapi/pull/3698) by [@pfackeldey](https://github.com/pfackeldey). * 📝 Add note about Python 3.10 `X | Y` operator in explanation about Response Models. PR [#5307](https://github.com/tiangolo/fastapi/pull/5307) by [@MendyLanda](https://github.com/MendyLanda). From ee035dfa9a245669115dffe0c39e42234c4b1472 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 4 Sep 2022 15:59:46 +0200 Subject: [PATCH 784/814] =?UTF-8?q?=E2=AC=86=20[pre-commit.ci]=20pre-commi?= =?UTF-8?q?t=20autoupdate=20(#5318)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6e51622e7..237feb083 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: - --py3-plus - --keep-runtime-typing - repo: https://github.com/myint/autoflake - rev: v1.4 + rev: v1.5.1 hooks: - id: autoflake args: From a3a8d68715bbc344a2b8b8ac6c6f49272c09ce9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 4 Sep 2022 15:59:59 +0200 Subject: [PATCH 785/814] =?UTF-8?q?=E2=AC=86=20Bump=20dawidd6/action-downl?= =?UTF-8?q?oad-artifact=20from=202.22.0=20to=202.23.0=20(#5321)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/preview-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml index a4bf322f4..d42b08543 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/preview-docs.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Download Artifact Docs - uses: dawidd6/action-download-artifact@v2.22.0 + uses: dawidd6/action-download-artifact@v2.23.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} workflow: build-docs.yml From 94b7527dfd3e65903a6b34dea9a71c6e54e9c978 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 14:00:22 +0000 Subject: [PATCH 786/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7a74b7f92..ddbc9605d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5318](https://github.com/tiangolo/fastapi/pull/5318) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * 🌐 Update Chinese translation for `docs/zh/docs/tutorial/request-files.md`. PR [#4529](https://github.com/tiangolo/fastapi/pull/4529) by [@ASpathfinder](https://github.com/ASpathfinder). * 🌐 Add Chinese translation for `docs/zh/docs/tutorial/encoder.md`. PR [#4969](https://github.com/tiangolo/fastapi/pull/4969) by [@Zssaer](https://github.com/Zssaer). * ✏ Tweak wording in `docs/en/docs/advanced/dataclasses.md`. PR [#3698](https://github.com/tiangolo/fastapi/pull/3698) by [@pfackeldey](https://github.com/pfackeldey). From 7dd4a4f435b5381af379284af186862bd9f99712 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 14:00:36 +0000 Subject: [PATCH 787/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ddbc9605d..0da899c00 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ Bump dawidd6/action-download-artifact from 2.22.0 to 2.23.0. PR [#5321](https://github.com/tiangolo/fastapi/pull/5321) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5318](https://github.com/tiangolo/fastapi/pull/5318) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * 🌐 Update Chinese translation for `docs/zh/docs/tutorial/request-files.md`. PR [#4529](https://github.com/tiangolo/fastapi/pull/4529) by [@ASpathfinder](https://github.com/ASpathfinder). * 🌐 Add Chinese translation for `docs/zh/docs/tutorial/encoder.md`. PR [#4969](https://github.com/tiangolo/fastapi/pull/4969) by [@Zssaer](https://github.com/Zssaer). From 81967f8f9340d9288b11e48c0fa0ad415ec6b5ac Mon Sep 17 00:00:00 2001 From: Vladislav Kramorenko <85196001+Xewus@users.noreply.github.com> Date: Sun, 4 Sep 2022 17:27:48 +0300 Subject: [PATCH 788/814] =?UTF-8?q?=F0=9F=8C=90=20Add=20Russian=20translat?= =?UTF-8?q?ion=20for=20`docs/ru/docs/features.md`=20(#5315)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/ru/docs/features.md | 203 +++++++++++++++++++++++++++++++++++++++ docs/ru/mkdocs.yml | 1 + 2 files changed, 204 insertions(+) create mode 100644 docs/ru/docs/features.md diff --git a/docs/ru/docs/features.md b/docs/ru/docs/features.md new file mode 100644 index 000000000..0cec4eee2 --- /dev/null +++ b/docs/ru/docs/features.md @@ -0,0 +1,203 @@ +# Основные свойства + +## Основные свойства FastAPI + +**FastAPI** предлагает вам следующее: + +### Использование открытых стандартов + +* OpenAPI для создания API, включая объявления операций пути, параметров, тела запроса, безопасности и т.д. + + +* Автоматическое документирование моделей данных в соответствии с JSON Schema (так как спецификация OpenAPI сама основана на JSON Schema). +* Разработан, придерживаясь этих стандартов, после тщательного их изучения. Эти стандарты изначально включены во фреймфорк, а не являются дополнительной надстройкой. +* Это также позволяет использовать автоматическую **генерацию клиентского кода** на многих языках. + +### Автоматически генерируемая документация + +Интерактивная документация для API и исследования пользовательских веб-интерфейсов. Поскольку этот фреймворк основан на OpenAPI, существует несколько вариантов документирования, 2 из которых включены по умолчанию. + +* Swagger UI, с интерактивным взаимодействием, вызывает и тестирует ваш API прямо из браузера. + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Альтернативная документация API в ReDoc. + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Только современный Python + +Все эти возможности основаны на стандартных **аннотациях типов Python 3.6** (благодаря Pydantic). Не нужно изучать новый синтаксис. Только лишь стандартный современный Python. + +Если вам нужно освежить знания, как использовать аннотации типов в Python (даже если вы не используете FastAPI), выделите 2 минуты и просмотрите краткое руководство: [Введение в аннотации типов Python¶ +](python-types.md){.internal-link target=_blank}. + +Вы пишете на стандартном Python с аннотациями типов: + +```Python +from datetime import date + +from pydantic import BaseModel + +# Объявляем параметр user_id с типом `str` +# и получаем поддержку редактора внутри функции +def main(user_id: str): + return user_id + + +# Модель Pydantic +class User(BaseModel): + id: int + name: str + joined: date +``` + +Это можно использовать так: + +```Python +my_user: User = User(id=3, name="John Doe", joined="2018-07-19") + +second_user_data = { + "id": 4, + "name": "Mary", + "joined": "2018-11-30", +} + +my_second_user: User = User(**second_user_data) +``` + +!!! Информация + `**second_user_data` означает: + + Передать ключи и значения словаря `second_user_data`, в качестве аргументов типа "ключ-значение", это эквивалентно: `User(id=4, name="Mary", joined="2018-11-30")` . + +### Поддержка редакторов (IDE) + +Весь фреймворк был продуман так, чтобы быть простым и интуитивно понятным в использовании, все решения были проверены на множестве редакторов еще до начала разработки, чтобы обеспечить наилучшие условия при написании кода. + +В опросе Python-разработчиков было выяснено, что наиболее часто используемой функцией редакторов, является "автодополнение". + +Вся структура **FastAPI** основана на удовлетворении этой возможности. Автодополнение работает везде. + +Вам редко нужно будет возвращаться к документации. + +Вот как ваш редактор может вам помочь: + +* в Visual Studio Code: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +* в PyCharm: + +![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png) + +Вы будете получать автодополнение кода даже там, где вы считали это невозможным раньше. +Как пример, ключ `price` внутри тела JSON (который может быть вложенным), приходящего в запросе. + +Больше никаких неправильных имён ключей, метания по документации или прокручивания кода вверх и вниз, в попытках узнать - использовали вы ранее `username` или `user_name`. + +### Краткость +FastAPI имеет продуманные значения **по умолчанию** для всего, с произвольными настройками везде. Все параметры могут быть тонко подстроены так, чтобы делать то, что вам нужно и определять необходимый вам API. + +Но, по умолчанию, всё это **"и так работает"**. + +### Проверка значений + +* Проверка значений для большинства (или всех?) **типов данных** Python, включая: + * Объекты JSON (`dict`). + * Массивы JSON (`list`) с установленными типами элементов. + * Строковые (`str`) поля с ограничением минимальной и максимальной длины. + * Числа (`int`, `float`) с минимальными и максимальными значениями и т.п. + +* Проверка для более экзотических типов, таких как: + * URL. + * Email. + * UUID. + * ...и другие. + +Все проверки обрабатываются хорошо зарекомендовавшим себя и надежным **Pydantic**. + +### Безопасность и аутентификация + +Встроеные функции безопасности и аутентификации. Без каких-либо компромиссов с базами данных или моделями данных. + +Все схемы безопасности, определённые в OpenAPI, включая: + +* HTTP Basic. +* **OAuth2** (также с **токенами JWT**). Ознакомьтесь с руководством [OAuth2 с JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. +* Ключи API в: + * Заголовках. + * Параметрах запросов. + * Cookies и т.п. + +Вдобавок все функции безопасности от Starlette (включая **сессионные cookies**). + +Все инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т. д. + +### Внедрение зависимостей + +FastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему Внедрения зависимостей. + +* Даже зависимости могут иметь зависимости, создавая иерархию или **"графы" зависимостей**. +* Всё **автоматически обрабатывается** фреймворком. +* Все зависимости могут запрашивать данные из запросов и **дополнять операции пути** ограничениями и автоматической документацией. +* **Автоматическая проверка** даже для параметров *операций пути*, определенных в зависимостях. +* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т.д. +* **Никаких компромиссов** с базами данных, интерфейсами и т.д. Но легкая интеграция со всеми ними. + +### Нет ограничений на "Плагины" + +Или, другими словами, нет сложностей с ними, импортируйте и используйте нужный вам код. + +Любая интеграция разработана настолько простой в использовании (с зависимостями), что вы можете создать "плагин" для своего приложения в пару строк кода, используя ту же структуру и синтаксис, что и для ваших *операций пути*. + +### Проверен + +* 100% покрытие тестами. +* 100% аннотирование типов в кодовой базе. +* Используется в реально работающих приложениях. + +## Основные свойства Starlette + +**FastAPI** основан на Starlette и полностью совместим с ним. Так что, любой дополнительный код Starlette, который у вас есть, будет также работать. + +На самом деле, `FastAPI` - это класс, унаследованный от `Starlette`. Таким образом, если вы уже знаете или используете Starlette, большая часть функционала будет работать так же. + +С **FastAPI** вы получаете все возможности **Starlette** (так как FastAPI это всего лишь Starlette на стероидах): + +* Серьёзно впечатляющая производительность. Это один из самых быстрых фреймворков на Python, наравне с приложениями использующими **NodeJS** или **Go**. +* Поддержка **WebSocket**. +* Фоновые задачи для процессов. +* События запуска и выключения. +* Тестовый клиент построен на библиотеке `requests`. +* **CORS**, GZip, статические файлы, потоковые ответы. +* Поддержка **сессий и cookie**. +* 100% покрытие тестами. +* 100% аннотирование типов в кодовой базе. + +## Особенности и возможности Pydantic + +**FastAPI** основан на Pydantic и полностью совместим с ним. Так что, любой дополнительный код Pydantic, который у вас есть, будет также работать. + +Включая внешние библиотеки, также основанные на Pydantic, такие как: ORM'ы, ODM'ы для баз данных. + +Это также означает, что во многих случаях вы можете передавать тот же объект, который получили из запроса, **непосредственно в базу данных**, так как всё проверяется автоматически. + +И наоборот, во многих случаях вы можете просто передать объект, полученный из базы данных, **непосредственно клиенту**. + +С **FastAPI** вы получаете все возможности **Pydantic** (так как, FastAPI основан на Pydantic, для обработки данных): + +* **Никакой нервотрёпки** : + * Не нужно изучать новых схем в микроязыках. + * Если вы знаете аннотации типов в Python, вы знаете, как использовать Pydantic. +* Прекрасно сочетается с вашими **IDE/linter/мозгом**: + * Потому что структуры данных pydantic - это всего лишь экземпляры классов, определённых вами. Автодополнение, проверка кода, mypy и ваша интуиция - всё будет работать с вашими проверенными данными. +* **Быстродействие**: + * В тестовых замерах Pydantic быстрее, чем все другие проверенные библиотеки. +* Проверка **сложных структур**: + * Использование иерархических моделей Pydantic; `List`, `Dict` и т.п. из модуля `typing` (входит в стандартную библиотеку Python). + * Валидаторы позволяют четко и легко определять, проверять и документировать сложные схемы данных в виде JSON Schema. + * У вас могут быть глубоко **вложенные объекты JSON** и все они будут проверены и аннотированы. +* **Расширяемость**: + * Pydantic позволяет определять пользовательские типы данных или расширять проверку методами модели, с помощью проверочных декораторов. +* 100% покрытие тестами. diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 2cb5eb8e0..381775ac6 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -58,6 +58,7 @@ nav: - tr: /tr/ - uk: /uk/ - zh: /zh/ +- features.md - python-types.md - Учебник - руководство пользователя: - tutorial/background-tasks.md From 9df22ab86475ddd507985fe74d199bd80b1da42a Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 14:28:31 +0000 Subject: [PATCH 789/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0da899c00..dcf629f81 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Russian translation for `docs/ru/docs/features.md`. PR [#5315](https://github.com/tiangolo/fastapi/pull/5315) by [@Xewus](https://github.com/Xewus). * ⬆ Bump dawidd6/action-download-artifact from 2.22.0 to 2.23.0. PR [#5321](https://github.com/tiangolo/fastapi/pull/5321) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5318](https://github.com/tiangolo/fastapi/pull/5318) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * 🌐 Update Chinese translation for `docs/zh/docs/tutorial/request-files.md`. PR [#4529](https://github.com/tiangolo/fastapi/pull/4529) by [@ASpathfinder](https://github.com/ASpathfinder). From 0ae8d091892242954b12d129b627c60517c9cd1e Mon Sep 17 00:00:00 2001 From: baconfield <65581433+baconfield@users.noreply.github.com> Date: Sun, 4 Sep 2022 09:56:29 -0500 Subject: [PATCH 790/814] =?UTF-8?q?=E2=9C=8F=20Update=20Hypercorn=20link,?= =?UTF-8?q?=20now=20pointing=20to=20GitHub=20(#5346)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- README.md | 2 +- docs/en/docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 590abf17e..bc00d9ed9 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ $ pip install fastapi
-You will also need an ASGI server, for production such as Uvicorn or Hypercorn. +You will also need an ASGI server, for production such as Uvicorn or Hypercorn.
diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index 24ce14e23..97ec0ffcf 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -128,7 +128,7 @@ $ pip install fastapi
-You will also need an ASGI server, for production such as Uvicorn or Hypercorn. +You will also need an ASGI server, for production such as Uvicorn or Hypercorn.
From 0195bb57062106e44b7d17bc88e91538d9249b2b Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 14:57:04 +0000 Subject: [PATCH 791/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index dcf629f81..af4b36dde 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏ Update Hypercorn link, now pointing to GitHub. PR [#5346](https://github.com/tiangolo/fastapi/pull/5346) by [@baconfield](https://github.com/baconfield). * 🌐 Add Russian translation for `docs/ru/docs/features.md`. PR [#5315](https://github.com/tiangolo/fastapi/pull/5315) by [@Xewus](https://github.com/Xewus). * ⬆ Bump dawidd6/action-download-artifact from 2.22.0 to 2.23.0. PR [#5321](https://github.com/tiangolo/fastapi/pull/5321) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5318](https://github.com/tiangolo/fastapi/pull/5318) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). From 4cff206ebb925acfa4904bb5ddf62c6748f8b15f Mon Sep 17 00:00:00 2001 From: Irfanuddin Shafi Ahmed Date: Sun, 4 Sep 2022 20:37:12 +0530 Subject: [PATCH 792/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20FastAPI=20People?= =?UTF-8?q?=20GitHub=20Action:=20set=20HTTPX=20timeout=20for=20GraphQL=20q?= =?UTF-8?q?uery=20request=20(#5222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Irfanuddin Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- .github/actions/people/app/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/actions/people/app/main.py b/.github/actions/people/app/main.py index 1455d01ca..cdf423b97 100644 --- a/.github/actions/people/app/main.py +++ b/.github/actions/people/app/main.py @@ -260,6 +260,7 @@ class Settings(BaseSettings): input_token: SecretStr input_standard_token: SecretStr github_repository: str + httpx_timeout: int = 30 def get_graphql_response( @@ -270,9 +271,10 @@ def get_graphql_response( response = httpx.post( github_graphql_url, headers=headers, + timeout=settings.httpx_timeout, json={"query": query, "variables": variables, "operationName": "Q"}, ) - if not response.status_code == 200: + if response.status_code != 200: logging.error(f"Response was not 200, after: {after}") logging.error(response.text) raise RuntimeError(response.text) From dd2f759bac14b1ecf259c5d9cafe72e211c0e69e Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 15:07:46 +0000 Subject: [PATCH 793/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index af4b36dde..34183c140 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix FastAPI People GitHub Action: set HTTPX timeout for GraphQL query request. PR [#5222](https://github.com/tiangolo/fastapi/pull/5222) by [@iudeen](https://github.com/iudeen). * ✏ Update Hypercorn link, now pointing to GitHub. PR [#5346](https://github.com/tiangolo/fastapi/pull/5346) by [@baconfield](https://github.com/baconfield). * 🌐 Add Russian translation for `docs/ru/docs/features.md`. PR [#5315](https://github.com/tiangolo/fastapi/pull/5315) by [@Xewus](https://github.com/Xewus). * ⬆ Bump dawidd6/action-download-artifact from 2.22.0 to 2.23.0. PR [#5321](https://github.com/tiangolo/fastapi/pull/5321) by [@dependabot[bot]](https://github.com/apps/dependabot). From dacb68929082060b46848c237a3a23085eab947b Mon Sep 17 00:00:00 2001 From: Mateusz Nowak Date: Sun, 4 Sep 2022 17:12:10 +0200 Subject: [PATCH 794/814] =?UTF-8?q?=E2=9C=A8=20Export=20`WebSocketState`?= =?UTF-8?q?=20in=20`fastapi.websockets`=20(#4376)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/websockets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fastapi/websockets.py b/fastapi/websockets.py index bed672acf..55a4ac4a1 100644 --- a/fastapi/websockets.py +++ b/fastapi/websockets.py @@ -1,2 +1,3 @@ from starlette.websockets import WebSocket as WebSocket # noqa from starlette.websockets import WebSocketDisconnect as WebSocketDisconnect # noqa +from starlette.websockets import WebSocketState as WebSocketState # noqa From 80d68a6eda93dd1e89725aca6d38fa9bb8db4f73 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 15:12:59 +0000 Subject: [PATCH 795/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 34183c140..327175a76 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Export `WebSocketState` in `fastapi.websockets`. PR [#4376](https://github.com/tiangolo/fastapi/pull/4376) by [@matiuszka](https://github.com/matiuszka). * 🐛 Fix FastAPI People GitHub Action: set HTTPX timeout for GraphQL query request. PR [#5222](https://github.com/tiangolo/fastapi/pull/5222) by [@iudeen](https://github.com/iudeen). * ✏ Update Hypercorn link, now pointing to GitHub. PR [#5346](https://github.com/tiangolo/fastapi/pull/5346) by [@baconfield](https://github.com/baconfield). * 🌐 Add Russian translation for `docs/ru/docs/features.md`. PR [#5315](https://github.com/tiangolo/fastapi/pull/5315) by [@Xewus](https://github.com/Xewus). From c70fab38e74039d9564da175f3d42c34f9581de8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 4 Sep 2022 15:16:00 +0000 Subject: [PATCH 796/814] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20Peopl?= =?UTF-8?q?e=20(#5347)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions Co-authored-by: Sebastián Ramírez --- docs/en/data/github_sponsors.yml | 182 +++++++++++++++++-------------- docs/en/data/people.yml | 182 +++++++++++++++---------------- 2 files changed, 189 insertions(+), 175 deletions(-) diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml index 6c1efcbbd..891a990a4 100644 --- a/docs/en/data/github_sponsors.yml +++ b/docs/en/data/github_sponsors.yml @@ -1,25 +1,19 @@ sponsors: -- - login: github - avatarUrl: https://avatars.githubusercontent.com/u/9919?v=4 - url: https://github.com/github +- - login: jina-ai + avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4 + url: https://github.com/jina-ai - - login: Doist avatarUrl: https://avatars.githubusercontent.com/u/2565372?v=4 url: https://github.com/Doist - login: cryptapi avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4 url: https://github.com/cryptapi - - login: BLUE-DEVIL1134 - avatarUrl: https://avatars.githubusercontent.com/u/55914808?u=f283d674fce31be7fb3ed2665b0f20d89958e541&v=4 - url: https://github.com/BLUE-DEVIL1134 - - login: jina-ai - avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4 - url: https://github.com/jina-ai - - login: DropbaseHQ - avatarUrl: https://avatars.githubusercontent.com/u/85367855?v=4 - url: https://github.com/DropbaseHQ - - login: ObliviousAI avatarUrl: https://avatars.githubusercontent.com/u/65656077?v=4 url: https://github.com/ObliviousAI + - login: Lovage-Labs + avatarUrl: https://avatars.githubusercontent.com/u/71685552?v=4 + url: https://github.com/Lovage-Labs - login: chaserowbotham avatarUrl: https://avatars.githubusercontent.com/u/97751084?v=4 url: https://github.com/chaserowbotham @@ -47,9 +41,9 @@ sponsors: - - login: SendCloud avatarUrl: https://avatars.githubusercontent.com/u/7831959?v=4 url: https://github.com/SendCloud - - login: qaas - avatarUrl: https://avatars.githubusercontent.com/u/8503759?u=10a6b4391ad6ab4cf9487ce54e3fcb61322d1efc&v=4 - url: https://github.com/qaas + - login: mercedes-benz + avatarUrl: https://avatars.githubusercontent.com/u/34240465?v=4 + url: https://github.com/mercedes-benz - login: xoflare avatarUrl: https://avatars.githubusercontent.com/u/74335107?v=4 url: https://github.com/xoflare @@ -59,10 +53,10 @@ sponsors: - login: BoostryJP avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4 url: https://github.com/BoostryJP -- - login: nnfuzzy - avatarUrl: https://avatars.githubusercontent.com/u/687670?v=4 - url: https://github.com/nnfuzzy - - login: johnadjei + - login: Jonathanjwp + avatarUrl: https://avatars.githubusercontent.com/u/110426978?u=5e6ed4984022cb8886c4fdfdc0c59f55c48a2f1d&v=4 + url: https://github.com/Jonathanjwp +- - login: johnadjei avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4 url: https://github.com/johnadjei - login: HiredScore @@ -71,6 +65,9 @@ sponsors: - login: wdwinslow avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 url: https://github.com/wdwinslow + - login: khalidelboray + avatarUrl: https://avatars.githubusercontent.com/u/37024839?u=9a4b19123b5a1ba39dc581f8e4e1bc53fafdda2e&v=4 + url: https://github.com/khalidelboray - - login: moellenbeck avatarUrl: https://avatars.githubusercontent.com/u/169372?v=4 url: https://github.com/moellenbeck @@ -80,27 +77,39 @@ sponsors: - login: tizz98 avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4 url: https://github.com/tizz98 + - login: Vikka + avatarUrl: https://avatars.githubusercontent.com/u/9381120?u=4bfc7032a824d1ed1994aa8256dfa597c8f187ad&v=4 + url: https://github.com/Vikka - login: jmaralc avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4 url: https://github.com/jmaralc - - login: marutoraman + - login: takashi-yoneya avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4 - url: https://github.com/marutoraman + url: https://github.com/takashi-yoneya - login: leynier avatarUrl: https://avatars.githubusercontent.com/u/36774373?u=2284831c821307de562ebde5b59014d5416c7e0d&v=4 url: https://github.com/leynier - login: mainframeindustries avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4 url: https://github.com/mainframeindustries - - login: A-Edge - avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4 - url: https://github.com/A-Edge - login: DelfinaCare avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4 url: https://github.com/DelfinaCare - - login: povilasb avatarUrl: https://avatars.githubusercontent.com/u/1213442?u=b11f58ed6ceea6e8297c9b310030478ebdac894d&v=4 url: https://github.com/povilasb + - login: primer-io + avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4 + url: https://github.com/primer-io +- - login: ekpyrosis + avatarUrl: https://avatars.githubusercontent.com/u/60075?v=4 + url: https://github.com/ekpyrosis + - login: ryangrose + avatarUrl: https://avatars.githubusercontent.com/u/24993976?u=052f346aa859f3e52c21bd2c1792f61a98cfbacf&v=4 + url: https://github.com/ryangrose + - login: A-Edge + avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4 + url: https://github.com/A-Edge - - login: Kludex avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex @@ -116,6 +125,9 @@ sponsors: - login: kamalgill avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4 url: https://github.com/kamalgill + - login: dekoza + avatarUrl: https://avatars.githubusercontent.com/u/210980?u=c03c78a8ae1039b500dfe343665536ebc51979b2&v=4 + url: https://github.com/dekoza - login: deserat avatarUrl: https://avatars.githubusercontent.com/u/299332?v=4 url: https://github.com/deserat @@ -164,12 +176,18 @@ sponsors: - login: zsinx6 avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4 url: https://github.com/zsinx6 + - login: aacayaco + avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4 + url: https://github.com/aacayaco - login: anomaly avatarUrl: https://avatars.githubusercontent.com/u/3654837?v=4 url: https://github.com/anomaly - login: peterHoburg avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4 url: https://github.com/peterHoburg + - login: jgreys + avatarUrl: https://avatars.githubusercontent.com/u/4136890?u=b579fd97033269a5e703ab509c7d5478b146cc2d&v=4 + url: https://github.com/jgreys - login: gorhack avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4 url: https://github.com/gorhack @@ -188,9 +206,6 @@ sponsors: - login: ennui93 avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4 url: https://github.com/ennui93 - - login: MacroPower - avatarUrl: https://avatars.githubusercontent.com/u/5648814?u=e13991efd1e03c44c911f919872e750530ded633&v=4 - url: https://github.com/MacroPower - login: Yaleesa avatarUrl: https://avatars.githubusercontent.com/u/6135475?v=4 url: https://github.com/Yaleesa @@ -203,9 +218,6 @@ sponsors: - login: pkucmus avatarUrl: https://avatars.githubusercontent.com/u/6347418?u=98f5918b32e214a168a2f5d59b0b8ebdf57dca0d&v=4 url: https://github.com/pkucmus - - login: ioalloc - avatarUrl: https://avatars.githubusercontent.com/u/6737824?u=6c3a31449f1c92064287171aa9ebe6363a0c9b7b&v=4 - url: https://github.com/ioalloc - login: s3ich4n avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=ba3025d698e1c986655e776ae383a3d60d9d578e&v=4 url: https://github.com/s3ich4n @@ -218,9 +230,6 @@ sponsors: - login: Shackelford-Arden avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4 url: https://github.com/Shackelford-Arden - - login: Vikka - avatarUrl: https://avatars.githubusercontent.com/u/9381120?u=4bfc7032a824d1ed1994aa8256dfa597c8f187ad&v=4 - url: https://github.com/Vikka - login: Ge0f3 avatarUrl: https://avatars.githubusercontent.com/u/11887760?u=ccd80f1ac36dcb8517ef5c4e702e8cc5a80cad2f&v=4 url: https://github.com/Ge0f3 @@ -242,9 +251,6 @@ sponsors: - login: wedwardbeck avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4 url: https://github.com/wedwardbeck - - login: stradivari96 - avatarUrl: https://avatars.githubusercontent.com/u/19752586?u=255f5f06a768f518b20cebd6963e840ac49294fd&v=4 - url: https://github.com/stradivari96 - login: RedCarpetUp avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4 url: https://github.com/RedCarpetUp @@ -266,9 +272,9 @@ sponsors: - login: veprimk avatarUrl: https://avatars.githubusercontent.com/u/29689749?u=f8cb5a15a286e522e5b189bc572d5a1a90217fb2&v=4 url: https://github.com/veprimk - - login: meysam81 - avatarUrl: https://avatars.githubusercontent.com/u/30233243?u=64dc9fc62d039892c6fb44d804251cad5537132b&v=4 - url: https://github.com/meysam81 + - login: BrettskiPy + avatarUrl: https://avatars.githubusercontent.com/u/30988215?u=d8a94a67e140d5ee5427724b292cc52d8827087a&v=4 + url: https://github.com/BrettskiPy - login: mauroalejandrojm avatarUrl: https://avatars.githubusercontent.com/u/31569442?u=cdada990a1527926a36e95f62c30a8b48bbc49a1&v=4 url: https://github.com/mauroalejandrojm @@ -281,18 +287,12 @@ sponsors: - login: ProteinQure avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4 url: https://github.com/ProteinQure - - login: guligon90 - avatarUrl: https://avatars.githubusercontent.com/u/35070513?u=b48c05f669d1ea1d329f90dc70e45f10b569ef55&v=4 - url: https://github.com/guligon90 - login: ybressler avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=41e2c00f1eebe3c402635f0325e41b4e6511462c&v=4 url: https://github.com/ybressler - login: ddilidili avatarUrl: https://avatars.githubusercontent.com/u/42176885?u=c0a849dde06987434653197b5f638d3deb55fc6c&v=4 url: https://github.com/ddilidili - - login: dbanty - avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4 - url: https://github.com/dbanty - login: VictorCalderon avatarUrl: https://avatars.githubusercontent.com/u/44529243?u=cea69884f826a29aff1415493405209e0706d07a&v=4 url: https://github.com/VictorCalderon @@ -302,27 +302,27 @@ sponsors: - login: rafsaf avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4 url: https://github.com/rafsaf + - login: yezz123 + avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 + url: https://github.com/yezz123 - login: dudikbender avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4 url: https://github.com/dudikbender - - login: daisuke8000 - avatarUrl: https://avatars.githubusercontent.com/u/55035595?u=23a3f2f2925ad3efc27c7420041622b7f5fd2b79&v=4 - url: https://github.com/daisuke8000 - login: dazeddd avatarUrl: https://avatars.githubusercontent.com/u/59472056?u=7a1b668449bf8b448db13e4c575576d24d7d658b&v=4 url: https://github.com/dazeddd - login: yakkonaut avatarUrl: https://avatars.githubusercontent.com/u/60633704?u=90a71fd631aa998ba4a96480788f017c9904e07b&v=4 url: https://github.com/yakkonaut - - login: primer-io - avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4 - url: https://github.com/primer-io - - login: around - avatarUrl: https://avatars.githubusercontent.com/u/62425723?v=4 - url: https://github.com/around + - login: patsatsia + avatarUrl: https://avatars.githubusercontent.com/u/61111267?u=419516384f798a35e9d9e2dd81282cc46c151b58&v=4 + url: https://github.com/patsatsia - login: predictionmachine avatarUrl: https://avatars.githubusercontent.com/u/63719559?v=4 url: https://github.com/predictionmachine + - login: minsau + avatarUrl: https://avatars.githubusercontent.com/u/64386242?u=7e45f24b2958caf946fa3546ea33bacf5cd886f8&v=4 + url: https://github.com/minsau - login: daverin avatarUrl: https://avatars.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4 url: https://github.com/daverin @@ -335,11 +335,14 @@ sponsors: - login: pyt3h avatarUrl: https://avatars.githubusercontent.com/u/99658549?v=4 url: https://github.com/pyt3h +- - login: raestrada95 + avatarUrl: https://avatars.githubusercontent.com/u/34411704?u=f32b7e8f57a3f7e2a99e2bc115356f89f094f340&v=4 + url: https://github.com/raestrada95 - - login: linux-china avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4 url: https://github.com/linux-china - login: ddanier - avatarUrl: https://avatars.githubusercontent.com/u/113563?v=4 + avatarUrl: https://avatars.githubusercontent.com/u/113563?u=ed1dc79de72f93bd78581f88ebc6952b62f472da&v=4 url: https://github.com/ddanier - login: jhb avatarUrl: https://avatars.githubusercontent.com/u/142217?v=4 @@ -350,6 +353,9 @@ sponsors: - login: bryanculbertson avatarUrl: https://avatars.githubusercontent.com/u/144028?u=defda4f90e93429221cc667500944abde60ebe4a&v=4 url: https://github.com/bryanculbertson + - login: hhatto + avatarUrl: https://avatars.githubusercontent.com/u/150309?u=3e8f63c27bf996bfc68464b0ce3f7a3e40e6ea7f&v=4 + url: https://github.com/hhatto - login: yourkin avatarUrl: https://avatars.githubusercontent.com/u/178984?u=fa7c3503b47bf16405b96d21554bc59f07a65523&v=4 url: https://github.com/yourkin @@ -369,7 +375,7 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/388564?v=4 url: https://github.com/dmig - login: rinckd - avatarUrl: https://avatars.githubusercontent.com/u/546002?u=1fcc7e664dc86524a0af6837a0c222829c3fd4e5&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/546002?u=8ec88ab721a5636346f19dcd677a6f323058be8b&v=4 url: https://github.com/rinckd - login: securancy avatarUrl: https://avatars.githubusercontent.com/u/606673?v=4 @@ -393,7 +399,7 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=169dba3bfbc04ed214a914640ff435969f19ddb3&v=4 url: https://github.com/Pytlicek - login: allen0125 - avatarUrl: https://avatars.githubusercontent.com/u/1448456?u=d4feb3d06a61baa4a69857ce371cc53fb4dffd2c&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/1448456?u=dc2ad819497eef494b88688a1796e0adb87e7cae&v=4 url: https://github.com/allen0125 - login: WillHogan avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4 @@ -404,6 +410,9 @@ sponsors: - login: rglsk avatarUrl: https://avatars.githubusercontent.com/u/2768101?u=e349c88673f2155fe021331377c656a9d74bcc25&v=4 url: https://github.com/rglsk + - login: Debakel + avatarUrl: https://avatars.githubusercontent.com/u/2857237?u=07df6d11c8feef9306d071cb1c1005a2dd596585&v=4 + url: https://github.com/Debakel - login: paul121 avatarUrl: https://avatars.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4 url: https://github.com/paul121 @@ -413,6 +422,9 @@ sponsors: - login: anthonycorletti avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4 url: https://github.com/anthonycorletti + - login: jonathanhle + avatarUrl: https://avatars.githubusercontent.com/u/3851599?u=76b9c5d2fecd6c3a16e7645231878c4507380d4d&v=4 + url: https://github.com/jonathanhle - login: pawamoy avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4 url: https://github.com/pawamoy @@ -425,9 +437,15 @@ sponsors: - login: unredundant avatarUrl: https://avatars.githubusercontent.com/u/5607577?u=57dd0023365bec03f4fc566df6b81bc0a264a47d&v=4 url: https://github.com/unredundant + - login: Baghdady92 + avatarUrl: https://avatars.githubusercontent.com/u/5708590?v=4 + url: https://github.com/Baghdady92 - login: holec avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4 url: https://github.com/holec + - login: hcristea + avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=61d7a4fcf846983a4606788eac25e1c6c1209ba8&v=4 + url: https://github.com/hcristea - login: moonape1226 avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4 url: https://github.com/moonape1226 @@ -449,12 +467,18 @@ sponsors: - login: satwikkansal avatarUrl: https://avatars.githubusercontent.com/u/10217535?u=b12d6ef74ea297de9e46da6933b1a5b7ba9e6a61&v=4 url: https://github.com/satwikkansal + - login: mntolia + avatarUrl: https://avatars.githubusercontent.com/u/10390224?v=4 + url: https://github.com/mntolia - login: pheanex avatarUrl: https://avatars.githubusercontent.com/u/10408624?u=5b6bab6ee174aa6e991333e06eb29f628741013d&v=4 url: https://github.com/pheanex - login: JimFawkes avatarUrl: https://avatars.githubusercontent.com/u/12075115?u=dc58ecfd064d72887c34bf500ddfd52592509acd&v=4 url: https://github.com/JimFawkes + - login: giuliano-oliveira + avatarUrl: https://avatars.githubusercontent.com/u/13181797?u=0ef2dfbf7fc9a9726d45c21d32b5d1038a174870&v=4 + url: https://github.com/giuliano-oliveira - login: logan-connolly avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4 url: https://github.com/logan-connolly @@ -467,9 +491,6 @@ sponsors: - login: cdsre avatarUrl: https://avatars.githubusercontent.com/u/16945936?v=4 url: https://github.com/cdsre - - login: aprilcoskun - avatarUrl: https://avatars.githubusercontent.com/u/17393603?u=29145243b4c7fadc80c7099471309cc2c04b6bcc&v=4 - url: https://github.com/aprilcoskun - login: jangia avatarUrl: https://avatars.githubusercontent.com/u/17927101?u=9261b9bb0c3e3bb1ecba43e8915dc58d8c9a077e&v=4 url: https://github.com/jangia @@ -485,15 +506,12 @@ sponsors: - login: mertguvencli avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4 url: https://github.com/mertguvencli - - login: elisoncrum - avatarUrl: https://avatars.githubusercontent.com/u/30413278?u=531190845bb0935dbc1e4f017cda3cb7b4dd0e54&v=4 - url: https://github.com/elisoncrum + - login: ruizdiazever + avatarUrl: https://avatars.githubusercontent.com/u/29817086?u=2df54af55663d246e3a4dc8273711c37f1adb117&v=4 + url: https://github.com/ruizdiazever - login: HosamAlmoghraby avatarUrl: https://avatars.githubusercontent.com/u/32025281?u=aa1b09feabccbf9dc506b81c71155f32d126cefa&v=4 url: https://github.com/HosamAlmoghraby - - login: kitaramu0401 - avatarUrl: https://avatars.githubusercontent.com/u/33246506?u=929e6efa2c518033b8097ba524eb5347a069bb3b&v=4 - url: https://github.com/kitaramu0401 - login: engineerjoe440 avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4 url: https://github.com/engineerjoe440 @@ -516,11 +534,11 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4 url: https://github.com/ilias-ant - login: arrrrrmin - avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=fee5739394fea074cb0b66929d070114a5067aae&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=2a812c1a2ec58227ed01778837f255143de9df97&v=4 url: https://github.com/arrrrrmin - - login: BomGard - avatarUrl: https://avatars.githubusercontent.com/u/47395385?u=8e9052f54e0b8dc7285099c438fa29c55a7d6407&v=4 - url: https://github.com/BomGard + - login: MauriceKuenicke + avatarUrl: https://avatars.githubusercontent.com/u/47433175?u=37455bc95c7851db296ac42626f0cacb77ca2443&v=4 + url: https://github.com/MauriceKuenicke - login: akanz1 avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4 url: https://github.com/akanz1 @@ -548,24 +566,24 @@ sponsors: - login: alessio-proietti avatarUrl: https://avatars.githubusercontent.com/u/67370599?u=8ac73db1e18e946a7681f173abdb640516f88515&v=4 url: https://github.com/alessio-proietti - - login: Mr-Sunglasses - avatarUrl: https://avatars.githubusercontent.com/u/81439109?u=a5d0762fdcec26e18a028aef05323de3c6fb195c&v=4 - url: https://github.com/Mr-Sunglasses + - login: pondDevThai + avatarUrl: https://avatars.githubusercontent.com/u/71592181?u=08af9a59bccfd8f6b101de1005aa9822007d0a44&v=4 + url: https://github.com/pondDevThai + - login: CY0xZ + avatarUrl: https://avatars.githubusercontent.com/u/103884082?u=0b3260c6a1af6268492f69264dbb75989afb155f&v=4 + url: https://github.com/CY0xZ - - login: backbord avatarUrl: https://avatars.githubusercontent.com/u/6814946?v=4 url: https://github.com/backbord + - login: mattwelke + avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=5d963ead289969257190b133250653bd99df06ba&v=4 + url: https://github.com/mattwelke - login: gabrielmbmb avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=6d1e00b5d558e96718312ff910a2318f47cc3145&v=4 url: https://github.com/gabrielmbmb - login: danburonline avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4 url: https://github.com/danburonline - - login: zachspar - avatarUrl: https://avatars.githubusercontent.com/u/41600414?u=edf29c197137f51bace3f19a2ba759662640771f&v=4 - url: https://github.com/zachspar - - login: sownt - avatarUrl: https://avatars.githubusercontent.com/u/44340502?u=c06e3c45fb00a403075172770805fe57ff17b1cf&v=4 - url: https://github.com/sownt - - login: aahouzi - avatarUrl: https://avatars.githubusercontent.com/u/75032370?u=82677ee9cd86b3ccf4e13d9cb6765d8de5713e1e&v=4 - url: https://github.com/aahouzi + - login: Moises6669 + avatarUrl: https://avatars.githubusercontent.com/u/66188523?u=81761d977faabab60cba5a06e7d50b44416c0c99&v=4 + url: https://github.com/Moises6669 diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 031c1ca4d..d804ecabb 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,12 +1,12 @@ maintainers: - login: tiangolo - answers: 1248 - prs: 318 + answers: 1265 + prs: 333 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 352 + count: 360 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: dmontagu @@ -29,6 +29,10 @@ experts: count: 130 avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 +- login: JarroVGIT + count: 129 + avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 + url: https://github.com/JarroVGIT - login: raphaelauv count: 77 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 @@ -37,10 +41,6 @@ experts: count: 71 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4 url: https://github.com/ArcLightSlavik -- login: JarroVGIT - count: 68 - avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 - url: https://github.com/JarroVGIT - login: falkben count: 58 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4 @@ -57,14 +57,18 @@ experts: count: 43 avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 url: https://github.com/Dustyposa -- login: adriangb - count: 40 - avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4 - url: https://github.com/adriangb +- login: iudeen + count: 42 + avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 + url: https://github.com/iudeen - login: jgould22 - count: 40 + count: 42 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 url: https://github.com/jgould22 +- login: adriangb + count: 40 + avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=75087f0cf0e9f725f3cd18a899218b6c63ae60d3&v=4 + url: https://github.com/adriangb - login: includeamin count: 39 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 @@ -73,6 +77,10 @@ experts: count: 37 avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 url: https://github.com/STeveShary +- login: chbndrhnns + count: 34 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: prostomarkeloff count: 33 avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4 @@ -85,20 +93,16 @@ experts: count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 url: https://github.com/krishnardt -- login: chbndrhnns - count: 30 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns - login: wshayes count: 29 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes - login: panla - count: 27 + count: 28 avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 url: https://github.com/panla - login: acidjunk - count: 25 + count: 26 avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 url: https://github.com/acidjunk - login: ghandic @@ -125,14 +129,14 @@ experts: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 url: https://github.com/chris-allnutt +- login: odiseo0 + count: 20 + avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4 + url: https://github.com/odiseo0 - login: retnikt count: 19 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 url: https://github.com/retnikt -- login: odiseo0 - count: 19 - avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4 - url: https://github.com/odiseo0 - login: Hultner count: 18 avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 @@ -173,6 +177,10 @@ experts: count: 13 avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4 url: https://github.com/haizaar +- login: yinziyan1206 + count: 13 + avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4 + url: https://github.com/yinziyan1206 - login: valentin994 count: 13 avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4 @@ -181,47 +189,31 @@ experts: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4 url: https://github.com/David-Lor -- login: yinziyan1206 - count: 12 - avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4 - url: https://github.com/yinziyan1206 - login: n8sty count: 12 avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 url: https://github.com/n8sty -- login: lowercase00 - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/21188280?v=4 - url: https://github.com/lowercase00 -- login: zamiramir - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/40475662?u=e58ef61034e8d0d6a312cc956fb09b9c3332b449&v=4 - url: https://github.com/zamiramir -last_month_active: -- login: JarroVGIT - count: 30 - avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 - url: https://github.com/JarroVGIT - login: zoliknemet - count: 9 + count: 12 avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4 url: https://github.com/zoliknemet +last_month_active: +- login: JarroVGIT + count: 27 + avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 + url: https://github.com/JarroVGIT - login: iudeen - count: 5 + count: 17 avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 url: https://github.com/iudeen -- login: Kludex +- login: imacat count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/594968?v=4 + url: https://github.com/imacat +- login: Kludex + count: 3 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex -- login: odiseo0 - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4 - url: https://github.com/odiseo0 -- login: jonatasoli - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4 - url: https://github.com/jonatasoli top_contributors: - login: waynerv count: 25 @@ -236,25 +228,29 @@ top_contributors: avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4 url: https://github.com/dmontagu - login: jaystone776 - count: 15 + count: 16 avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 url: https://github.com/jaystone776 - login: euri10 count: 13 avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4 url: https://github.com/euri10 +- login: Kludex + count: 13 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 + url: https://github.com/Kludex - login: mariacamilagl count: 12 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 url: https://github.com/mariacamilagl -- login: Kludex - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 - url: https://github.com/Kludex - login: Smlep count: 10 avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4 url: https://github.com/Smlep +- login: dependabot + count: 9 + avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4 + url: https://github.com/apps/dependabot - login: Serrones count: 8 avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 @@ -279,10 +275,10 @@ top_contributors: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4 url: https://github.com/Attsun1031 -- login: dependabot +- login: ComicShrimp count: 5 - avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4 - url: https://github.com/apps/dependabot + avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 + url: https://github.com/ComicShrimp - login: jekirl count: 4 avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4 @@ -303,25 +299,29 @@ top_contributors: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/3360631?u=5fa1f475ad784d64eb9666bdd43cc4d285dcc773&v=4 url: https://github.com/hitrust +- login: rjNemo + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4 + url: https://github.com/rjNemo - login: lsglucas count: 4 avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 url: https://github.com/lsglucas -- login: ComicShrimp - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 - url: https://github.com/ComicShrimp - login: NinaHwang count: 4 avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 url: https://github.com/NinaHwang top_reviewers: - login: Kludex - count: 95 + count: 96 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex +- login: BilalAlpaslan + count: 51 + avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 + url: https://github.com/BilalAlpaslan - login: tokusumi - count: 49 + count: 50 avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 url: https://github.com/tokusumi - login: waynerv @@ -332,10 +332,6 @@ top_reviewers: count: 47 avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4 url: https://github.com/Laineyzhang55 -- login: BilalAlpaslan - count: 45 - avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 - url: https://github.com/BilalAlpaslan - login: ycd count: 45 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4 @@ -345,7 +341,7 @@ top_reviewers: avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 url: https://github.com/cikay - login: yezz123 - count: 34 + count: 39 avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4 url: https://github.com/yezz123 - login: AdrianDeAnda @@ -356,6 +352,10 @@ top_reviewers: count: 31 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4 url: https://github.com/ArcLightSlavik +- login: JarroVGIT + count: 27 + avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 + url: https://github.com/JarroVGIT - login: cassiobotaro count: 25 avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4 @@ -369,7 +369,7 @@ top_reviewers: avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4 url: https://github.com/komtaki - login: hard-coders - count: 19 + count: 20 avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4 url: https://github.com/hard-coders - login: 0417taehyun @@ -380,10 +380,6 @@ top_reviewers: count: 18 avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4 url: https://github.com/lsglucas -- login: JarroVGIT - count: 18 - avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 - url: https://github.com/JarroVGIT - login: zy7y count: 17 avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4 @@ -424,6 +420,14 @@ top_reviewers: count: 12 avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=efb5b45b55584450507834f279ce48d4d64dea2f&v=4 url: https://github.com/RunningIkkyu +- login: odiseo0 + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4 + url: https://github.com/odiseo0 +- login: LorhanSohaky + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4 + url: https://github.com/LorhanSohaky - login: solomein-sv count: 11 avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4 @@ -440,10 +444,10 @@ top_reviewers: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4 url: https://github.com/maoyibo -- login: odiseo0 +- login: ComicShrimp count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4 - url: https://github.com/odiseo0 + avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 + url: https://github.com/ComicShrimp - login: graingert count: 9 avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4 @@ -460,6 +464,10 @@ top_reviewers: count: 9 avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4 url: https://github.com/bezaca +- login: izaguerreiro + count: 8 + avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4 + url: https://github.com/izaguerreiro - login: raphaelauv count: 8 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 @@ -472,10 +480,6 @@ top_reviewers: count: 8 avatarUrl: https://avatars.githubusercontent.com/u/5690226?v=4 url: https://github.com/rogerbrinkmann -- login: ComicShrimp - count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4 - url: https://github.com/ComicShrimp - login: NinaHwang count: 8 avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4 @@ -488,6 +492,10 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4 url: https://github.com/Serrones +- login: jovicon + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4 + url: https://github.com/jovicon - login: ryuckel count: 7 avatarUrl: https://avatars.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4 @@ -500,15 +508,3 @@ top_reviewers: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause -- login: wakabame - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/35513518?v=4 - url: https://github.com/wakabame -- login: AlexandreBiguet - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/1483079?u=ff926455cd4cab03c6c49441aa5dc2b21df3e266&v=4 - url: https://github.com/AlexandreBiguet -- login: krocdort - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/34248814?v=4 - url: https://github.com/krocdort From d0cc996dc7000542beb95286834c55bd785a78eb Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 15:17:43 +0000 Subject: [PATCH 797/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 327175a76..9232db7f1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#5347](https://github.com/tiangolo/fastapi/pull/5347) by [@github-actions[bot]](https://github.com/apps/github-actions). * ✨ Export `WebSocketState` in `fastapi.websockets`. PR [#4376](https://github.com/tiangolo/fastapi/pull/4376) by [@matiuszka](https://github.com/matiuszka). * 🐛 Fix FastAPI People GitHub Action: set HTTPX timeout for GraphQL query request. PR [#5222](https://github.com/tiangolo/fastapi/pull/5222) by [@iudeen](https://github.com/iudeen). * ✏ Update Hypercorn link, now pointing to GitHub. PR [#5346](https://github.com/tiangolo/fastapi/pull/5346) by [@baconfield](https://github.com/baconfield). From f8460a8b54fd4975ca64c7fbe8d516740781f0df Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Sun, 4 Sep 2022 14:09:24 -0500 Subject: [PATCH 798/814] =?UTF-8?q?=F0=9F=90=9B=20Allow=20exit=20code=20fo?= =?UTF-8?q?r=20dependencies=20with=20`yield`=20to=20always=20execute,=20by?= =?UTF-8?q?=20removing=20capacity=20limiter=20for=20them,=20to=20e.g.=20al?= =?UTF-8?q?low=20closing=20DB=20connections=20without=20deadlocks=20(#5122?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/concurrency.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/fastapi/concurrency.py b/fastapi/concurrency.py index becac3f33..c728ec1d2 100644 --- a/fastapi/concurrency.py +++ b/fastapi/concurrency.py @@ -1,6 +1,8 @@ import sys from typing import AsyncGenerator, ContextManager, TypeVar +import anyio +from anyio import CapacityLimiter from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa from starlette.concurrency import ( # noqa @@ -22,11 +24,24 @@ _T = TypeVar("_T") async def contextmanager_in_threadpool( cm: ContextManager[_T], ) -> AsyncGenerator[_T, None]: + # blocking __exit__ from running waiting on a free thread + # can create race conditions/deadlocks if the context manager itself + # has it's own internal pool (e.g. a database connection pool) + # to avoid this we let __exit__ run without a capacity limit + # since we're creating a new limiter for each call, any non-zero limit + # works (1 is arbitrary) + exit_limiter = CapacityLimiter(1) try: yield await run_in_threadpool(cm.__enter__) except Exception as e: - ok: bool = await run_in_threadpool(cm.__exit__, type(e), e, None) + ok = bool( + await anyio.to_thread.run_sync( + cm.__exit__, type(e), e, None, limiter=exit_limiter + ) + ) if not ok: raise e else: - await run_in_threadpool(cm.__exit__, None, None, None) + await anyio.to_thread.run_sync( + cm.__exit__, None, None, None, limiter=exit_limiter + ) From f3efaf69da4dd6e00dbc871b418f74d3338b7c3a Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 4 Sep 2022 19:10:05 +0000 Subject: [PATCH 799/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9232db7f1..f44cd4f6e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Allow exit code for dependencies with `yield` to always execute, by removing capacity limiter for them, to e.g. allow closing DB connections without deadlocks. PR [#5122](https://github.com/tiangolo/fastapi/pull/5122) by [@adriangb](https://github.com/adriangb). * 👥 Update FastAPI People. PR [#5347](https://github.com/tiangolo/fastapi/pull/5347) by [@github-actions[bot]](https://github.com/apps/github-actions). * ✨ Export `WebSocketState` in `fastapi.websockets`. PR [#4376](https://github.com/tiangolo/fastapi/pull/4376) by [@matiuszka](https://github.com/matiuszka). * 🐛 Fix FastAPI People GitHub Action: set HTTPX timeout for GraphQL query request. PR [#5222](https://github.com/tiangolo/fastapi/pull/5222) by [@iudeen](https://github.com/iudeen). From ddf6daeb0759c6e0cb2cfc6af075ba95dd271779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 4 Sep 2022 21:25:29 +0200 Subject: [PATCH 800/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 56 ++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f44cd4f6e..4b241cdd6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,30 +2,50 @@ ## Latest Changes -* 🐛 Allow exit code for dependencies with `yield` to always execute, by removing capacity limiter for them, to e.g. allow closing DB connections without deadlocks. PR [#5122](https://github.com/tiangolo/fastapi/pull/5122) by [@adriangb](https://github.com/adriangb). -* 👥 Update FastAPI People. PR [#5347](https://github.com/tiangolo/fastapi/pull/5347) by [@github-actions[bot]](https://github.com/apps/github-actions). +🚨 This is probably the last release (or one of the last releases) to support Python 3.6. 🔥 + +Python 3.6 reached the [end-of-life and is no longer supported by Python](https://www.python.org/downloads/release/python-3615/) since around a year ago. + +You hopefully updated to a supported version of Python a while ago. If you haven't, you really should. + +### Features + * ✨ Export `WebSocketState` in `fastapi.websockets`. PR [#4376](https://github.com/tiangolo/fastapi/pull/4376) by [@matiuszka](https://github.com/matiuszka). -* 🐛 Fix FastAPI People GitHub Action: set HTTPX timeout for GraphQL query request. PR [#5222](https://github.com/tiangolo/fastapi/pull/5222) by [@iudeen](https://github.com/iudeen). -* ✏ Update Hypercorn link, now pointing to GitHub. PR [#5346](https://github.com/tiangolo/fastapi/pull/5346) by [@baconfield](https://github.com/baconfield). -* 🌐 Add Russian translation for `docs/ru/docs/features.md`. PR [#5315](https://github.com/tiangolo/fastapi/pull/5315) by [@Xewus](https://github.com/Xewus). -* ⬆ Bump dawidd6/action-download-artifact from 2.22.0 to 2.23.0. PR [#5321](https://github.com/tiangolo/fastapi/pull/5321) by [@dependabot[bot]](https://github.com/apps/dependabot). -* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5318](https://github.com/tiangolo/fastapi/pull/5318) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). -* 🌐 Update Chinese translation for `docs/zh/docs/tutorial/request-files.md`. PR [#4529](https://github.com/tiangolo/fastapi/pull/4529) by [@ASpathfinder](https://github.com/ASpathfinder). -* 🌐 Add Chinese translation for `docs/zh/docs/tutorial/encoder.md`. PR [#4969](https://github.com/tiangolo/fastapi/pull/4969) by [@Zssaer](https://github.com/Zssaer). -* ✏ Tweak wording in `docs/en/docs/advanced/dataclasses.md`. PR [#3698](https://github.com/tiangolo/fastapi/pull/3698) by [@pfackeldey](https://github.com/pfackeldey). -* 📝 Add note about Python 3.10 `X | Y` operator in explanation about Response Models. PR [#5307](https://github.com/tiangolo/fastapi/pull/5307) by [@MendyLanda](https://github.com/MendyLanda). -* 🌐 Fix MkDocs file line for Portuguese translation of `background-task.md`. PR [#5242](https://github.com/tiangolo/fastapi/pull/5242) by [@ComicShrimp](https://github.com/ComicShrimp). -* ✏ Fix a small code highlight line error. PR [#5256](https://github.com/tiangolo/fastapi/pull/5256) by [@hjlarry](https://github.com/hjlarry). -* 📝 Add link to New Relic article: "How to monitor FastAPI application performance using Python agent". PR [#5260](https://github.com/tiangolo/fastapi/pull/5260) by [@sjyothi54](https://github.com/sjyothi54). -* 🐛 Make sure a parameter defined as required is kept required in OpenAPI even if defined as optional in another dependency. PR [#4319](https://github.com/tiangolo/fastapi/pull/4319) by [@cd17822](https://github.com/cd17822). -* ♻ Internal small refactor, move `operation_id` parameter position in delete method for consistency with the code. PR [#4474](https://github.com/tiangolo/fastapi/pull/4474) by [@hiel](https://github.com/hiel). * ✨ Support Python internal description on Pydantic model's docstring. PR [#3032](https://github.com/tiangolo/fastapi/pull/3032) by [@Kludex](https://github.com/Kludex). * ✨ Update `ORJSONResponse` to support non `str` keys and serializing Numpy arrays. PR [#3892](https://github.com/tiangolo/fastapi/pull/3892) by [@baby5](https://github.com/baby5). -* 🔧 Update sponsors, disable ImgWhale. PR [#5338](https://github.com/tiangolo/fastapi/pull/5338) by [@tiangolo](https://github.com/tiangolo). + +### Fixes + +* 🐛 Allow exit code for dependencies with `yield` to always execute, by removing capacity limiter for them, to e.g. allow closing DB connections without deadlocks. PR [#5122](https://github.com/tiangolo/fastapi/pull/5122) by [@adriangb](https://github.com/adriangb). +* 🐛 Fix FastAPI People GitHub Action: set HTTPX timeout for GraphQL query request. PR [#5222](https://github.com/tiangolo/fastapi/pull/5222) by [@iudeen](https://github.com/iudeen). +* 🐛 Make sure a parameter defined as required is kept required in OpenAPI even if defined as optional in another dependency. PR [#4319](https://github.com/tiangolo/fastapi/pull/4319) by [@cd17822](https://github.com/cd17822). +* 🐛 Fix support for path parameters in WebSockets. PR [#3879](https://github.com/tiangolo/fastapi/pull/3879) by [@davidbrochart](https://github.com/davidbrochart). + +### Docs + +* ✏ Update Hypercorn link, now pointing to GitHub. PR [#5346](https://github.com/tiangolo/fastapi/pull/5346) by [@baconfield](https://github.com/baconfield). +* ✏ Tweak wording in `docs/en/docs/advanced/dataclasses.md`. PR [#3698](https://github.com/tiangolo/fastapi/pull/3698) by [@pfackeldey](https://github.com/pfackeldey). +* 📝 Add note about Python 3.10 `X | Y` operator in explanation about Response Models. PR [#5307](https://github.com/tiangolo/fastapi/pull/5307) by [@MendyLanda](https://github.com/MendyLanda). +* 📝 Add link to New Relic article: "How to monitor FastAPI application performance using Python agent". PR [#5260](https://github.com/tiangolo/fastapi/pull/5260) by [@sjyothi54](https://github.com/sjyothi54). * 📝 Update docs for `ORJSONResponse` with details about improving performance. PR [#2615](https://github.com/tiangolo/fastapi/pull/2615) by [@falkben](https://github.com/falkben). * 📝 Add docs for creating a custom Response class. PR [#5331](https://github.com/tiangolo/fastapi/pull/5331) by [@tiangolo](https://github.com/tiangolo). * 📝 Add tip about using alias for form data fields. PR [#5329](https://github.com/tiangolo/fastapi/pull/5329) by [@tiangolo](https://github.com/tiangolo). -* 🐛 Fix support for path parameters in WebSockets. PR [#3879](https://github.com/tiangolo/fastapi/pull/3879) by [@davidbrochart](https://github.com/davidbrochart). + +### Translations + +* 🌐 Add Russian translation for `docs/ru/docs/features.md`. PR [#5315](https://github.com/tiangolo/fastapi/pull/5315) by [@Xewus](https://github.com/Xewus). +* 🌐 Update Chinese translation for `docs/zh/docs/tutorial/request-files.md`. PR [#4529](https://github.com/tiangolo/fastapi/pull/4529) by [@ASpathfinder](https://github.com/ASpathfinder). +* 🌐 Add Chinese translation for `docs/zh/docs/tutorial/encoder.md`. PR [#4969](https://github.com/tiangolo/fastapi/pull/4969) by [@Zssaer](https://github.com/Zssaer). +* 🌐 Fix MkDocs file line for Portuguese translation of `background-task.md`. PR [#5242](https://github.com/tiangolo/fastapi/pull/5242) by [@ComicShrimp](https://github.com/ComicShrimp). + +### Internal + +* 👥 Update FastAPI People. PR [#5347](https://github.com/tiangolo/fastapi/pull/5347) by [@github-actions[bot]](https://github.com/apps/github-actions). +* ⬆ Bump dawidd6/action-download-artifact from 2.22.0 to 2.23.0. PR [#5321](https://github.com/tiangolo/fastapi/pull/5321) by [@dependabot[bot]](https://github.com/apps/dependabot). +* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5318](https://github.com/tiangolo/fastapi/pull/5318) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). +* ✏ Fix a small code highlight line error. PR [#5256](https://github.com/tiangolo/fastapi/pull/5256) by [@hjlarry](https://github.com/hjlarry). +* ♻ Internal small refactor, move `operation_id` parameter position in delete method for consistency with the code. PR [#4474](https://github.com/tiangolo/fastapi/pull/4474) by [@hiel](https://github.com/hiel). +* 🔧 Update sponsors, disable ImgWhale. PR [#5338](https://github.com/tiangolo/fastapi/pull/5338) by [@tiangolo](https://github.com/tiangolo). ## 0.81.0 From 3079ba925ec04ce2a630d3d919a1308b48a45df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 4 Sep 2022 21:26:31 +0200 Subject: [PATCH 801/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.82?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4b241cdd6..303e6b8e1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.82.0 + 🚨 This is probably the last release (or one of the last releases) to support Python 3.6. 🔥 Python 3.6 reached the [end-of-life and is no longer supported by Python](https://www.python.org/downloads/release/python-3615/) since around a year ago. diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 3688ec89f..c50543bf9 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.81.0" +__version__ = "0.82.0" from starlette import status as status From ef5d6181b62214eee73ccdaf8617e8e3ea39a6ea Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 8 Sep 2022 16:08:33 +0200 Subject: [PATCH 802/814] =?UTF-8?q?=E2=AC=86=20[pre-commit.ci]=20pre-commi?= =?UTF-8?q?t=20autoupdate=20(#5352)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 237feb083..c4c1d4d9e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: - --py3-plus - --keep-runtime-typing - repo: https://github.com/myint/autoflake - rev: v1.5.1 + rev: v1.5.3 hooks: - id: autoflake args: @@ -43,7 +43,7 @@ repos: name: isort (pyi) types: [pyi] - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 22.8.0 hooks: - id: black ci: From 895789bed0280865b8aa85973dc35d89f33730b5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 8 Sep 2022 14:09:15 +0000 Subject: [PATCH 803/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 303e6b8e1..ba5d7b26f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5352](https://github.com/tiangolo/fastapi/pull/5352) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). ## 0.82.0 From 3ec498af63ddc994a7c70f1a05407ea5f7095be4 Mon Sep 17 00:00:00 2001 From: DCsunset Date: Thu, 8 Sep 2022 10:29:23 -0400 Subject: [PATCH 804/814] =?UTF-8?q?=E2=9C=A8=20Add=20support=20in=20`jsona?= =?UTF-8?q?ble=5Fencoder`=20for=20include=20and=20exclude=20with=20datacla?= =?UTF-8?q?sses=20(#4923)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/encoders.py | 6 +++++- tests/test_jsonable_encoder.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/fastapi/encoders.py b/fastapi/encoders.py index f64e4b86e..93045ca27 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -74,8 +74,12 @@ def jsonable_encoder( obj_dict = dataclasses.asdict(obj) return jsonable_encoder( obj_dict, - exclude_none=exclude_none, + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, + exclude_none=exclude_none, custom_encoder=custom_encoder, sqlalchemy_safe=sqlalchemy_safe, ) diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py index 5e55f2f91..f4fdcf601 100644 --- a/tests/test_jsonable_encoder.py +++ b/tests/test_jsonable_encoder.py @@ -1,3 +1,4 @@ +from dataclasses import dataclass from datetime import datetime, timezone from enum import Enum from pathlib import PurePath, PurePosixPath, PureWindowsPath @@ -19,6 +20,12 @@ class Pet: self.name = name +@dataclass +class Item: + name: str + count: int + + class DictablePerson(Person): def __iter__(self): return ((k, v) for k, v in self.__dict__.items()) @@ -131,6 +138,15 @@ def test_encode_dictable(): } +def test_encode_dataclass(): + item = Item(name="foo", count=100) + assert jsonable_encoder(item) == {"name": "foo", "count": 100} + assert jsonable_encoder(item, include={"name"}) == {"name": "foo"} + assert jsonable_encoder(item, exclude={"count"}) == {"name": "foo"} + assert jsonable_encoder(item, include={}) == {} + assert jsonable_encoder(item, exclude={}) == {"name": "foo", "count": 100} + + def test_encode_unsupported(): unserializable = Unserializable() with pytest.raises(ValueError): From c4007cb9ecacd54df95e29780976937af01ff5ae Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 8 Sep 2022 14:30:00 +0000 Subject: [PATCH 805/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ba5d7b26f..bc58b578d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support in `jsonable_encoder` for include and exclude with dataclasses. PR [#4923](https://github.com/tiangolo/fastapi/pull/4923) by [@DCsunset](https://github.com/DCsunset). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5352](https://github.com/tiangolo/fastapi/pull/5352) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). ## 0.82.0 From 0b4fe10c8fed59de02100612a6168a9aefaf3659 Mon Sep 17 00:00:00 2001 From: Thomas Meckel <14177833+tmeckel@users.noreply.github.com> Date: Thu, 8 Sep 2022 17:02:59 +0200 Subject: [PATCH 806/814] =?UTF-8?q?=F0=9F=90=9B=20Fix=20empty=20reponse=20?= =?UTF-8?q?body=20when=20default=20`status=5Fcode`=20is=20empty=20but=20th?= =?UTF-8?q?e=20a=20`Response`=20parameter=20with=20`response.status=5Fcode?= =?UTF-8?q?`=20is=20set=20(#5360)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Thomas Meckel Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- fastapi/routing.py | 2 +- tests/test_reponse_set_reponse_code_empty.py | 97 ++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 tests/test_reponse_set_reponse_code_empty.py diff --git a/fastapi/routing.py b/fastapi/routing.py index 233f79fcb..710cb9734 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -258,7 +258,7 @@ def get_request_handler( is_coroutine=is_coroutine, ) response = actual_response_class(content, **response_args) - if not is_body_allowed_for_status_code(status_code): + if not is_body_allowed_for_status_code(response.status_code): response.body = b"" response.headers.raw.extend(sub_response.headers.raw) return response diff --git a/tests/test_reponse_set_reponse_code_empty.py b/tests/test_reponse_set_reponse_code_empty.py new file mode 100644 index 000000000..094d54a84 --- /dev/null +++ b/tests/test_reponse_set_reponse_code_empty.py @@ -0,0 +1,97 @@ +from typing import Any + +from fastapi import FastAPI, Response +from fastapi.testclient import TestClient + +app = FastAPI() + + +@app.delete( + "/{id}", + status_code=204, +) +async def delete_deployment( + id: int, + response: Response, +) -> Any: + response.status_code = 400 + return {"msg": "Status overwritten", "id": id} + + +client = TestClient(app) + + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/{id}": { + "delete": { + "summary": "Delete Deployment", + "operationId": "delete_deployment__id__delete", + "parameters": [ + { + "required": True, + "schema": {"title": "Id", "type": "integer"}, + "name": "id", + "in": "path", + } + ], + "responses": { + "204": {"description": "Successful Response"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "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"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_dependency_set_status_code(): + response = client.delete("/1") + assert response.status_code == 400 and response.content + assert response.json() == {"msg": "Status overwritten", "id": 1} From 6620273083275f7fec446bb3456d3df6582c6813 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 8 Sep 2022 15:03:37 +0000 Subject: [PATCH 807/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bc58b578d..7d0a16c95 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix empty reponse body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel). * ✨ Add support in `jsonable_encoder` for include and exclude with dataclasses. PR [#4923](https://github.com/tiangolo/fastapi/pull/4923) by [@DCsunset](https://github.com/DCsunset). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5352](https://github.com/tiangolo/fastapi/pull/5352) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). From 4d270463af2279d9723d99da45f0b31631424030 Mon Sep 17 00:00:00 2001 From: Irfanuddin Shafi Ahmed Date: Sun, 11 Sep 2022 21:43:36 +0530 Subject: [PATCH 808/814] =?UTF-8?q?=F0=9F=90=9BFix=20`RuntimeError`=20rais?= =?UTF-8?q?ed=20when=20`HTTPException`=20has=20a=20status=20code=20with=20?= =?UTF-8?q?no=20content=20(#5365)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marcelo Trylesinski Co-authored-by: Sebastián Ramírez --- fastapi/exception_handlers.py | 16 +++++------ tests/test_starlette_exception.py | 46 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/fastapi/exception_handlers.py b/fastapi/exception_handlers.py index 2b286d71c..4d7ea5ec2 100644 --- a/fastapi/exception_handlers.py +++ b/fastapi/exception_handlers.py @@ -1,19 +1,19 @@ from fastapi.encoders import jsonable_encoder from fastapi.exceptions import RequestValidationError +from fastapi.utils import is_body_allowed_for_status_code from starlette.exceptions import HTTPException from starlette.requests import Request -from starlette.responses import JSONResponse +from starlette.responses import JSONResponse, Response from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY -async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse: +async def http_exception_handler(request: Request, exc: HTTPException) -> Response: headers = getattr(exc, "headers", None) - if headers: - return JSONResponse( - {"detail": exc.detail}, status_code=exc.status_code, headers=headers - ) - else: - return JSONResponse({"detail": exc.detail}, status_code=exc.status_code) + if not is_body_allowed_for_status_code(exc.status_code): + return Response(status_code=exc.status_code, headers=headers) + return JSONResponse( + {"detail": exc.detail}, status_code=exc.status_code, headers=headers + ) async def request_validation_exception_handler( diff --git a/tests/test_starlette_exception.py b/tests/test_starlette_exception.py index 859169d3c..2b6712f7b 100644 --- a/tests/test_starlette_exception.py +++ b/tests/test_starlette_exception.py @@ -18,6 +18,16 @@ async def read_item(item_id: str): return {"item": items[item_id]} +@app.get("/http-no-body-statuscode-exception") +async def no_body_status_code_exception(): + raise HTTPException(status_code=204) + + +@app.get("/http-no-body-statuscode-with-detail-exception") +async def no_body_status_code_with_detail_exception(): + raise HTTPException(status_code=204, detail="I should just disappear!") + + @app.get("/starlette-items/{item_id}") async def read_starlette_item(item_id: str): if item_id not in items: @@ -31,6 +41,30 @@ openapi_schema = { "openapi": "3.0.2", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { + "/http-no-body-statuscode-exception": { + "get": { + "operationId": "no_body_status_code_exception_http_no_body_statuscode_exception_get", + "responses": { + "200": { + "content": {"application/json": {"schema": {}}}, + "description": "Successful " "Response", + } + }, + "summary": "No Body " "Status " "Code " "Exception", + } + }, + "/http-no-body-statuscode-with-detail-exception": { + "get": { + "operationId": "no_body_status_code_with_detail_exception_http_no_body_statuscode_with_detail_exception_get", + "responses": { + "200": { + "content": {"application/json": {"schema": {}}}, + "description": "Successful " "Response", + } + }, + "summary": "No Body Status Code With Detail Exception", + } + }, "/items/{item_id}": { "get": { "responses": { @@ -154,3 +188,15 @@ def test_get_starlette_item_not_found(): assert response.status_code == 404, response.text assert response.headers.get("x-error") is None assert response.json() == {"detail": "Item not found"} + + +def test_no_body_status_code_exception_handlers(): + response = client.get("/http-no-body-statuscode-exception") + assert response.status_code == 204 + assert not response.content + + +def test_no_body_status_code_with_detail_exception_handlers(): + response = client.get("/http-no-body-statuscode-with-detail-exception") + assert response.status_code == 204 + assert not response.content From 275306c369d7186aebf6e6d7d56be11e6d01c43c Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Sep 2022 16:14:21 +0000 Subject: [PATCH 809/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7d0a16c95..92e1dfe77 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛Fix `RuntimeError` raised when `HTTPException` has a status code with no content. PR [#5365](https://github.com/tiangolo/fastapi/pull/5365) by [@iudeen](https://github.com/iudeen). * 🐛 Fix empty reponse body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel). * ✨ Add support in `jsonable_encoder` for include and exclude with dataclasses. PR [#4923](https://github.com/tiangolo/fastapi/pull/4923) by [@DCsunset](https://github.com/DCsunset). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5352](https://github.com/tiangolo/fastapi/pull/5352) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). From 4fec12b354c7d87101aac60d0143236afcd8678f Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sun, 11 Sep 2022 18:15:49 +0200 Subject: [PATCH 810/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20`SECURITY.md`?= =?UTF-8?q?=20(#5377)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 322f95f62..db412cf2c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,7 +6,7 @@ Learn more about it below. 👇 ## Versions -The latest versions of FastAPI are supported. +The latest version of FastAPI is supported. You are encouraged to [write tests](https://fastapi.tiangolo.com/tutorial/testing/) for your application and update your FastAPI version frequently after ensuring that your tests are passing. This way you will benefit from the latest features, bug fixes, and **security fixes**. From 306326a2138eff3835901fa34190e4475aed1409 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Sep 2022 16:16:31 +0000 Subject: [PATCH 811/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 92e1dfe77..9c86e4615 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update `SECURITY.md`. PR [#5377](https://github.com/tiangolo/fastapi/pull/5377) by [@Kludex](https://github.com/Kludex). * 🐛Fix `RuntimeError` raised when `HTTPException` has a status code with no content. PR [#5365](https://github.com/tiangolo/fastapi/pull/5365) by [@iudeen](https://github.com/iudeen). * 🐛 Fix empty reponse body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel). * ✨ Add support in `jsonable_encoder` for include and exclude with dataclasses. PR [#4923](https://github.com/tiangolo/fastapi/pull/4923) by [@DCsunset](https://github.com/DCsunset). From 22a155efc1ba51b215ed0aedcc0054854e85122e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 11 Sep 2022 18:24:46 +0200 Subject: [PATCH 812/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9c86e4615..bea543c43 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,10 +2,21 @@ ## Latest Changes -* 📝 Update `SECURITY.md`. PR [#5377](https://github.com/tiangolo/fastapi/pull/5377) by [@Kludex](https://github.com/Kludex). -* 🐛Fix `RuntimeError` raised when `HTTPException` has a status code with no content. PR [#5365](https://github.com/tiangolo/fastapi/pull/5365) by [@iudeen](https://github.com/iudeen). -* 🐛 Fix empty reponse body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel). +### Features + * ✨ Add support in `jsonable_encoder` for include and exclude with dataclasses. PR [#4923](https://github.com/tiangolo/fastapi/pull/4923) by [@DCsunset](https://github.com/DCsunset). + +### Fixes + +* 🐛 Fix `RuntimeError` raised when `HTTPException` has a status code with no content. PR [#5365](https://github.com/tiangolo/fastapi/pull/5365) by [@iudeen](https://github.com/iudeen). +* 🐛 Fix empty reponse body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel). + +### Docs + +* 📝 Update `SECURITY.md`. PR [#5377](https://github.com/tiangolo/fastapi/pull/5377) by [@Kludex](https://github.com/Kludex). + +### Internal + * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5352](https://github.com/tiangolo/fastapi/pull/5352) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). ## 0.82.0 From ed0fcba7cbea46b0cca74e9fce568f9c7316d8e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 11 Sep 2022 18:25:29 +0200 Subject: [PATCH 813/814] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.83?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bea543c43..63595da41 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.83.0 + ### Features * ✨ Add support in `jsonable_encoder` for include and exclude with dataclasses. PR [#4923](https://github.com/tiangolo/fastapi/pull/4923) by [@DCsunset](https://github.com/DCsunset). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index c50543bf9..a9b44fc4a 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.82.0" +__version__ = "0.83.0" from starlette import status as status From b2aa3593be300b57973987fb2489ed01ed9c9f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 11 Sep 2022 18:26:30 +0200 Subject: [PATCH 814/814] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 63595da41..120b374e2 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -5,6 +5,12 @@ ## 0.83.0 +🚨 This is probably the last release (or one of the last releases) to support Python 3.6. 🔥 + +Python 3.6 reached the [end-of-life and is no longer supported by Python](https://www.python.org/downloads/release/python-3615/) since around a year ago. + +You hopefully updated to a supported version of Python a while ago. If you haven't, you really should. + ### Features * ✨ Add support in `jsonable_encoder` for include and exclude with dataclasses. PR [#4923](https://github.com/tiangolo/fastapi/pull/4923) by [@DCsunset](https://github.com/DCsunset).

F$&nSGjm+)B(l^i#fk@M42$y;{?fP5NJM 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Ⓢ<%VQ556rL)Q= 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