From 503cec56494585201a43c644d48f7e659cd3d413 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 Jun 2023 16:03:40 +0000 Subject: [PATCH 01/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8f7ecd07e..9012b491e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👷 Add custom token to Smokeshow and Preview Docs for download-artifact, to prevent API rate limits. PR [#9646](https://github.com/tiangolo/fastapi/pull/9646) by [@tiangolo](https://github.com/tiangolo). * 👷 Add custom tokens for GitHub Actions to avoid rate limits. PR [#9647](https://github.com/tiangolo/fastapi/pull/9647) by [@tiangolo](https://github.com/tiangolo). * ♻ Instantiate `HTTPException` only when needed, optimization refactor. PR [#5356](https://github.com/tiangolo/fastapi/pull/5356) by [@pawamoy](https://github.com/pawamoy). * 📌 Update minimum version of Pydantic to >=1.7.4. PR [#9567](https://github.com/tiangolo/fastapi/pull/9567) by [@Kludex](https://github.com/Kludex). From 52fd0afc945e503a56725e79f5d44fb9a7c75f09 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sat, 10 Jun 2023 19:04:29 +0200 Subject: [PATCH 02/38] =?UTF-8?q?=E2=99=BB=20Remove=20`media=5Ftype`=20fro?= =?UTF-8?q?m=20`ORJSONResponse`=20as=20it's=20inherited=20from=20the=20par?= =?UTF-8?q?ent=20class=20(#5805)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/responses.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/fastapi/responses.py b/fastapi/responses.py index 88dba96e8..c0a13b755 100644 --- a/fastapi/responses.py +++ b/fastapi/responses.py @@ -27,8 +27,6 @@ class UJSONResponse(JSONResponse): class ORJSONResponse(JSONResponse): - media_type = "application/json" - def render(self, content: Any) -> bytes: assert orjson is not None, "orjson must be installed to use ORJSONResponse" return orjson.dumps( From e645a2db1b78da1918d6013eab1f8bf969178dc0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 Jun 2023 17:05:03 +0000 Subject: [PATCH 03/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9012b491e..410039fd1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻ Remove `media_type` from `ORJSONResponse` as it's inherited from the parent class. PR [#5805](https://github.com/tiangolo/fastapi/pull/5805) by [@Kludex](https://github.com/Kludex). * 👷 Add custom token to Smokeshow and Preview Docs for download-artifact, to prevent API rate limits. PR [#9646](https://github.com/tiangolo/fastapi/pull/9646) by [@tiangolo](https://github.com/tiangolo). * 👷 Add custom tokens for GitHub Actions to avoid rate limits. PR [#9647](https://github.com/tiangolo/fastapi/pull/9647) by [@tiangolo](https://github.com/tiangolo). * ♻ Instantiate `HTTPException` only when needed, optimization refactor. PR [#5356](https://github.com/tiangolo/fastapi/pull/5356) by [@pawamoy](https://github.com/pawamoy). From 19757d1859914652a9d245891bb3e29c675e1c7b Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sat, 10 Jun 2023 19:05:42 +0200 Subject: [PATCH 04/38] =?UTF-8?q?=F0=9F=94=A5=20Remove=20link=20to=20Pydan?= =?UTF-8?q?tic's=20benchmark,=20as=20it=20was=20removed=20there=20(#5811)?= 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/features.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/en/docs/features.md b/docs/en/docs/features.md index 387ff86c9..98f37b534 100644 --- a/docs/en/docs/features.md +++ b/docs/en/docs/features.md @@ -189,8 +189,6 @@ With **FastAPI** you get all of **Pydantic**'s features (as FastAPI is based on * If you know Python types you know how to use Pydantic. * 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. * 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. From ae5c51afa67258b9b801ccae2b26919f4331d98f Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 Jun 2023 17:06:14 +0000 Subject: [PATCH 05/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 410039fd1..f456c2930 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔥 Remove link to Pydantic's benchmark, as it was removed there. PR [#5811](https://github.com/tiangolo/fastapi/pull/5811) by [@Kludex](https://github.com/Kludex). * ♻ Remove `media_type` from `ORJSONResponse` as it's inherited from the parent class. PR [#5805](https://github.com/tiangolo/fastapi/pull/5805) by [@Kludex](https://github.com/Kludex). * 👷 Add custom token to Smokeshow and Preview Docs for download-artifact, to prevent API rate limits. PR [#9646](https://github.com/tiangolo/fastapi/pull/9646) by [@tiangolo](https://github.com/tiangolo). * 👷 Add custom tokens for GitHub Actions to avoid rate limits. PR [#9647](https://github.com/tiangolo/fastapi/pull/9647) by [@tiangolo](https://github.com/tiangolo). From 6dd8e567cc2de5993bdb69f57d1cbc2554e6b09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 10 Jun 2023 19:23:12 +0200 Subject: [PATCH 06/38] =?UTF-8?q?=F0=9F=90=9B=20Fix=20`HTTPException`=20he?= =?UTF-8?q?ader=20type=20annotations=20(#9648)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py index ca097b1ce..cac5330a2 100644 --- a/fastapi/exceptions.py +++ b/fastapi/exceptions.py @@ -11,7 +11,7 @@ class HTTPException(StarletteHTTPException): self, status_code: int, detail: Any = None, - headers: Optional[Dict[str, Any]] = None, + headers: Optional[Dict[str, str]] = None, ) -> None: super().__init__(status_code=status_code, detail=detail, headers=headers) From ca8ddb28937a7f252e2f3fd9d63e63d8ac6dbcf2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 Jun 2023 17:23:47 +0000 Subject: [PATCH 07/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f456c2930..ffa68e2c3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix `HTTPException` header type annotations. PR [#9648](https://github.com/tiangolo/fastapi/pull/9648) by [@tiangolo](https://github.com/tiangolo). * 🔥 Remove link to Pydantic's benchmark, as it was removed there. PR [#5811](https://github.com/tiangolo/fastapi/pull/5811) by [@Kludex](https://github.com/Kludex). * ♻ Remove `media_type` from `ORJSONResponse` as it's inherited from the parent class. PR [#5805](https://github.com/tiangolo/fastapi/pull/5805) by [@Kludex](https://github.com/Kludex). * 👷 Add custom token to Smokeshow and Preview Docs for download-artifact, to prevent API rate limits. PR [#9646](https://github.com/tiangolo/fastapi/pull/9646) by [@tiangolo](https://github.com/tiangolo). From 510fa5b7fe56320a4ee8b836996c5ea3e8e64fe4 Mon Sep 17 00:00:00 2001 From: Alexandr Date: Sat, 10 Jun 2023 23:29:08 +0300 Subject: [PATCH 08/38] =?UTF-8?q?=F0=9F=8C=90=20Add=20Russian=20translatio?= =?UTF-8?q?n=20for=20`docs/ru/docs/tutorial/schema-extra-example.md`=20(#9?= =?UTF-8?q?621)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ivan-abc <36765187+ivan-abc@users.noreply.github.com> --- docs/ru/docs/tutorial/schema-extra-example.md | 189 ++++++++++++++++++ docs/ru/mkdocs.yml | 1 + 2 files changed, 190 insertions(+) create mode 100644 docs/ru/docs/tutorial/schema-extra-example.md diff --git a/docs/ru/docs/tutorial/schema-extra-example.md b/docs/ru/docs/tutorial/schema-extra-example.md new file mode 100644 index 000000000..a0363b9ba --- /dev/null +++ b/docs/ru/docs/tutorial/schema-extra-example.md @@ -0,0 +1,189 @@ +# Объявление примера запроса данных + +Вы можете объявлять примеры данных, которые ваше приложение может получать. + +Вот несколько способов, как это можно сделать. + +## Pydantic `schema_extra` + +Вы можете объявить ключ `example` для модели Pydantic, используя класс `Config` и переменную `schema_extra`, как описано в Pydantic документации: Настройка схемы: + +=== "Python 3.10+" + + ```Python hl_lines="13-21" + {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="15-23" + {!> ../../../docs_src/schema_extra_example/tutorial001.py!} + ``` + +Эта дополнительная информация будет включена в **JSON Schema** выходных данных для этой модели, и она будет использоваться в документации к API. + +!!! tip Подсказка + Вы можете использовать тот же метод для расширения JSON-схемы и добавления своей собственной дополнительной информации. + + Например, вы можете использовать это для добавления дополнительной информации для пользовательского интерфейса в вашем веб-приложении и т.д. + +## Дополнительные аргументы поля `Field` + +При использовании `Field()` с моделями Pydantic, вы также можете объявлять дополнительную информацию для **JSON Schema**, передавая любые другие произвольные аргументы в функцию. + +Вы можете использовать это, чтобы добавить аргумент `example` для каждого поля: + +=== "Python 3.10+" + + ```Python hl_lines="2 8-11" + {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="4 10-13" + {!> ../../../docs_src/schema_extra_example/tutorial002.py!} + ``` + +!!! warning Внимание + Имейте в виду, что эти дополнительные переданные аргументы не добавляют никакой валидации, только дополнительную информацию для документации. + +## Использование `example` и `examples` в OpenAPI + +При использовании любой из этих функций: + +* `Path()` +* `Query()` +* `Header()` +* `Cookie()` +* `Body()` +* `Form()` +* `File()` + +вы также можете добавить аргумент, содержащий `example` или группу `examples` с дополнительной информацией, которая будет добавлена в **OpenAPI**. + +### Параметр `Body` с аргументом `example` + +Здесь мы передаём аргумент `example`, как пример данных ожидаемых в параметре `Body()`: + +=== "Python 3.10+" + + ```Python hl_lines="22-27" + {!> ../../../docs_src/schema_extra_example/tutorial003_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="22-27" + {!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="23-28" + {!> ../../../docs_src/schema_extra_example/tutorial003_an.py!} + ``` + +=== "Python 3.10+ non-Annotated" + + !!! tip Заметка + Рекомендуется использовать версию с `Annotated`, если это возможно. + + ```Python hl_lines="18-23" + {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!} + ``` + +=== "Python 3.6+ non-Annotated" + + !!! tip Заметка + Рекомендуется использовать версию с `Annotated`, если это возможно. + + ```Python hl_lines="20-25" + {!> ../../../docs_src/schema_extra_example/tutorial003.py!} + ``` + +### Аргумент "example" в UI документации + +С любым из вышеуказанных методов это будет выглядеть так в `/docs`: + + + +### `Body` с аргументом `examples` + +В качестве альтернативы одному аргументу `example`, вы можете передавать `examples` используя тип данных `dict` с **несколькими примерами**, каждый из которых содержит дополнительную информацию, которая также будет добавлена в **OpenAPI**. + +Ключи `dict` указывают на каждый пример, а значения для каждого из них - на еще один тип `dict` с дополнительной информацией. + +Каждый конкретный пример типа `dict` в аргументе `examples` может содержать: + +* `summary`: Краткое описание для примера. +* `description`: Полное описание, которое может содержать текст в формате Markdown. +* `value`: Это конкретный пример, который отображается, например, в виде типа `dict`. +* `externalValue`: альтернатива параметру `value`, URL-адрес, указывающий на пример. Хотя это может не поддерживаться таким же количеством инструментов разработки и тестирования API, как параметр `value`. + +=== "Python 3.10+" + + ```Python hl_lines="23-49" + {!> ../../../docs_src/schema_extra_example/tutorial004_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="23-49" + {!> ../../../docs_src/schema_extra_example/tutorial004_an_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="24-50" + {!> ../../../docs_src/schema_extra_example/tutorial004_an.py!} + ``` + +=== "Python 3.10+ non-Annotated" + + !!! tip Заметка + Рекомендуется использовать версию с `Annotated`, если это возможно. + + ```Python hl_lines="19-45" + {!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!} + ``` + +=== "Python 3.6+ non-Annotated" + + !!! tip Заметка + Рекомендуется использовать версию с `Annotated`, если это возможно. + + ```Python hl_lines="21-47" + {!> ../../../docs_src/schema_extra_example/tutorial004.py!} + ``` + +### Аргумент "examples" в UI документации + +С аргументом `examples`, добавленным в `Body()`, страница документации `/docs` будет выглядеть так: + + + +## Технические Детали + +!!! warning Внимание + Эти технические детали относятся к стандартам **JSON Schema** и **OpenAPI**. + + Если предложенные выше идеи уже работают для вас, возможно этого будет достаточно и эти детали вам не потребуются, можете спокойно их пропустить. + +Когда вы добавляете пример внутрь модели Pydantic, используя `schema_extra` или `Field(example="something")`, этот пример добавляется в **JSON Schema** для данной модели Pydantic. + +И эта **JSON Schema** модели Pydantic включается в **OpenAPI** вашего API, а затем используется в UI документации. + +Поля `example` как такового не существует в стандартах **JSON Schema**. В последних версиях JSON-схемы определено поле `examples`, но OpenAPI 3.0.3 основан на более старой версии JSON-схемы, которая не имела поля `examples`. + +Таким образом, OpenAPI 3.0.3 определяет своё собственное поле `example` для модифицированной версии **JSON Schema**, которую он использует чтобы достичь той же цели (однако это именно поле `example`, а не `examples`), и именно это используется API в UI документации (с интеграцией Swagger UI). + +Итак, хотя поле `example` не является частью JSON-схемы, оно является частью настраиваемой версии JSON-схемы в OpenAPI, и именно это поле будет использоваться в UI документации. + +Однако, когда вы используете поле `example` или `examples` с любой другой функцией (`Query()`, `Body()`, и т.д.), эти примеры не добавляются в JSON-схему, которая описывает эти данные (даже в собственную версию JSON-схемы OpenAPI), они добавляются непосредственно в объявление *операции пути* в OpenAPI (вне частей OpenAPI, которые используют JSON-схему). + +Для функций `Path()`, `Query()`, `Header()`, и `Cookie()`, аргументы `example` или `examples` добавляются в определение OpenAPI, к объекту `Parameter Object` (в спецификации). + +И для функций `Body()`, `File()` и `Form()` аргументы `example` или `examples` аналогично добавляются в определение OpenAPI, к объекту `Request Body Object`, в поле `content` в объекте `Media Type Object` (в спецификации). + +С другой стороны, существует более новая версия OpenAPI: **3.1.0**, недавно выпущенная. Она основана на последней версии JSON-схемы и большинство модификаций из OpenAPI JSON-схемы удалены в обмен на новые возможности из последней версии JSON-схемы, так что все эти мелкие отличия устранены. Тем не менее, Swagger UI в настоящее время не поддерживает OpenAPI 3.1.0, поэтому пока лучше продолжать использовать вышеупомянутые методы. diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index e41333894..5fb453dd2 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -81,6 +81,7 @@ nav: - tutorial/body-multiple-params.md - tutorial/static-files.md - tutorial/debugging.md + - tutorial/schema-extra-example.md - async.md - Развёртывание: - deployment/index.md From 6fe26b5689ebc150c360f45570765f1f5cb5fa36 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 Jun 2023 20:29:47 +0000 Subject: [PATCH 09/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index ffa68e2c3..6df84bbe3 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/schema-extra-example.md`. PR [#9621](https://github.com/tiangolo/fastapi/pull/9621) by [@Alexandrhub](https://github.com/Alexandrhub). * 🐛 Fix `HTTPException` header type annotations. PR [#9648](https://github.com/tiangolo/fastapi/pull/9648) by [@tiangolo](https://github.com/tiangolo). * 🔥 Remove link to Pydantic's benchmark, as it was removed there. PR [#5811](https://github.com/tiangolo/fastapi/pull/5811) by [@Kludex](https://github.com/Kludex). * ♻ Remove `media_type` from `ORJSONResponse` as it's inherited from the parent class. PR [#5805](https://github.com/tiangolo/fastapi/pull/5805) by [@Kludex](https://github.com/Kludex). From 57679e8370ab0f792b6201c2f189adb8147e2ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E8=BF=87=E5=88=9D=E6=99=B4?= <129537877+ChoyeonChern@users.noreply.github.com> Date: Sun, 11 Jun 2023 04:30:28 +0800 Subject: [PATCH 10/38] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translatio?= =?UTF-8?q?ns=20for=20`docs/zh/docs/advanced/response-change-status-code.m?= =?UTF-8?q?d`=20and=20`docs/zh/docs/advanced/response-headers.md`=20(#9544?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../advanced/response-change-status-code.md | 31 +++++++++++++++ docs/zh/docs/advanced/response-headers.md | 39 +++++++++++++++++++ docs/zh/mkdocs.yml | 2 + 3 files changed, 72 insertions(+) create mode 100644 docs/zh/docs/advanced/response-change-status-code.md create mode 100644 docs/zh/docs/advanced/response-headers.md diff --git a/docs/zh/docs/advanced/response-change-status-code.md b/docs/zh/docs/advanced/response-change-status-code.md new file mode 100644 index 000000000..a289cf201 --- /dev/null +++ b/docs/zh/docs/advanced/response-change-status-code.md @@ -0,0 +1,31 @@ +# 响应 - 更改状态码 + +你可能之前已经了解到,你可以设置默认的[响应状态码](../tutorial/response-status-code.md){.internal-link target=_blank}。 + +但在某些情况下,你需要返回一个不同于默认值的状态码。 + +## 使用场景 + +例如,假设你想默认返回一个HTTP状态码为“OK”`200`。 + +但如果数据不存在,你想创建它,并返回一个HTTP状态码为“CREATED”`201`。 + +但你仍然希望能够使用`response_model`过滤和转换你返回的数据。 + +对于这些情况,你可以使用一个`Response`参数。 + +## 使用 `Response` 参数 + +你可以在你的*路径操作函数*中声明一个`Response`类型的参数(就像你可以为cookies和头部做的那样)。 + +然后你可以在这个*临时*响应对象中设置`status_code`。 + +```Python hl_lines="1 9 12" +{!../../../docs_src/response_change_status_code/tutorial001.py!} +``` + +然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。 + +**FastAPI**将使用这个临时响应来提取状态码(也包括cookies和头部),并将它们放入包含你返回的值的最终响应中,该响应由任何`response_model`过滤。 + +你也可以在依赖项中声明`Response`参数,并在其中设置状态码。但请注意,最后设置的状态码将会生效。 diff --git a/docs/zh/docs/advanced/response-headers.md b/docs/zh/docs/advanced/response-headers.md new file mode 100644 index 000000000..85dab15ac --- /dev/null +++ b/docs/zh/docs/advanced/response-headers.md @@ -0,0 +1,39 @@ +# 响应头 + +## 使用 `Response` 参数 + +你可以在你的*路径操作函数*中声明一个`Response`类型的参数(就像你可以为cookies做的那样)。 + +然后你可以在这个*临时*响应对象中设置头部。 +```Python hl_lines="1 7-8" +{!../../../docs_src/response_headers/tutorial002.py!} +``` + +然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。 + +**FastAPI**将使用这个临时响应来提取头部(也包括cookies和状态码),并将它们放入包含你返回的值的最终响应中,该响应由任何`response_model`过滤。 + +你也可以在依赖项中声明`Response`参数,并在其中设置头部(和cookies)。 + +## 直接返回 `Response` + +你也可以在直接返回`Response`时添加头部。 + +按照[直接返回响应](response-directly.md){.internal-link target=_blank}中所述创建响应,并将头部作为附加参数传递: +```Python hl_lines="10-12" +{!../../../docs_src/response_headers/tutorial001.py!} +``` + + +!!! 注意 "技术细节" + 你也可以使用`from starlette.responses import Response`或`from starlette.responses import JSONResponse`。 + + **FastAPI**提供了与`fastapi.responses`相同的`starlette.responses`,只是为了方便开发者。但是,大多数可用的响应都直接来自Starlette。 + + 由于`Response`经常用于设置头部和cookies,因此**FastAPI**还在`fastapi.Response`中提供了它。 + +## 自定义头部 + +请注意,可以使用'X-'前缀添加自定义专有头部。 + +但是,如果你有自定义头部,你希望浏览器中的客户端能够看到它们,你需要将它们添加到你的CORS配置中(在[CORS(跨源资源共享)](../tutorial/cors.md){.internal-link target=_blank}中阅读更多),使用在Starlette的CORS文档中记录的`expose_headers`参数。 diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml index 75bd2ccab..522c83766 100644 --- a/docs/zh/mkdocs.yml +++ b/docs/zh/mkdocs.yml @@ -117,6 +117,8 @@ nav: - advanced/response-directly.md - advanced/custom-response.md - advanced/response-cookies.md + - advanced/response-change-status-code.md + - advanced/response-headers.md - advanced/wsgi.md - contributing.md - help-fastapi.md From 9b141076950e16fac842701488c9441e867d15f8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 Jun 2023 20:31:03 +0000 Subject: [PATCH 11/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6df84bbe3..d66fa73d8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translations for `docs/zh/docs/advanced/response-change-status-code.md` and `docs/zh/docs/advanced/response-headers.md`. PR [#9544](https://github.com/tiangolo/fastapi/pull/9544) by [@ChoyeonChern](https://github.com/ChoyeonChern). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/schema-extra-example.md`. PR [#9621](https://github.com/tiangolo/fastapi/pull/9621) by [@Alexandrhub](https://github.com/Alexandrhub). * 🐛 Fix `HTTPException` header type annotations. PR [#9648](https://github.com/tiangolo/fastapi/pull/9648) by [@tiangolo](https://github.com/tiangolo). * 🔥 Remove link to Pydantic's benchmark, as it was removed there. PR [#5811](https://github.com/tiangolo/fastapi/pull/5811) by [@Kludex](https://github.com/Kludex). From e3d67a150c8370a4e2fd26fb77b82689859bc62f Mon Sep 17 00:00:00 2001 From: Ildar Ramazanov Date: Sun, 11 Jun 2023 00:36:25 +0400 Subject: [PATCH 12/38] =?UTF-8?q?=F0=9F=8C=90=20Add=20Russian=20translatio?= =?UTF-8?q?n=20for=20`docs/ru/docs/tutorial/index.md`=20(#5896)?= 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/tutorial/index.md | 80 ++++++++++++++++++++++++++++++++++ docs/ru/mkdocs.yml | 1 + 2 files changed, 81 insertions(+) create mode 100644 docs/ru/docs/tutorial/index.md diff --git a/docs/ru/docs/tutorial/index.md b/docs/ru/docs/tutorial/index.md new file mode 100644 index 000000000..4277a6c4f --- /dev/null +++ b/docs/ru/docs/tutorial/index.md @@ -0,0 +1,80 @@ +# Учебник - Руководство пользователя - Введение + +В этом руководстве шаг за шагом показано, как использовать **FastApi** с большинством его функций. + +Каждый раздел постепенно основывается на предыдущих, но он структурирован по отдельным темам, так что вы можете перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API. + +Он также создан для использования в качестве будущего справочника. + +Так что вы можете вернуться и посмотреть именно то, что вам нужно. + +## Запустите код + +Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы Python). + +Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `uvicorn` с параметрами: + +
+ +```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. +``` + +
+ +**НАСТОЯТЕЛЬНО рекомендуется**, чтобы вы написали или скопировали код, отредактировали его и запустили локально. + +Использование кода в вашем редакторе — это то, что действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д. + +--- + +## Установка FastAPI + +Первый шаг — установить FastAPI. + +Для руководства вы, возможно, захотите установить его со всеми дополнительными зависимостями и функциями: + +
+ +```console +$ pip install "fastapi[all]" + +---> 100% +``` + +
+ +...это также включает `uvicorn`, который вы можете использовать в качестве сервера, который запускает ваш код. + +!!! note "Технические детали" + Вы также можете установить его по частям. + + Это то, что вы, вероятно, сделаете, когда захотите развернуть свое приложение в рабочей среде: + + ``` + pip install fastapi + ``` + + Также установите `uvicorn` для работы в качестве сервера: + + ``` + pip install "uvicorn[standard]" + ``` + + И то же самое для каждой из необязательных зависимостей, которые вы хотите использовать. + +## Продвинутое руководство пользователя + +Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после руководства **Учебник - Руководство пользователя**. + +**Продвинутое руководство пользователя** основано на этом, использует те же концепции и учит вас некоторым дополнительным функциям. + +Но вы должны сначала прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас). + +Он разработан таким образом, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**. diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml index 5fb453dd2..9fb56ce1b 100644 --- a/docs/ru/mkdocs.yml +++ b/docs/ru/mkdocs.yml @@ -67,6 +67,7 @@ nav: - fastapi-people.md - python-types.md - Учебник - руководство пользователя: + - tutorial/index.md - tutorial/first-steps.md - tutorial/path-params.md - tutorial/query-params-str-validations.md From 4c64c15ead4d59d667d2956d8087a916f5de71b4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 Jun 2023 20:37:02 +0000 Subject: [PATCH 13/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d66fa73d8..5a3161734 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/index.md`. PR [#5896](https://github.com/tiangolo/fastapi/pull/5896) by [@Wilidon](https://github.com/Wilidon). * 🌐 Add Chinese translations for `docs/zh/docs/advanced/response-change-status-code.md` and `docs/zh/docs/advanced/response-headers.md`. PR [#9544](https://github.com/tiangolo/fastapi/pull/9544) by [@ChoyeonChern](https://github.com/ChoyeonChern). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/schema-extra-example.md`. PR [#9621](https://github.com/tiangolo/fastapi/pull/9621) by [@Alexandrhub](https://github.com/Alexandrhub). * 🐛 Fix `HTTPException` header type annotations. PR [#9648](https://github.com/tiangolo/fastapi/pull/9648) by [@tiangolo](https://github.com/tiangolo). From edc939eb3abdb2a2d557e0f32c2b40d944cd2528 Mon Sep 17 00:00:00 2001 From: Purwo Widodo Date: Sun, 11 Jun 2023 03:48:51 +0700 Subject: [PATCH 14/38] =?UTF-8?q?=F0=9F=8C=90=20Fix=20spelling=20in=20Indo?= =?UTF-8?q?nesian=20translation=20of=20`docs/id/docs/tutorial/index.md`=20?= =?UTF-8?q?(#5635)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Purwo Widodo Co-authored-by: Sebastián Ramírez --- docs/id/docs/tutorial/index.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/id/docs/tutorial/index.md b/docs/id/docs/tutorial/index.md index 8fec3c087..b8ed96ae1 100644 --- a/docs/id/docs/tutorial/index.md +++ b/docs/id/docs/tutorial/index.md @@ -10,9 +10,9 @@ 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). +Semua blok-blok kode dapat disalin 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: +Untuk menjalankan setiap contoh, salin kode ke file `main.py`, dan jalankan `uvicorn` dengan:
@@ -28,7 +28,7 @@ $ uvicorn main:app --reload
-**SANGAT disarankan** agar kamu menulis atau meng-copy kode, meng-editnya dan menjalankannya secara lokal. +**SANGAT disarankan** agar kamu menulis atau menyalin kode, mengubahnya 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. @@ -38,7 +38,7 @@ Dengan menggunakannya di dalam editor, benar-benar memperlihatkan manfaat dari F Langkah pertama adalah dengan meng-install FastAPI. -Untuk tutorial, kamu mungkin hendak meng-instalnya dengan semua pilihan fitur dan dependensinya: +Untuk tutorial, kamu mungkin hendak meng-installnya dengan semua pilihan fitur dan dependensinya:
@@ -53,15 +53,15 @@ $ pip install "fastapi[all]" ...yang juga termasuk `uvicorn`, yang dapat kamu gunakan sebagai server yang menjalankan kodemu. !!! catatan - Kamu juga dapat meng-instalnya bagian demi bagian. + Kamu juga dapat meng-installnya bagian demi bagian. - Hal ini mungkin yang akan kamu lakukan ketika kamu hendak men-deploy aplikasimu ke tahap produksi: + Hal ini mungkin yang akan kamu lakukan ketika kamu hendak menyebarkan (men-deploy) aplikasimu ke tahap produksi: ``` pip install fastapi ``` - Juga install `uvicorn` untk menjalankan server" + Juga install `uvicorn` untuk menjalankan server" ``` pip install "uvicorn[standard]" @@ -77,4 +77,4 @@ Tersedia juga **Pedoman Pengguna Lanjutan** yang dapat kamu baca nanti setelah * 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**. +Hal ini dirancang supaya 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 3d162455a7186f065a31c92a4defe21a19bf7287 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 Jun 2023 20:49:25 +0000 Subject: [PATCH 15/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5a3161734..4c7b3694a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Fix spelling in Indonesian translation of `docs/id/docs/tutorial/index.md`. PR [#5635](https://github.com/tiangolo/fastapi/pull/5635) by [@purwowd](https://github.com/purwowd). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/index.md`. PR [#5896](https://github.com/tiangolo/fastapi/pull/5896) by [@Wilidon](https://github.com/Wilidon). * 🌐 Add Chinese translations for `docs/zh/docs/advanced/response-change-status-code.md` and `docs/zh/docs/advanced/response-headers.md`. PR [#9544](https://github.com/tiangolo/fastapi/pull/9544) by [@ChoyeonChern](https://github.com/ChoyeonChern). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/schema-extra-example.md`. PR [#9621](https://github.com/tiangolo/fastapi/pull/9621) by [@Alexandrhub](https://github.com/Alexandrhub). From 4ac8b8e4432db5214e0a6081ccb6ef68a30f62d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 10 Jun 2023 22:58:15 +0200 Subject: [PATCH 16/38] =?UTF-8?q?=F0=9F=94=A7=20Add=20sponsor=20Platform.s?= =?UTF-8?q?h=20(#9650)?= 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/platform-sh-banner.png | Bin 0 -> 6313 bytes docs/en/docs/img/sponsors/platform-sh.png | Bin 0 -> 5779 bytes docs/en/overrides/main.html | 6 ++++++ 6 files changed, 11 insertions(+) create mode 100644 docs/en/docs/img/sponsors/platform-sh-banner.png create mode 100644 docs/en/docs/img/sponsors/platform-sh.png diff --git a/README.md b/README.md index e45e7f56c..ee25f1803 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index ad31dc0bc..9913c5df5 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -2,6 +2,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://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023 + title: "Build, run and scale your apps on a modern, reliable, and secure PaaS." + img: https://fastapi.tiangolo.com/img/sponsors/platform-sh.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 a95af177c..014744a10 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -15,3 +15,4 @@ logins: - svix - armand-sauzay - databento-bot + - nanram22 diff --git a/docs/en/docs/img/sponsors/platform-sh-banner.png b/docs/en/docs/img/sponsors/platform-sh-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f4580fac519541b46776d40071002d18804508 GIT binary patch literal 6313 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/sponsors/platform-sh.png b/docs/en/docs/img/sponsors/platform-sh.png new file mode 100644 index 0000000000000000000000000000000000000000..fb4e07becdb896502137ac3a4f673ed368875a86 GIT binary patch literal 5779 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 nDxm6LO1s
+ {% endblock %} From 58e50622dee3dfad35fb342c677407bd0a0f3f8a Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 Jun 2023 20:58:55 +0000 Subject: [PATCH 17/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4c7b3694a..b00a75a21 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔧 Add sponsor Platform.sh. PR [#9650](https://github.com/tiangolo/fastapi/pull/9650) by [@tiangolo](https://github.com/tiangolo). * 🌐 Fix spelling in Indonesian translation of `docs/id/docs/tutorial/index.md`. PR [#5635](https://github.com/tiangolo/fastapi/pull/5635) by [@purwowd](https://github.com/purwowd). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/index.md`. PR [#5896](https://github.com/tiangolo/fastapi/pull/5896) by [@Wilidon](https://github.com/Wilidon). * 🌐 Add Chinese translations for `docs/zh/docs/advanced/response-change-status-code.md` and `docs/zh/docs/advanced/response-headers.md`. PR [#9544](https://github.com/tiangolo/fastapi/pull/9544) by [@ChoyeonChern](https://github.com/ChoyeonChern). From 20d93fad94699eef779d668860772687b4f66270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 10 Jun 2023 23:50:09 +0200 Subject: [PATCH 18/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b00a75a21..eb0a08fdf 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,19 +2,33 @@ ## Latest Changes -* 🔧 Add sponsor Platform.sh. PR [#9650](https://github.com/tiangolo/fastapi/pull/9650) by [@tiangolo](https://github.com/tiangolo). +### Fixes + +* 🐛 Fix `HTTPException` header type annotations. PR [#9648](https://github.com/tiangolo/fastapi/pull/9648) by [@tiangolo](https://github.com/tiangolo). +* 🐛 Fix OpenAPI model fields int validations, `gte` to `ge`. PR [#9635](https://github.com/tiangolo/fastapi/pull/9635) by [@tiangolo](https://github.com/tiangolo). + +### Upgrades + +* 📌 Update minimum version of Pydantic to >=1.7.4. This fixes an issue when trying to use an old version of Pydantic. PR [#9567](https://github.com/tiangolo/fastapi/pull/9567) by [@Kludex](https://github.com/Kludex). + +### Docs + +* 🔥 Remove link to Pydantic's benchmark, as it was removed there. PR [#5811](https://github.com/tiangolo/fastapi/pull/5811) by [@Kludex](https://github.com/Kludex). + +### Translations + * 🌐 Fix spelling in Indonesian translation of `docs/id/docs/tutorial/index.md`. PR [#5635](https://github.com/tiangolo/fastapi/pull/5635) by [@purwowd](https://github.com/purwowd). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/index.md`. PR [#5896](https://github.com/tiangolo/fastapi/pull/5896) by [@Wilidon](https://github.com/Wilidon). * 🌐 Add Chinese translations for `docs/zh/docs/advanced/response-change-status-code.md` and `docs/zh/docs/advanced/response-headers.md`. PR [#9544](https://github.com/tiangolo/fastapi/pull/9544) by [@ChoyeonChern](https://github.com/ChoyeonChern). * 🌐 Add Russian translation for `docs/ru/docs/tutorial/schema-extra-example.md`. PR [#9621](https://github.com/tiangolo/fastapi/pull/9621) by [@Alexandrhub](https://github.com/Alexandrhub). -* 🐛 Fix `HTTPException` header type annotations. PR [#9648](https://github.com/tiangolo/fastapi/pull/9648) by [@tiangolo](https://github.com/tiangolo). -* 🔥 Remove link to Pydantic's benchmark, as it was removed there. PR [#5811](https://github.com/tiangolo/fastapi/pull/5811) by [@Kludex](https://github.com/Kludex). + +### Internal + +* 🔧 Add sponsor Platform.sh. PR [#9650](https://github.com/tiangolo/fastapi/pull/9650) by [@tiangolo](https://github.com/tiangolo). * ♻ Remove `media_type` from `ORJSONResponse` as it's inherited from the parent class. PR [#5805](https://github.com/tiangolo/fastapi/pull/5805) by [@Kludex](https://github.com/Kludex). * 👷 Add custom token to Smokeshow and Preview Docs for download-artifact, to prevent API rate limits. PR [#9646](https://github.com/tiangolo/fastapi/pull/9646) by [@tiangolo](https://github.com/tiangolo). * 👷 Add custom tokens for GitHub Actions to avoid rate limits. PR [#9647](https://github.com/tiangolo/fastapi/pull/9647) by [@tiangolo](https://github.com/tiangolo). * ♻ Instantiate `HTTPException` only when needed, optimization refactor. PR [#5356](https://github.com/tiangolo/fastapi/pull/5356) by [@pawamoy](https://github.com/pawamoy). -* 📌 Update minimum version of Pydantic to >=1.7.4. PR [#9567](https://github.com/tiangolo/fastapi/pull/9567) by [@Kludex](https://github.com/Kludex). -* 🐛 Fix OpenAPI model fields int validations, `gte` to `ge`. PR [#9635](https://github.com/tiangolo/fastapi/pull/9635) by [@tiangolo](https://github.com/tiangolo). ## 0.96.0 From 19347bfc3cd1d3dcf3d8216c642033dcb9a3d6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 10 Jun 2023 23:51:40 +0200 Subject: [PATCH 19/38] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.96.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 eb0a08fdf..0bf888183 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.96.1 + ### Fixes * 🐛 Fix `HTTPException` header type annotations. PR [#9648](https://github.com/tiangolo/fastapi/pull/9648) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index d564d5fa3..2bc795b4b 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.96.0" +__version__ = "0.96.1" from starlette import status as status From f5e2dd8025e2164af6779bdd883d432a47d2bd3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 11 Jun 2023 00:03:27 +0200 Subject: [PATCH 20/38] =?UTF-8?q?=F0=9F=93=9D=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, 5 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 0bf888183..765be57a9 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -14,6 +14,11 @@ * 📌 Update minimum version of Pydantic to >=1.7.4. This fixes an issue when trying to use an old version of Pydantic. PR [#9567](https://github.com/tiangolo/fastapi/pull/9567) by [@Kludex](https://github.com/Kludex). +### Refactors + +* ♻ Remove `media_type` from `ORJSONResponse` as it's inherited from the parent class. PR [#5805](https://github.com/tiangolo/fastapi/pull/5805) by [@Kludex](https://github.com/Kludex). +* ♻ Instantiate `HTTPException` only when needed, optimization refactor. PR [#5356](https://github.com/tiangolo/fastapi/pull/5356) by [@pawamoy](https://github.com/pawamoy). + ### Docs * 🔥 Remove link to Pydantic's benchmark, as it was removed there. PR [#5811](https://github.com/tiangolo/fastapi/pull/5811) by [@Kludex](https://github.com/Kludex). @@ -28,10 +33,8 @@ ### Internal * 🔧 Add sponsor Platform.sh. PR [#9650](https://github.com/tiangolo/fastapi/pull/9650) by [@tiangolo](https://github.com/tiangolo). -* ♻ Remove `media_type` from `ORJSONResponse` as it's inherited from the parent class. PR [#5805](https://github.com/tiangolo/fastapi/pull/5805) by [@Kludex](https://github.com/Kludex). * 👷 Add custom token to Smokeshow and Preview Docs for download-artifact, to prevent API rate limits. PR [#9646](https://github.com/tiangolo/fastapi/pull/9646) by [@tiangolo](https://github.com/tiangolo). * 👷 Add custom tokens for GitHub Actions to avoid rate limits. PR [#9647](https://github.com/tiangolo/fastapi/pull/9647) by [@tiangolo](https://github.com/tiangolo). -* ♻ Instantiate `HTTPException` only when needed, optimization refactor. PR [#5356](https://github.com/tiangolo/fastapi/pull/5356) by [@pawamoy](https://github.com/pawamoy). ## 0.96.0 From ab03f226353394da467b77ff08cad4cbf94463e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Sun, 11 Jun 2023 19:08:14 +0000 Subject: [PATCH 21/38] =?UTF-8?q?=E2=9C=A8=20Add=20exception=20handler=20f?= =?UTF-8?q?or=20`WebSocketRequestValidationError`=20(which=20also=20allows?= =?UTF-8?q?=20to=20override=20it)=20(#6030)?= 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 --- fastapi/applications.py | 8 +- fastapi/exception_handlers.py | 13 ++- fastapi/routing.py | 2 - tests/test_ws_router.py | 152 +++++++++++++++++++++++++++++++++- 4 files changed, 166 insertions(+), 9 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index 8b3a74d3c..d5ea1d72a 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -19,8 +19,9 @@ from fastapi.encoders import DictIntStrAny, SetIntStr from fastapi.exception_handlers import ( http_exception_handler, request_validation_exception_handler, + websocket_request_validation_exception_handler, ) -from fastapi.exceptions import RequestValidationError +from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError from fastapi.logger import logger from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware from fastapi.openapi.docs import ( @@ -145,6 +146,11 @@ class FastAPI(Starlette): self.exception_handlers.setdefault( RequestValidationError, request_validation_exception_handler ) + self.exception_handlers.setdefault( + WebSocketRequestValidationError, + # Starlette still has incorrect type specification for the handlers + websocket_request_validation_exception_handler, # type: ignore + ) self.user_middleware: List[Middleware] = ( [] if middleware is None else list(middleware) diff --git a/fastapi/exception_handlers.py b/fastapi/exception_handlers.py index 4d7ea5ec2..6c2ba7fed 100644 --- a/fastapi/exception_handlers.py +++ b/fastapi/exception_handlers.py @@ -1,10 +1,11 @@ from fastapi.encoders import jsonable_encoder -from fastapi.exceptions import RequestValidationError +from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError from fastapi.utils import is_body_allowed_for_status_code +from fastapi.websockets import WebSocket from starlette.exceptions import HTTPException from starlette.requests import Request from starlette.responses import JSONResponse, Response -from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY +from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION async def http_exception_handler(request: Request, exc: HTTPException) -> Response: @@ -23,3 +24,11 @@ async def request_validation_exception_handler( status_code=HTTP_422_UNPROCESSABLE_ENTITY, content={"detail": jsonable_encoder(exc.errors())}, ) + + +async def websocket_request_validation_exception_handler( + websocket: WebSocket, exc: WebSocketRequestValidationError +) -> None: + await websocket.close( + code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors()) + ) diff --git a/fastapi/routing.py b/fastapi/routing.py index 06c71bffa..7f1936f7f 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -56,7 +56,6 @@ from starlette.routing import ( request_response, websocket_session, ) -from starlette.status import WS_1008_POLICY_VIOLATION from starlette.types import ASGIApp, Lifespan, Scope from starlette.websockets import WebSocket @@ -283,7 +282,6 @@ def get_websocket_app( ) values, errors, _, _2, _3 = solved_result if errors: - await websocket.close(code=WS_1008_POLICY_VIOLATION) raise WebSocketRequestValidationError(errors) assert dependant.call is not None, "dependant.call must be a function" await dependant.call(**values) diff --git a/tests/test_ws_router.py b/tests/test_ws_router.py index c312821e9..240a42bb0 100644 --- a/tests/test_ws_router.py +++ b/tests/test_ws_router.py @@ -1,4 +1,16 @@ -from fastapi import APIRouter, Depends, FastAPI, WebSocket +import functools + +import pytest +from fastapi import ( + APIRouter, + Depends, + FastAPI, + Header, + WebSocket, + WebSocketDisconnect, + status, +) +from fastapi.middleware import Middleware from fastapi.testclient import TestClient router = APIRouter() @@ -63,9 +75,44 @@ async def router_native_prefix_ws(websocket: WebSocket): await websocket.close() -app.include_router(router) -app.include_router(prefix_router, prefix="/prefix") -app.include_router(native_prefix_route) +async def ws_dependency_err(): + raise NotImplementedError() + + +@router.websocket("/depends-err/") +async def router_ws_depends_err(websocket: WebSocket, data=Depends(ws_dependency_err)): + pass # pragma: no cover + + +async def ws_dependency_validate(x_missing: str = Header()): + pass # pragma: no cover + + +@router.websocket("/depends-validate/") +async def router_ws_depends_validate( + websocket: WebSocket, data=Depends(ws_dependency_validate) +): + pass # pragma: no cover + + +class CustomError(Exception): + pass + + +@router.websocket("/custom_error/") +async def router_ws_custom_error(websocket: WebSocket): + raise CustomError() + + +def make_app(app=None, **kwargs): + app = app or FastAPI(**kwargs) + app.include_router(router) + app.include_router(prefix_router, prefix="/prefix") + app.include_router(native_prefix_route) + return app + + +app = make_app(app) def test_app(): @@ -125,3 +172,100 @@ def test_router_with_params(): assert data == "path/to/file" data = websocket.receive_text() assert data == "a_query_param" + + +def test_wrong_uri(): + """ + Verify that a websocket connection to a non-existent endpoing returns in a shutdown + """ + client = TestClient(app) + with pytest.raises(WebSocketDisconnect) as e: + with client.websocket_connect("/no-router/"): + pass # pragma: no cover + assert e.value.code == status.WS_1000_NORMAL_CLOSURE + + +def websocket_middleware(middleware_func): + """ + Helper to create a Starlette pure websocket middleware + """ + + def middleware_constructor(app): + @functools.wraps(app) + async def wrapped_app(scope, receive, send): + if scope["type"] != "websocket": + return await app(scope, receive, send) # pragma: no cover + + async def call_next(): + return await app(scope, receive, send) + + websocket = WebSocket(scope, receive=receive, send=send) + return await middleware_func(websocket, call_next) + + return wrapped_app + + return middleware_constructor + + +def test_depend_validation(): + """ + Verify that a validation in a dependency invokes the correct exception handler + """ + caught = [] + + @websocket_middleware + async def catcher(websocket, call_next): + try: + return await call_next() + except Exception as e: # pragma: no cover + caught.append(e) + raise + + myapp = make_app(middleware=[Middleware(catcher)]) + + client = TestClient(myapp) + with pytest.raises(WebSocketDisconnect) as e: + with client.websocket_connect("/depends-validate/"): + pass # pragma: no cover + # the validation error does produce a close message + assert e.value.code == status.WS_1008_POLICY_VIOLATION + # and no error is leaked + assert caught == [] + + +def test_depend_err_middleware(): + """ + Verify that it is possible to write custom WebSocket middleware to catch errors + """ + + @websocket_middleware + async def errorhandler(websocket: WebSocket, call_next): + try: + return await call_next() + except Exception as e: + await websocket.close(code=status.WS_1006_ABNORMAL_CLOSURE, reason=repr(e)) + + myapp = make_app(middleware=[Middleware(errorhandler)]) + client = TestClient(myapp) + with pytest.raises(WebSocketDisconnect) as e: + with client.websocket_connect("/depends-err/"): + pass # pragma: no cover + assert e.value.code == status.WS_1006_ABNORMAL_CLOSURE + assert "NotImplementedError" in e.value.reason + + +def test_depend_err_handler(): + """ + Verify that it is possible to write custom WebSocket middleware to catch errors + """ + + async def custom_handler(websocket: WebSocket, exc: CustomError) -> None: + await websocket.close(1002, "foo") + + myapp = make_app(exception_handlers={CustomError: custom_handler}) + client = TestClient(myapp) + with pytest.raises(WebSocketDisconnect) as e: + with client.websocket_connect("/custom_error/"): + pass # pragma: no cover + assert e.value.code == 1002 + assert "foo" in e.value.reason From ee96a099d8acc7ede6c66aaef987b6412e0fcc54 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Jun 2023 19:08:50 +0000 Subject: [PATCH 22/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 765be57a9..8d51bb26e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add exception handler for `WebSocketRequestValidationError` (which also allows to override it). PR [#6030](https://github.com/tiangolo/fastapi/pull/6030) by [@kristjanvalur](https://github.com/kristjanvalur). ## 0.96.1 From d8b8f211e813ba4d53987a2bae16587eeaff4ad2 Mon Sep 17 00:00:00 2001 From: Paulo Costa Date: Sun, 11 Jun 2023 17:35:39 -0300 Subject: [PATCH 23/38] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20`depend?= =?UTF-8?q?encies`=20in=20WebSocket=20routes=20(#4534)?= 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 | 27 +++++++++++-- fastapi/routing.py | 47 +++++++++++++++++----- tests/test_ws_dependencies.py | 73 +++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 13 deletions(-) create mode 100644 tests/test_ws_dependencies.py diff --git a/fastapi/applications.py b/fastapi/applications.py index d5ea1d72a..298aca921 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -401,15 +401,34 @@ class FastAPI(Starlette): return decorator def add_api_websocket_route( - self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None + self, + path: str, + endpoint: Callable[..., Any], + name: Optional[str] = None, + *, + dependencies: Optional[Sequence[Depends]] = None, ) -> None: - self.router.add_api_websocket_route(path, endpoint, name=name) + self.router.add_api_websocket_route( + path, + endpoint, + name=name, + dependencies=dependencies, + ) def websocket( - self, path: str, name: Optional[str] = None + self, + path: str, + name: Optional[str] = None, + *, + dependencies: Optional[Sequence[Depends]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_api_websocket_route(path, func, name=name) + self.add_api_websocket_route( + path, + func, + name=name, + dependencies=dependencies, + ) return func return decorator diff --git a/fastapi/routing.py b/fastapi/routing.py index 7f1936f7f..af628f32d 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -296,13 +296,21 @@ class APIWebSocketRoute(routing.WebSocketRoute): endpoint: Callable[..., Any], *, name: Optional[str] = None, + dependencies: Optional[Sequence[params.Depends]] = None, dependency_overrides_provider: Optional[Any] = None, ) -> None: self.path = path self.endpoint = endpoint self.name = get_name(endpoint) if name is None else name + self.dependencies = list(dependencies or []) self.path_regex, self.path_format, self.param_convertors = compile_path(path) self.dependant = get_dependant(path=self.path_format, call=self.endpoint) + for depends in self.dependencies[::-1]: + self.dependant.dependencies.insert( + 0, + get_parameterless_sub_dependant(depends=depends, path=self.path_format), + ) + self.app = websocket_session( get_websocket_app( dependant=self.dependant, @@ -416,10 +424,7 @@ class APIRoute(routing.Route): else: self.response_field = None # type: ignore self.secure_cloned_response_field = None - if dependencies: - self.dependencies = list(dependencies) - else: - self.dependencies = [] + self.dependencies = list(dependencies or []) 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" @@ -514,7 +519,7 @@ class APIRouter(routing.Router): ), "A path prefix must not end with '/', as the routes will start with '/'" self.prefix = prefix self.tags: List[Union[str, Enum]] = tags or [] - self.dependencies = list(dependencies or []) or [] + self.dependencies = list(dependencies or []) self.deprecated = deprecated self.include_in_schema = include_in_schema self.responses = responses or {} @@ -688,21 +693,37 @@ class APIRouter(routing.Router): return decorator def add_api_websocket_route( - self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None + self, + path: str, + endpoint: Callable[..., Any], + name: Optional[str] = None, + *, + dependencies: Optional[Sequence[params.Depends]] = None, ) -> None: + current_dependencies = self.dependencies.copy() + if dependencies: + current_dependencies.extend(dependencies) + route = APIWebSocketRoute( self.prefix + path, endpoint=endpoint, name=name, + dependencies=current_dependencies, dependency_overrides_provider=self.dependency_overrides_provider, ) self.routes.append(route) def websocket( - self, path: str, name: Optional[str] = None + self, + path: str, + name: Optional[str] = None, + *, + dependencies: Optional[Sequence[params.Depends]] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_api_websocket_route(path, func, name=name) + self.add_api_websocket_route( + path, func, name=name, dependencies=dependencies + ) return func return decorator @@ -817,8 +838,16 @@ class APIRouter(routing.Router): name=route.name, ) elif isinstance(route, APIWebSocketRoute): + current_dependencies = [] + if dependencies: + current_dependencies.extend(dependencies) + if route.dependencies: + current_dependencies.extend(route.dependencies) self.add_api_websocket_route( - prefix + route.path, route.endpoint, name=route.name + prefix + route.path, + route.endpoint, + dependencies=current_dependencies, + name=route.name, ) elif isinstance(route, routing.WebSocketRoute): self.add_websocket_route( diff --git a/tests/test_ws_dependencies.py b/tests/test_ws_dependencies.py new file mode 100644 index 000000000..ccb1c4b7d --- /dev/null +++ b/tests/test_ws_dependencies.py @@ -0,0 +1,73 @@ +import json +from typing import List + +from fastapi import APIRouter, Depends, FastAPI, WebSocket +from fastapi.testclient import TestClient +from typing_extensions import Annotated + + +def dependency_list() -> List[str]: + return [] + + +DepList = Annotated[List[str], Depends(dependency_list)] + + +def create_dependency(name: str): + def fun(deps: DepList): + deps.append(name) + + return Depends(fun) + + +router = APIRouter(dependencies=[create_dependency("router")]) +prefix_router = APIRouter(dependencies=[create_dependency("prefix_router")]) +app = FastAPI(dependencies=[create_dependency("app")]) + + +@app.websocket("/", dependencies=[create_dependency("index")]) +async def index(websocket: WebSocket, deps: DepList): + await websocket.accept() + await websocket.send_text(json.dumps(deps)) + await websocket.close() + + +@router.websocket("/router", dependencies=[create_dependency("routerindex")]) +async def routerindex(websocket: WebSocket, deps: DepList): + await websocket.accept() + await websocket.send_text(json.dumps(deps)) + await websocket.close() + + +@prefix_router.websocket("/", dependencies=[create_dependency("routerprefixindex")]) +async def routerprefixindex(websocket: WebSocket, deps: DepList): + await websocket.accept() + await websocket.send_text(json.dumps(deps)) + await websocket.close() + + +app.include_router(router, dependencies=[create_dependency("router2")]) +app.include_router( + prefix_router, prefix="/prefix", dependencies=[create_dependency("prefix_router2")] +) + + +def test_index(): + client = TestClient(app) + with client.websocket_connect("/") as websocket: + data = json.loads(websocket.receive_text()) + assert data == ["app", "index"] + + +def test_routerindex(): + client = TestClient(app) + with client.websocket_connect("/router") as websocket: + data = json.loads(websocket.receive_text()) + assert data == ["app", "router2", "router", "routerindex"] + + +def test_routerprefixindex(): + client = TestClient(app) + with client.websocket_connect("/prefix/") as websocket: + data = json.loads(websocket.receive_text()) + assert data == ["app", "prefix_router2", "prefix_router", "routerprefixindex"] From c8b729aea72aaae22384461ead80ef39bf8588b0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Jun 2023 20:36:12 +0000 Subject: [PATCH 24/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8d51bb26e..e3b7c32cc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for `dependencies` in WebSocket routes. PR [#4534](https://github.com/tiangolo/fastapi/pull/4534) by [@paulo-raca](https://github.com/paulo-raca). * ✨ Add exception handler for `WebSocketRequestValidationError` (which also allows to override it). PR [#6030](https://github.com/tiangolo/fastapi/pull/6030) by [@kristjanvalur](https://github.com/kristjanvalur). ## 0.96.1 From 6595658324237b2905f16d3857bd524e58180f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 11 Jun 2023 23:38:15 +0200 Subject: [PATCH 25/38] =?UTF-8?q?=E2=AC=87=EF=B8=8F=20Separate=20requireme?= =?UTF-8?q?nts=20for=20development=20into=20their=20own=20requirements.txt?= =?UTF-8?q?=20files,=20they=20shouldn't=20be=20extras=20(#9655)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-docs.yml | 2 +- .github/workflows/test.yml | 2 +- docs/em/docs/contributing.md | 2 +- docs/en/docs/contributing.md | 9 +++++-- docs/ja/docs/contributing.md | 2 +- docs/pt/docs/contributing.md | 2 +- docs/ru/docs/contributing.md | 2 +- docs/zh/docs/contributing.md | 2 +- pyproject.toml | 41 -------------------------------- requirements-docs.txt | 8 +++++++ requirements-tests.txt | 26 ++++++++++++++++++++ requirements.txt | 6 +++++ scripts/build-docs.sh | 2 ++ scripts/test.sh | 2 -- 14 files changed, 56 insertions(+), 52 deletions(-) create mode 100644 requirements-docs.txt create mode 100644 requirements-tests.txt create mode 100644 requirements.txt diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 95cb8578b..41eb55b85 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -25,7 +25,7 @@ jobs: key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-v03 - name: Install docs extras if: steps.cache.outputs.cache-hit != 'true' - run: pip install .[doc] + run: pip install -r requirements-docs.txt - 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' run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 65b29be20..e3abe4b21 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test-v03 - name: Install Dependencies if: steps.cache.outputs.cache-hit != 'true' - run: pip install -e .[all,dev,doc,test] + run: pip install -r requirements-tests.txt - name: Lint run: bash scripts/lint.sh - run: mkdir coverage diff --git a/docs/em/docs/contributing.md b/docs/em/docs/contributing.md index 7749d27a1..748928f88 100644 --- a/docs/em/docs/contributing.md +++ b/docs/em/docs/contributing.md @@ -108,7 +108,7 @@ $ python -m pip install --upgrade pip
```console -$ pip install -e ."[dev,doc,test]" +$ pip install -r requirements.txt ---> 100% ``` diff --git a/docs/en/docs/contributing.md b/docs/en/docs/contributing.md index a1a32a1fe..660914a08 100644 --- a/docs/en/docs/contributing.md +++ b/docs/en/docs/contributing.md @@ -108,7 +108,7 @@ After activating the environment as described above:
```console -$ pip install -e ".[dev,doc,test]" +$ pip install -r requirements.txt ---> 100% ``` @@ -121,10 +121,15 @@ It will install all the dependencies and your local FastAPI in your local enviro If you create a Python file that imports and uses FastAPI, and run it with the Python from your local environment, it will use your local FastAPI source code. -And if you update that local FastAPI source code, as it is installed with `-e`, when you run that Python file again, it will use the fresh version of FastAPI you just edited. +And if you update that local FastAPI source code when you run that Python file again, it will use the fresh version of FastAPI you just edited. That way, you don't have to "install" your local version to be able to test every change. +!!! note "Technical Details" + This only happens when you install using this included `requiements.txt` instead of installing `pip install fastapi` directly. + + That is because inside of the `requirements.txt` file, the local version of FastAPI is marked to be installed in "editable" mode, with the `-e` option. + ### Format There is a script that you can run that will format and clean all your code: diff --git a/docs/ja/docs/contributing.md b/docs/ja/docs/contributing.md index 9affea443..31db51c52 100644 --- a/docs/ja/docs/contributing.md +++ b/docs/ja/docs/contributing.md @@ -97,7 +97,7 @@ $ python -m venv env
```console -$ pip install -e ."[dev,doc,test]" +$ pip install -r requirements.txt ---> 100% ``` diff --git a/docs/pt/docs/contributing.md b/docs/pt/docs/contributing.md index f95b6f4ec..02895fcfc 100644 --- a/docs/pt/docs/contributing.md +++ b/docs/pt/docs/contributing.md @@ -98,7 +98,7 @@ Após ativar o ambiente como descrito acima:
```console -$ pip install -e ."[dev,doc,test]" +$ pip install -r requirements.txt ---> 100% ``` diff --git a/docs/ru/docs/contributing.md b/docs/ru/docs/contributing.md index f61ef1cb6..f9b8912e5 100644 --- a/docs/ru/docs/contributing.md +++ b/docs/ru/docs/contributing.md @@ -108,7 +108,7 @@ $ python -m pip install --upgrade pip
```console -$ pip install -e ."[dev,doc,test]" +$ pip install -r requirements.txt ---> 100% ``` diff --git a/docs/zh/docs/contributing.md b/docs/zh/docs/contributing.md index 36c3631c4..4ebd67315 100644 --- a/docs/zh/docs/contributing.md +++ b/docs/zh/docs/contributing.md @@ -97,7 +97,7 @@ $ python -m venv env
```console -$ pip install -e ."[dev,doc,test]" +$ pip install -r requirements.txt ---> 100% ``` diff --git a/pyproject.toml b/pyproject.toml index 3bae6a3ef..69c42b254 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,47 +51,6 @@ Homepage = "https://github.com/tiangolo/fastapi" Documentation = "https://fastapi.tiangolo.com/" [project.optional-dependencies] -test = [ - "pytest >=7.1.3,<8.0.0", - "coverage[toml] >= 6.5.0,< 8.0", - "mypy ==0.982", - "ruff ==0.0.138", - "black == 23.1.0", - "isort >=5.0.6,<6.0.0", - "httpx >=0.23.0,<0.24.0", - "email_validator >=1.1.1,<2.0.0", - # TODO: once removing databases from tutorial, upgrade SQLAlchemy - # probably when including SQLModel - "sqlalchemy >=1.3.18,<1.4.43", - "peewee >=3.13.3,<4.0.0", - "databases[sqlite] >=0.3.2,<0.7.0", - "orjson >=3.2.1,<4.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.7", - "flask >=1.1.2,<3.0.0", - "anyio[trio] >=3.2.1,<4.0.0", - "python-jose[cryptography] >=3.3.0,<4.0.0", - "pyyaml >=5.3.1,<7.0.0", - "passlib[bcrypt] >=1.7.2,<2.0.0", - - # types - "types-ujson ==5.7.0.1", - "types-orjson ==3.6.2", -] -doc = [ - "mkdocs >=1.1.2,<2.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.13,<0.0.14", - "typer[all] >=0.6.1,<0.8.0", - "pyyaml >=5.3.1,<7.0.0", -] -dev = [ - "ruff ==0.0.138", - "uvicorn[standard] >=0.12.0,<0.21.0", - "pre-commit >=2.17.0,<3.0.0", -] all = [ "httpx >=0.23.0", "jinja2 >=2.11.2", diff --git a/requirements-docs.txt b/requirements-docs.txt new file mode 100644 index 000000000..e9d0567ed --- /dev/null +++ b/requirements-docs.txt @@ -0,0 +1,8 @@ +-e . +mkdocs >=1.1.2,<2.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.13,<0.0.14 +typer[all] >=0.6.1,<0.8.0 +pyyaml >=5.3.1,<7.0.0 diff --git a/requirements-tests.txt b/requirements-tests.txt new file mode 100644 index 000000000..52a44cec5 --- /dev/null +++ b/requirements-tests.txt @@ -0,0 +1,26 @@ +-e . +pytest >=7.1.3,<8.0.0 +coverage[toml] >= 6.5.0,< 8.0 +mypy ==0.982 +ruff ==0.0.138 +black == 23.1.0 +isort >=5.0.6,<6.0.0 +httpx >=0.23.0,<0.24.0 +email_validator >=1.1.1,<2.0.0 +# TODO: once removing databases from tutorial, upgrade SQLAlchemy +# probably when including SQLModel +sqlalchemy >=1.3.18,<1.4.43 +peewee >=3.13.3,<4.0.0 +databases[sqlite] >=0.3.2,<0.7.0 +orjson >=3.2.1,<4.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.7 +flask >=1.1.2,<3.0.0 +anyio[trio] >=3.2.1,<4.0.0 +python-jose[cryptography] >=3.3.0,<4.0.0 +pyyaml >=5.3.1,<7.0.0 +passlib[bcrypt] >=1.7.2,<2.0.0 + +# types +types-ujson ==5.7.0.1 +types-orjson ==3.6.2 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..9d51e1cb3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +-e .[all] +-r requirements-tests.txt +-r requirements-docs.txt +ruff ==0.0.138 +uvicorn[standard] >=0.12.0,<0.21.0 +pre-commit >=2.17.0,<3.0.0 diff --git a/scripts/build-docs.sh b/scripts/build-docs.sh index 383ad3f44..ebf864afa 100755 --- a/scripts/build-docs.sh +++ b/scripts/build-docs.sh @@ -3,4 +3,6 @@ set -e set -x +# Check README.md is up to date +python ./scripts/docs.py verify-readme python ./scripts/docs.py build-all diff --git a/scripts/test.sh b/scripts/test.sh index 62449ea41..7d17add8f 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -3,7 +3,5 @@ set -e set -x -# Check README.md is up to date -python ./scripts/docs.py verify-readme export PYTHONPATH=./docs_src coverage run -m pytest tests ${@} From df58ecdee2eda8bbac7fb8b8bcb00c4479e5d6db Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Jun 2023 21:38:54 +0000 Subject: [PATCH 26/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e3b7c32cc..160ec2fe8 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬇️ Separate requirements for development into their own requirements.txt files, they shouldn't be extras. PR [#9655](https://github.com/tiangolo/fastapi/pull/9655) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for `dependencies` in WebSocket routes. PR [#4534](https://github.com/tiangolo/fastapi/pull/4534) by [@paulo-raca](https://github.com/paulo-raca). * ✨ Add exception handler for `WebSocketRequestValidationError` (which also allows to override it). PR [#6030](https://github.com/tiangolo/fastapi/pull/6030) by [@kristjanvalur](https://github.com/kristjanvalur). From 17e49bc9f75d9f596eb3fea42a3f51f3a716475c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 11 Jun 2023 23:49:18 +0200 Subject: [PATCH 27/38] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Simplify=20`AsyncExi?= =?UTF-8?q?tStackMiddleware`=20as=20without=20Python=203.6=20`AsyncExitSta?= =?UTF-8?q?ck`=20is=20always=20available=20(#9657)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ♻️ Simplify AsyncExitStackMiddleware as without Python 3.6 AsyncExitStack is always available --- fastapi/middleware/asyncexitstack.py | 29 +++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/fastapi/middleware/asyncexitstack.py b/fastapi/middleware/asyncexitstack.py index 503a68ac7..30a0ae626 100644 --- a/fastapi/middleware/asyncexitstack.py +++ b/fastapi/middleware/asyncexitstack.py @@ -10,19 +10,16 @@ class AsyncExitStackMiddleware: 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 + 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 From 32cefb9bff624825d3086bed84bd380d8cc01f15 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Jun 2023 21:49:52 +0000 Subject: [PATCH 28/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 160ec2fe8..2ea4ef8e1 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻️ Simplify `AsyncExitStackMiddleware` as without Python 3.6 `AsyncExitStack` is always available. PR [#9657](https://github.com/tiangolo/fastapi/pull/9657) by [@tiangolo](https://github.com/tiangolo). * ⬇️ Separate requirements for development into their own requirements.txt files, they shouldn't be extras. PR [#9655](https://github.com/tiangolo/fastapi/pull/9655) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for `dependencies` in WebSocket routes. PR [#4534](https://github.com/tiangolo/fastapi/pull/4534) by [@paulo-raca](https://github.com/paulo-raca). * ✨ Add exception handler for `WebSocketRequestValidationError` (which also allows to override it). PR [#6030](https://github.com/tiangolo/fastapi/pull/6030) by [@kristjanvalur](https://github.com/kristjanvalur). From f5844e76b5e710ae8d42654927c1202f00f79526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 12 Jun 2023 00:08:56 +0200 Subject: [PATCH 29/38] =?UTF-8?q?=F0=9F=92=9A=20Update=20CI=20cache=20to?= =?UTF-8?q?=20fix=20installs=20when=20dependencies=20change=20(#9659)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-docs.yml | 2 +- .github/workflows/test.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 41eb55b85..a0e83e5c8 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-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-v03 + key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v03 - name: Install docs extras if: steps.cache.outputs.cache-hit != 'true' run: pip install -r requirements-docs.txt diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3abe4b21..b17d2e9d5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,12 +23,12 @@ jobs: python-version: ${{ matrix.python-version }} # Issue ref: https://github.com/actions/setup-python/issues/436 # cache: "pip" - cache-dependency-path: pyproject.toml + # cache-dependency-path: pyproject.toml - uses: actions/cache@v3 id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test-v03 + key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v03 - name: Install Dependencies if: steps.cache.outputs.cache-hit != 'true' run: pip install -r requirements-tests.txt @@ -57,7 +57,7 @@ jobs: python-version: '3.8' # Issue ref: https://github.com/actions/setup-python/issues/436 # cache: "pip" - cache-dependency-path: pyproject.toml + # cache-dependency-path: pyproject.toml - name: Get coverage files uses: actions/download-artifact@v3 From 3390a82832df2e5b6f0348ba71c570bd6f3a7f82 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Jun 2023 22:09:33 +0000 Subject: [PATCH 30/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2ea4ef8e1..c01399327 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 💚 Update CI cache to fix installs when dependencies change. PR [#9659](https://github.com/tiangolo/fastapi/pull/9659) by [@tiangolo](https://github.com/tiangolo). * ♻️ Simplify `AsyncExitStackMiddleware` as without Python 3.6 `AsyncExitStack` is always available. PR [#9657](https://github.com/tiangolo/fastapi/pull/9657) by [@tiangolo](https://github.com/tiangolo). * ⬇️ Separate requirements for development into their own requirements.txt files, they shouldn't be extras. PR [#9655](https://github.com/tiangolo/fastapi/pull/9655) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for `dependencies` in WebSocket routes. PR [#4534](https://github.com/tiangolo/fastapi/pull/4534) by [@paulo-raca](https://github.com/paulo-raca). From 4ac55af283457d7279711224c5f9a3810d4d6534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 12 Jun 2023 00:16:01 +0200 Subject: [PATCH 31/38] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Update=20internal=20?= =?UTF-8?q?type=20annotations=20and=20upgrade=20mypy=20(#9658)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/openapi/models.py | 13 ++++++++----- fastapi/security/api_key.py | 12 +++++++++--- fastapi/security/oauth2.py | 25 ++++++++++++++++--------- requirements-tests.txt | 2 +- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 11edfe38a..81a24f389 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -3,6 +3,7 @@ from typing import Any, Callable, Dict, Iterable, List, Optional, Union from fastapi.logger import logger from pydantic import AnyUrl, BaseModel, Field +from typing_extensions import Literal try: import email_validator # type: ignore @@ -298,18 +299,18 @@ class APIKeyIn(Enum): class APIKey(SecurityBase): - type_ = Field(SecuritySchemeType.apiKey, alias="type") + type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type") in_: APIKeyIn = Field(alias="in") name: str class HTTPBase(SecurityBase): - type_ = Field(SecuritySchemeType.http, alias="type") + type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type") scheme: str class HTTPBearer(HTTPBase): - scheme = "bearer" + scheme: Literal["bearer"] = "bearer" bearerFormat: Optional[str] = None @@ -349,12 +350,14 @@ class OAuthFlows(BaseModel): class OAuth2(SecurityBase): - type_ = Field(SecuritySchemeType.oauth2, alias="type") + type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type") flows: OAuthFlows class OpenIdConnect(SecurityBase): - type_ = Field(SecuritySchemeType.openIdConnect, alias="type") + type_: SecuritySchemeType = Field( + default=SecuritySchemeType.openIdConnect, alias="type" + ) openIdConnectUrl: str diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py index 61730187a..8b2c5c080 100644 --- a/fastapi/security/api_key.py +++ b/fastapi/security/api_key.py @@ -21,7 +21,9 @@ class APIKeyQuery(APIKeyBase): auto_error: bool = True, ): self.model: APIKey = APIKey( - **{"in": APIKeyIn.query}, name=name, description=description + **{"in": APIKeyIn.query}, # type: ignore[arg-type] + name=name, + description=description, ) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error @@ -48,7 +50,9 @@ class APIKeyHeader(APIKeyBase): auto_error: bool = True, ): self.model: APIKey = APIKey( - **{"in": APIKeyIn.header}, name=name, description=description + **{"in": APIKeyIn.header}, # type: ignore[arg-type] + name=name, + description=description, ) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error @@ -75,7 +79,9 @@ class APIKeyCookie(APIKeyBase): auto_error: bool = True, ): self.model: APIKey = APIKey( - **{"in": APIKeyIn.cookie}, name=name, description=description + **{"in": APIKeyIn.cookie}, # type: ignore[arg-type] + name=name, + 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 dc75dc9fe..938dec37c 100644 --- a/fastapi/security/oauth2.py +++ b/fastapi/security/oauth2.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Union, cast from fastapi.exceptions import HTTPException from fastapi.openapi.models import OAuth2 as OAuth2Model @@ -121,7 +121,9 @@ class OAuth2(SecurityBase): description: Optional[str] = None, auto_error: bool = True, ): - self.model = OAuth2Model(flows=flows, description=description) + self.model = OAuth2Model( + flows=cast(OAuthFlowsModel, flows), description=description + ) self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error @@ -148,7 +150,9 @@ class OAuth2PasswordBearer(OAuth2): ): if not scopes: scopes = {} - flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes}) + flows = OAuthFlowsModel( + password=cast(Any, {"tokenUrl": tokenUrl, "scopes": scopes}) + ) super().__init__( flows=flows, scheme_name=scheme_name, @@ -185,12 +189,15 @@ class OAuth2AuthorizationCodeBearer(OAuth2): if not scopes: scopes = {} flows = OAuthFlowsModel( - authorizationCode={ - "authorizationUrl": authorizationUrl, - "tokenUrl": tokenUrl, - "refreshUrl": refreshUrl, - "scopes": scopes, - } + authorizationCode=cast( + Any, + { + "authorizationUrl": authorizationUrl, + "tokenUrl": tokenUrl, + "refreshUrl": refreshUrl, + "scopes": scopes, + }, + ) ) super().__init__( flows=flows, diff --git a/requirements-tests.txt b/requirements-tests.txt index 52a44cec5..5105071be 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -1,7 +1,7 @@ -e . pytest >=7.1.3,<8.0.0 coverage[toml] >= 6.5.0,< 8.0 -mypy ==0.982 +mypy ==1.3.0 ruff ==0.0.138 black == 23.1.0 isort >=5.0.6,<6.0.0 From ba882c10feb34f8056d6d6819261d94d8820b3a5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Jun 2023 22:16:38 +0000 Subject: [PATCH 32/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c01399327..91e1c7aba 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ♻️ Update internal type annotations and upgrade mypy. PR [#9658](https://github.com/tiangolo/fastapi/pull/9658) by [@tiangolo](https://github.com/tiangolo). * 💚 Update CI cache to fix installs when dependencies change. PR [#9659](https://github.com/tiangolo/fastapi/pull/9659) by [@tiangolo](https://github.com/tiangolo). * ♻️ Simplify `AsyncExitStackMiddleware` as without Python 3.6 `AsyncExitStack` is always available. PR [#9657](https://github.com/tiangolo/fastapi/pull/9657) by [@tiangolo](https://github.com/tiangolo). * ⬇️ Separate requirements for development into their own requirements.txt files, they shouldn't be extras. PR [#9655](https://github.com/tiangolo/fastapi/pull/9655) by [@tiangolo](https://github.com/tiangolo). From 7167c77a18627c69fae2063cb987048ffc0a5633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 12 Jun 2023 00:37:34 +0200 Subject: [PATCH 33/38] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20and=20full?= =?UTF-8?q?y=20migrate=20to=20Ruff,=20remove=20isort,=20includes=20a=20cou?= =?UTF-8?q?ple=20of=20tweaks=20suggested=20by=20the=20new=20version=20of?= =?UTF-8?q?=20Ruff=20(#9660)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 13 +------------ fastapi/openapi/utils.py | 8 +++----- fastapi/routing.py | 13 +++++++++---- pyproject.toml | 6 +----- requirements-tests.txt | 3 +-- requirements.txt | 1 - scripts/format.sh | 1 - scripts/lint.sh | 1 - tests/test_empty_router.py | 3 ++- 9 files changed, 17 insertions(+), 32 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 25e797d24..7050aa31c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,22 +21,11 @@ repos: - --py3-plus - --keep-runtime-typing - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.254 + rev: v0.0.272 hooks: - id: ruff args: - --fix -- repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - name: isort (python) - - id: isort - name: isort (cython) - types: [cython] - - id: isort - name: isort (pyi) - types: [pyi] - repo: https://github.com/psf/black rev: 23.1.0 hooks: diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 86e15b46d..6d736647b 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -181,7 +181,7 @@ def get_openapi_operation_metadata( file_name = getattr(route.endpoint, "__globals__", {}).get("__file__") if file_name: message += f" at {file_name}" - warnings.warn(message) + warnings.warn(message, stacklevel=1) operation_ids.add(operation_id) operation["operationId"] = operation_id if route.deprecated: @@ -332,10 +332,8 @@ def get_openapi_path( openapi_response["description"] = description http422 = str(HTTP_422_UNPROCESSABLE_ENTITY) if (all_route_params or route.body_field) and not any( - [ - status in operation["responses"] - for status in [http422, "4XX", "default"] - ] + status in operation["responses"] + for status in [http422, "4XX", "default"] ): operation["responses"][http422] = { "description": "Validation Error", diff --git a/fastapi/routing.py b/fastapi/routing.py index af628f32d..ec8af99b3 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -30,7 +30,11 @@ from fastapi.dependencies.utils import ( solve_dependencies, ) from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder -from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError +from fastapi.exceptions import ( + FastAPIError, + RequestValidationError, + WebSocketRequestValidationError, +) from fastapi.types import DecoratedCallable from fastapi.utils import ( create_cloned_field, @@ -48,14 +52,15 @@ 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, Match -from starlette.routing import Mount as Mount # noqa from starlette.routing import ( + BaseRoute, + Match, compile_path, get_name, request_response, websocket_session, ) +from starlette.routing import Mount as Mount # noqa from starlette.types import ASGIApp, Lifespan, Scope from starlette.websockets import WebSocket @@ -763,7 +768,7 @@ class APIRouter(routing.Router): path = getattr(r, "path") # noqa: B009 name = getattr(r, "name", "unknown") if path is not None and not path: - raise Exception( + raise FastAPIError( f"Prefix and path cannot be both empty (path operation: {name})" ) if responses is None: diff --git a/pyproject.toml b/pyproject.toml index 69c42b254..547137144 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,10 +66,6 @@ all = [ [tool.hatch.version] path = "fastapi/__init__.py" -[tool.isort] -profile = "black" -known_third_party = ["fastapi", "pydantic", "starlette"] - [tool.mypy] strict = true @@ -125,7 +121,7 @@ select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes - # "I", # isort + "I", # isort "C", # flake8-comprehensions "B", # flake8-bugbear ] diff --git a/requirements-tests.txt b/requirements-tests.txt index 5105071be..a98280677 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -2,9 +2,8 @@ pytest >=7.1.3,<8.0.0 coverage[toml] >= 6.5.0,< 8.0 mypy ==1.3.0 -ruff ==0.0.138 +ruff ==0.0.272 black == 23.1.0 -isort >=5.0.6,<6.0.0 httpx >=0.23.0,<0.24.0 email_validator >=1.1.1,<2.0.0 # TODO: once removing databases from tutorial, upgrade SQLAlchemy diff --git a/requirements.txt b/requirements.txt index 9d51e1cb3..cb9abb44a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ -e .[all] -r requirements-tests.txt -r requirements-docs.txt -ruff ==0.0.138 uvicorn[standard] >=0.12.0,<0.21.0 pre-commit >=2.17.0,<3.0.0 diff --git a/scripts/format.sh b/scripts/format.sh index 3ac1fead8..3fb3eb4f1 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -3,4 +3,3 @@ set -x ruff fastapi tests docs_src scripts --fix black fastapi tests docs_src scripts -isort fastapi tests docs_src scripts diff --git a/scripts/lint.sh b/scripts/lint.sh index 0feb973a8..4db5caa96 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -6,4 +6,3 @@ set -x mypy fastapi ruff fastapi tests docs_src scripts black fastapi tests --check -isort fastapi tests docs_src scripts --check-only diff --git a/tests/test_empty_router.py b/tests/test_empty_router.py index 186ceb347..1a40cbe30 100644 --- a/tests/test_empty_router.py +++ b/tests/test_empty_router.py @@ -1,5 +1,6 @@ import pytest from fastapi import APIRouter, FastAPI +from fastapi.exceptions import FastAPIError from fastapi.testclient import TestClient app = FastAPI() @@ -31,5 +32,5 @@ def test_use_empty(): def test_include_empty(): # if both include and router.path are empty - it should raise exception - with pytest.raises(Exception): + with pytest.raises(FastAPIError): app.include_router(router) From 32897962860ad4c5045748c7955562922f659d08 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Jun 2023 22:38:17 +0000 Subject: [PATCH 34/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 91e1c7aba..14b1d5588 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade and fully migrate to Ruff, remove isort, includes a couple of tweaks suggested by the new version of Ruff. PR [#9660](https://github.com/tiangolo/fastapi/pull/9660) by [@tiangolo](https://github.com/tiangolo). * ♻️ Update internal type annotations and upgrade mypy. PR [#9658](https://github.com/tiangolo/fastapi/pull/9658) by [@tiangolo](https://github.com/tiangolo). * 💚 Update CI cache to fix installs when dependencies change. PR [#9659](https://github.com/tiangolo/fastapi/pull/9659) by [@tiangolo](https://github.com/tiangolo). * ♻️ Simplify `AsyncExitStackMiddleware` as without Python 3.6 `AsyncExitStack` is always available. PR [#9657](https://github.com/tiangolo/fastapi/pull/9657) by [@tiangolo](https://github.com/tiangolo). From 34fca99b284665c60d49ebac925ddeecf58eaca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 12 Jun 2023 00:46:44 +0200 Subject: [PATCH 35/38] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20Black=20(#?= =?UTF-8?q?9661)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 2 +- requirements-tests.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7050aa31c..2a8a03136 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: args: - --fix - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.3.0 hooks: - id: black ci: diff --git a/requirements-tests.txt b/requirements-tests.txt index a98280677..3ef3c4fd9 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -3,7 +3,7 @@ pytest >=7.1.3,<8.0.0 coverage[toml] >= 6.5.0,< 8.0 mypy ==1.3.0 ruff ==0.0.272 -black == 23.1.0 +black == 23.3.0 httpx >=0.23.0,<0.24.0 email_validator >=1.1.1,<2.0.0 # TODO: once removing databases from tutorial, upgrade SQLAlchemy From e958d30d1ddd82d5deadd613f3b9887865427522 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 11 Jun 2023 22:47:16 +0000 Subject: [PATCH 36/38] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 14b1d5588..6a09d5416 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ⬆️ Upgrade Black. PR [#9661](https://github.com/tiangolo/fastapi/pull/9661) by [@tiangolo](https://github.com/tiangolo). * ⬆️ Upgrade and fully migrate to Ruff, remove isort, includes a couple of tweaks suggested by the new version of Ruff. PR [#9660](https://github.com/tiangolo/fastapi/pull/9660) by [@tiangolo](https://github.com/tiangolo). * ♻️ Update internal type annotations and upgrade mypy. PR [#9658](https://github.com/tiangolo/fastapi/pull/9658) by [@tiangolo](https://github.com/tiangolo). * 💚 Update CI cache to fix installs when dependencies change. PR [#9659](https://github.com/tiangolo/fastapi/pull/9659) by [@tiangolo](https://github.com/tiangolo). From 395ece75aad0ee46eb39b9786bb52ceb89627837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 12 Jun 2023 00:49:35 +0200 Subject: [PATCH 37/38] =?UTF-8?q?=F0=9F=93=9D=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, 16 insertions(+), 4 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 6a09d5416..63d7d3e5e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,14 +2,26 @@ ## Latest Changes -* ⬆️ Upgrade Black. PR [#9661](https://github.com/tiangolo/fastapi/pull/9661) by [@tiangolo](https://github.com/tiangolo). + +### Features + +* ✨ Add support for `dependencies` in WebSocket routes. PR [#4534](https://github.com/tiangolo/fastapi/pull/4534) by [@paulo-raca](https://github.com/paulo-raca). +* ✨ Add exception handler for `WebSocketRequestValidationError` (which also allows to override it). PR [#6030](https://github.com/tiangolo/fastapi/pull/6030) by [@kristjanvalur](https://github.com/kristjanvalur). + +### Refactors + * ⬆️ Upgrade and fully migrate to Ruff, remove isort, includes a couple of tweaks suggested by the new version of Ruff. PR [#9660](https://github.com/tiangolo/fastapi/pull/9660) by [@tiangolo](https://github.com/tiangolo). * ♻️ Update internal type annotations and upgrade mypy. PR [#9658](https://github.com/tiangolo/fastapi/pull/9658) by [@tiangolo](https://github.com/tiangolo). -* 💚 Update CI cache to fix installs when dependencies change. PR [#9659](https://github.com/tiangolo/fastapi/pull/9659) by [@tiangolo](https://github.com/tiangolo). * ♻️ Simplify `AsyncExitStackMiddleware` as without Python 3.6 `AsyncExitStack` is always available. PR [#9657](https://github.com/tiangolo/fastapi/pull/9657) by [@tiangolo](https://github.com/tiangolo). + +### Upgrades + +* ⬆️ Upgrade Black. PR [#9661](https://github.com/tiangolo/fastapi/pull/9661) by [@tiangolo](https://github.com/tiangolo). + +### Internal + +* 💚 Update CI cache to fix installs when dependencies change. PR [#9659](https://github.com/tiangolo/fastapi/pull/9659) by [@tiangolo](https://github.com/tiangolo). * ⬇️ Separate requirements for development into their own requirements.txt files, they shouldn't be extras. PR [#9655](https://github.com/tiangolo/fastapi/pull/9655) by [@tiangolo](https://github.com/tiangolo). -* ✨ Add support for `dependencies` in WebSocket routes. PR [#4534](https://github.com/tiangolo/fastapi/pull/4534) by [@paulo-raca](https://github.com/paulo-raca). -* ✨ Add exception handler for `WebSocketRequestValidationError` (which also allows to override it). PR [#6030](https://github.com/tiangolo/fastapi/pull/6030) by [@kristjanvalur](https://github.com/kristjanvalur). ## 0.96.1 From 32935103b12b1548117abef0b4af9dd883898308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 12 Jun 2023 00:50:06 +0200 Subject: [PATCH 38/38] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.97.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 63d7d3e5e..917090784 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -3,6 +3,8 @@ ## Latest Changes +## 0.97.0 + ### Features * ✨ Add support for `dependencies` in WebSocket routes. PR [#4534](https://github.com/tiangolo/fastapi/pull/4534) by [@paulo-raca](https://github.com/paulo-raca). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 2bc795b4b..46a056363 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.96.1" +__version__ = "0.97.0" from starlette import status as status