Browse Source

Merge branch 'fastapi:master' into master

pull/13760/head
Kamran Pulatov 4 weeks ago
committed by GitHub
parent
commit
a4f95c49c7
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      README.md
  2. 2
      docs/de/docs/advanced/generate-clients.md
  3. 2
      docs/en/data/sponsors.yml
  4. 2
      docs/en/docs/advanced/generate-clients.md
  5. 2
      docs/en/docs/advanced/response-directly.md
  6. 2
      docs/en/docs/async.md
  7. 31
      docs/en/docs/release-notes.md
  8. 5
      docs/en/docs/tutorial/cors.md
  9. 23
      docs/en/docs/tutorial/middleware.md
  10. 2
      docs/es/docs/advanced/generate-clients.md
  11. 5
      docs/fa/docs/learn/index.md
  12. 2
      docs/pt/docs/advanced/generate-clients.md
  13. 21
      docs/ru/docs/advanced/index.md
  14. 31
      docs/ru/docs/advanced/response-change-status-code.md
  15. 2
      fastapi/__init__.py
  16. 5
      fastapi/_compat.py
  17. 27
      fastapi/applications.py
  18. 18
      fastapi/routing.py
  19. 21
      fastapi/security/oauth2.py
  20. 4
      scripts/label_approved.py
  21. 31
      tests/test_openapi_model_description_trim_on_formfeed.py
  22. 13
      tests/test_tutorial/test_security/test_tutorial003.py
  23. 13
      tests/test_tutorial/test_security/test_tutorial005.py
  24. 20
      tests/test_tutorial/test_settings/test_tutorial001.py
  25. 19
      tests/test_tutorial/test_settings/test_tutorial001_pv1.py
  26. 12
      tests/test_validate_response_recursive/app.py
  27. 51
      tests/test_validate_response_recursive/app_pv2.py
  28. 5
      tests/test_validate_response_recursive/test_validate_response_recursive.py
  29. 33
      tests/test_validate_response_recursive/test_validate_response_recursive_pv1.py

2
README.md

@ -56,7 +56,7 @@ The key features are:
<a href="https://www.coderabbit.ai/?utm_source=fastapi&utm_medium=badge&utm_campaign=fastapi" target="_blank" title="Cut Code Review Time & Bugs in Half with CodeRabbit"><img src="https://fastapi.tiangolo.com/img/sponsors/coderabbit.png"></a>
<a href="https://subtotal.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=open-source" target="_blank" title="The Gold Standard in Retail Account Linking"><img src="https://fastapi.tiangolo.com/img/sponsors/subtotal.svg"></a>
<a href="https://databento.com/" target="_blank" title="Pay as you go for market data"><img src="https://fastapi.tiangolo.com/img/sponsors/databento.svg"></a>
<a href="https://speakeasy.com?utm_source=fastapi+repo&utm_medium=github+sponsorship" target="_blank" title="SDKs for your API | Speakeasy"><img src="https://fastapi.tiangolo.com/img/sponsors/speakeasy.png"></a>
<a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" target="_blank" title="SDKs for your API | Speakeasy"><img src="https://fastapi.tiangolo.com/img/sponsors/speakeasy.png"></a>
<a href="https://www.svix.com/" target="_blank" title="Svix - Webhooks as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/svix.svg"></a>
<a href="https://www.stainlessapi.com/?utm_source=fastapi&utm_medium=referral" target="_blank" title="Stainless | Generate best-in-class SDKs"><img src="https://fastapi.tiangolo.com/img/sponsors/stainless.png"></a>
<a href="https://www.permit.io/blog/implement-authorization-in-fastapi?utm_source=github&utm_medium=referral&utm_campaign=fastapi" target="_blank" title="Fine-Grained Authorization for FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/permit.png"></a>

2
docs/de/docs/advanced/generate-clients.md

@ -20,7 +20,7 @@ Einige von diesen ✨ [**sponsern FastAPI**](../help-fastapi.md#den-autor-sponse
Und es zeigt deren wahres Engagement für FastAPI und seine **Community** (Sie), da diese Ihnen nicht nur einen **guten Service** bieten möchten, sondern auch sicherstellen möchten, dass Sie über ein **gutes und gesundes Framework** verfügen, FastAPI. 🙇
Beispielsweise könnten Sie <a href="https://speakeasy.com/?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a> ausprobieren.
Beispielsweise könnten Sie <a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a> ausprobieren.
Es gibt auch mehrere andere Unternehmen, welche ähnliche Dienste anbieten und die Sie online suchen und finden können. 🤓

2
docs/en/data/sponsors.yml

@ -30,7 +30,7 @@ silver:
- url: https://databento.com/
title: Pay as you go for market data
img: https://fastapi.tiangolo.com/img/sponsors/databento.svg
- url: https://speakeasy.com?utm_source=fastapi+repo&utm_medium=github+sponsorship
- url: https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship
title: SDKs for your API | Speakeasy
img: https://fastapi.tiangolo.com/img/sponsors/speakeasy.png
- url: https://www.svix.com/

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

@ -22,7 +22,7 @@ And it shows their true commitment to FastAPI and its **community** (you), as th
For example, you might want to try:
* <a href="https://speakeasy.com/?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
* <a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
* <a href="https://www.stainlessapi.com/?utm_source=fastapi&utm_medium=referral" class="external-link" target="_blank">Stainless</a>
* <a href="https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi" class="external-link" target="_blank">liblab</a>

2
docs/en/docs/advanced/response-directly.md

@ -58,7 +58,7 @@ You could put your XML content in a string, put that in a `Response`, and return
## Notes
When you return a `Response` directly its data is not validated, converted (serialized), nor documented automatically.
When you return a `Response` directly its data is not validated, converted (serialized), or documented automatically.
But you can still document it as described in [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.

2
docs/en/docs/async.md

@ -40,7 +40,7 @@ def results():
---
If your application (somehow) doesn't have to communicate with anything else and wait for it to respond, use `async def`.
If your application (somehow) doesn't have to communicate with anything else and wait for it to respond, use `async def`, even if you don't need to use `await` inside.
---

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

@ -7,12 +7,40 @@ hide:
## Latest Changes
### Docs
* Misprint. PR [#13800](https://github.com/fastapi/fastapi/pull/13800) by [@NavesSapnis](https://github.com/NavesSapnis).
* 📝 Update Speakeasy URL to Speakeasy Sandbox. PR [#13697](https://github.com/fastapi/fastapi/pull/13697) by [@ndimares](https://github.com/ndimares).
### Translations
* 🌐 Add Russian translation for `docs/ru/docs/advanced/index.md`. PR [#13797](https://github.com/fastapi/fastapi/pull/13797) by [@NavesSapnis](https://github.com/NavesSapnis).
## 0.115.13
### Fixes
* 🐛 Fix truncating the model's description with form feed (`\f`) character for Pydantic V2. PR [#13698](https://github.com/fastapi/fastapi/pull/13698) by [@YuriiMotov](https://github.com/YuriiMotov).
### Refactors
* ✨ Add `refreshUrl` parameter in `OAuth2PasswordBearer`. PR [#11460](https://github.com/fastapi/fastapi/pull/11460) by [@snosratiershad](https://github.com/snosratiershad).
* 🚸 Set format to password for fields `password` and `client_secret` in `OAuth2PasswordRequestForm`, make docs show password fields for passwords. PR [#11032](https://github.com/fastapi/fastapi/pull/11032) by [@Thodoris1999](https://github.com/Thodoris1999).
* ✅ Simplify tests for `settings`. PR [#13505](https://github.com/fastapi/fastapi/pull/13505) by [@valentinDruzhinin](https://github.com/valentinDruzhinin).
* ✅ Simplify tests for `validate_response_recursive`. PR [#13507](https://github.com/fastapi/fastapi/pull/13507) by [@valentinDruzhinin](https://github.com/valentinDruzhinin).
### Upgrades
* ⬆️ Update ReDoc to version 2.x. PR [#9700](https://github.com/fastapi/fastapi/pull/9700) by [@joakimnordling](https://github.com/joakimnordling).
### Docs
* 📝 Add annotations to HTTP middleware example. PR [#11530](https://github.com/fastapi/fastapi/pull/11530) by [@Kilo59](https://github.com/Kilo59).
* 📝 Clarify in CORS docs that wildcards and credentials are mutually exclusive. PR [#9829](https://github.com/fastapi/fastapi/pull/9829) by [@dfioravanti](https://github.com/dfioravanti).
* ✏️ Fix typo in docstring. PR [#13532](https://github.com/fastapi/fastapi/pull/13532) by [@comp64](https://github.com/comp64).
* 📝 Clarify guidance on using `async def` without `await`. PR [#13642](https://github.com/fastapi/fastapi/pull/13642) by [@swastikpradhan1999](https://github.com/swastikpradhan1999).
* 📝 Update exclude-parameters-from-openapi documentation links. PR [#13600](https://github.com/fastapi/fastapi/pull/13600) by [@timonrieger](https://github.com/timonrieger).
* 📝 Clarify the middleware execution order in docs. PR [#13699](https://github.com/fastapi/fastapi/pull/13699) by [@YuriiMotov](https://github.com/YuriiMotov).
* 🍱 Update Drawio diagrams SVGs, single file per diagram, sans-serif font. PR [#13706](https://github.com/fastapi/fastapi/pull/13706) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update docs for "Help FastAPI", simplify and reduce "sponsor" section. PR [#13670](https://github.com/fastapi/fastapi/pull/13670) by [@tiangolo](https://github.com/tiangolo).
* 📝 Remove unnecessary bullet from docs. PR [#13641](https://github.com/fastapi/fastapi/pull/13641) by [@Adamowoc](https://github.com/Adamowoc).
@ -24,6 +52,8 @@ hide:
### Translations
* 🌐 Add Russian Translation for `docs/ru/docs/advanced/response-change-status-code.md`. PR [#13791](https://github.com/fastapi/fastapi/pull/13791) by [@NavesSapnis](https://github.com/NavesSapnis).
* 🌐 Add Persian translation for `docs/fa/docs/learn/index.md`. PR [#13518](https://github.com/fastapi/fastapi/pull/13518) by [@Mohammad222PR](https://github.com/Mohammad222PR).
* 🌐 Add Korean translation for `docs/ko/docs/advanced/sub-applications.md`. PR [#4543](https://github.com/fastapi/fastapi/pull/4543) by [@NinaHwang](https://github.com/NinaHwang).
* 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/schema-extra-example.md`. PR [#13769](https://github.com/fastapi/fastapi/pull/13769) by [@valentinDruzhinin](https://github.com/valentinDruzhinin).
* ✏️ Remove redundant words in docs/zh/docs/python-types.md. PR [#13774](https://github.com/fastapi/fastapi/pull/13774) by [@CharleeWa](https://github.com/CharleeWa).
@ -49,6 +79,7 @@ hide:
### Internal
* 🔨 Resolve Pydantic deprecation warnings in internal script. PR [#13696](https://github.com/fastapi/fastapi/pull/13696) by [@emmanuel-ferdman](https://github.com/emmanuel-ferdman).
* 🔧 Update sponsors: remove Porter. PR [#13783](https://github.com/fastapi/fastapi/pull/13783) by [@tiangolo](https://github.com/tiangolo).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13781](https://github.com/fastapi/fastapi/pull/13781) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13757](https://github.com/fastapi/fastapi/pull/13757) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).

5
docs/en/docs/tutorial/cors.md

@ -57,7 +57,10 @@ The following arguments are supported:
* `allow_origin_regex` - A regex string to match against origins that should be permitted to make cross-origin requests. e.g. `'https://.*\.example\.org'`.
* `allow_methods` - A list of HTTP methods that should be allowed for cross-origin requests. Defaults to `['GET']`. You can use `['*']` to allow all standard methods.
* `allow_headers` - A list of HTTP request headers that should be supported for cross-origin requests. Defaults to `[]`. You can use `['*']` to allow all headers. The `Accept`, `Accept-Language`, `Content-Language` and `Content-Type` headers are always allowed for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">simple CORS requests</a>.
* `allow_credentials` - Indicate that cookies should be supported for cross-origin requests. Defaults to `False`. Also, `allow_origins` cannot be set to `['*']` for credentials to be allowed, origins must be specified.
* `allow_credentials` - Indicate that cookies should be supported for cross-origin requests. Defaults to `False`.
None of `allow_origins`, `allow_methods` and `allow_headers` can be set to `['*']` if `allow_credentials` is set to `True`. All of them must be <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards" class="external-link" rel="noopener" target="_blank">explicitly specified</a>.
* `expose_headers` - Indicate any response headers that should be made accessible to the browser. Defaults to `[]`.
* `max_age` - Sets a maximum time in seconds for browsers to cache CORS responses. Defaults to `600`.

23
docs/en/docs/tutorial/middleware.md

@ -65,6 +65,29 @@ Here we use <a href="https://docs.python.org/3/library/time.html#time.perf_count
///
## Multiple middleware execution order
When you add multiple middlewares using either `@app.middleware()` decorator or `app.add_middleware()` method, each new middleware wraps the application, forming a stack. The last middleware added is the *outermost*, and the first is the *innermost*.
On the request path, the *outermost* middleware runs first.
On the response path, it runs last.
For example:
```Python
app.add_middleware(MiddlewareA)
app.add_middleware(MiddlewareB)
```
This results in the following execution order:
* **Request**: MiddlewareB → MiddlewareA → route
* **Response**: route → MiddlewareA → MiddlewareB
This stacking behavior ensures that middlewares are executed in a predictable and controllable order.
## Other middlewares
You can later read more about other middlewares in the [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.

2
docs/es/docs/advanced/generate-clients.md

@ -22,7 +22,7 @@ Y muestra su verdadero compromiso con FastAPI y su **comunidad** (tú), ya que n
Por ejemplo, podrías querer probar:
* <a href="https://speakeasy.com/?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
* <a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
* <a href="https://www.stainlessapi.com/?utm_source=fastapi&utm_medium=referral" class="external-link" target="_blank">Stainless</a>
* <a href="https://developers.liblab.com/tutorials/sdk-for-fastapi/?utm_source=fastapi" class="external-link" target="_blank">liblab</a>

5
docs/fa/docs/learn/index.md

@ -0,0 +1,5 @@
# یادگیری
اینجا بخش‌های مقدماتی و آموزش‌هایی هستن که برای یادگیری **FastAPI** بهت کمک می‌کنن.
می‌تونی اینو یه **کتاب**، یه **دوره آموزشی**، یا راه **رسمی** و پیشنهادی برای یادگیری FastAPI در نظر بگیری. 😎

2
docs/pt/docs/advanced/generate-clients.md

@ -22,7 +22,7 @@ E isso mostra o verdadeiro compromisso deles com o FastAPI e sua **comunidade**
Por exemplo, você pode querer experimentar:
* <a href="https://speakeasy.com/?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
* <a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
* <a href="https://www.stainlessapi.com/?utm_source=fastapi&utm_medium=referral" class="external-link" target="_blank">Stainless</a>
* <a href="https://developers.liblab.com/tutorials/sdk-for-fastapi/?utm_source=fastapi" class="external-link" target="_blank">liblab</a>

21
docs/ru/docs/advanced/index.md

@ -0,0 +1,21 @@
# Расширенное руководство пользователя
## Дополнительные возможности
Основное [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} должно быть достаточно, чтобы познакомить вас со всеми основными функциями **FastAPI**.
В следующих разделах вы увидите другие варианты, конфигурации и дополнительные возможности.
/// tip
Следующие разделы **не обязательно являются "продвинутыми"**.
И вполне возможно, что для вашего случая использования решение находится в одном из них.
///
## Сначала прочитайте Учебник - Руководство пользователя
Вы все еще можете использовать большинство функций **FastAPI** со знаниями из [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank}.
И следующие разделы предполагают, что вы уже прочитали его, и предполагают, что вы знаете эти основные идеи.

31
docs/ru/docs/advanced/response-change-status-code.md

@ -0,0 +1,31 @@
# Response - Изменение cтатус кода
Вы, вероятно, уже читали о том, что можно установить [Состояние ответа по умолчанию](../tutorial/response-status-code.md){.internal-link target=_blank}.
Но в некоторых случаях вам нужно вернуть код состояния, отличный от установленного по умолчанию.
## Пример использования
Например, представьте, что вы хотите возвращать HTTP код состояния "OK" `200` по умолчанию.
Но если данные не существовали, вы хотите создать их и вернуть HTTP код состояния "CREATED" `201`.
При этом вы всё ещё хотите иметь возможность фильтровать и преобразовывать возвращаемые данные с помощью `response_model`.
Для таких случаев вы можете использовать параметр `Response`.
## Использование параметра `Response`
Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (так же как для cookies и headers).
И затем вы можете установить `status_code` в этом *временном* объекте ответа.
{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *}
После этого вы можете вернуть любой объект, который вам нужен, как обычно (`dict`, модель базы данных и т.д.).
И если вы объявили `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта.
**FastAPI** будет использовать этот *временный* ответ для извлечения кода состояния (а также cookies и headers) и поместит их в финальный ответ, который содержит возвращаемое вами значение, отфильтрованное любым `response_model`.
Вы также можете объявить параметр `Response` в зависимостях и установить код состояния в них. Но помните, что последнее установленное значение будет иметь приоритет.

2
fastapi/__init__.py

@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.115.12"
__version__ = "0.115.13"
from starlette import status as status

5
fastapi/_compat.py

@ -16,6 +16,7 @@ from typing import (
Tuple,
Type,
Union,
cast,
)
from fastapi.exceptions import RequestErrorModel
@ -231,6 +232,10 @@ if PYDANTIC_V2:
field_mapping, definitions = schema_generator.generate_definitions(
inputs=inputs
)
for item_def in cast(Dict[str, Dict[str, Any]], definitions).values():
if "description" in item_def:
item_description = cast(str, item_def["description"]).split("\f")[0]
item_def["description"] = item_description
return field_mapping, definitions # type: ignore[return-value]
def is_scalar_field(field: ModelField) -> bool:

27
fastapi/applications.py

@ -748,7 +748,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -1720,7 +1720,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -2093,7 +2093,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -2471,7 +2471,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -2849,7 +2849,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -3222,7 +3222,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -3595,7 +3595,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -3968,7 +3968,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -4346,7 +4346,7 @@ class FastAPI(Starlette):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -4425,7 +4425,7 @@ class FastAPI(Starlette):
app = FastAPI()
@app.put("/items/{item_id}")
@app.trace("/items/{item_id}")
def trace_item(item_id: str):
return None
```
@ -4515,14 +4515,17 @@ class FastAPI(Starlette):
```python
import time
from typing import Awaitable, Callable
from fastapi import FastAPI, Request
from fastapi import FastAPI, Request, Response
app = FastAPI()
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
async def add_process_time_header(
request: Request, call_next: Callable[[Request], Awaitable[Response]]
) -> Response:
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time

18
fastapi/routing.py

@ -814,7 +814,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -1626,7 +1626,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -2003,7 +2003,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -2385,7 +2385,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -2767,7 +2767,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -3144,7 +3144,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -3521,7 +3521,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -3903,7 +3903,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,
@ -4285,7 +4285,7 @@ class APIRouter(routing.Router):
This affects the generated OpenAPI (e.g. visible at `/docs`).
Read more about it in the
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
"""
),
] = True,

21
fastapi/security/oauth2.py

@ -85,7 +85,7 @@ class OAuth2PasswordRequestForm:
],
password: Annotated[
str,
Form(),
Form(json_schema_extra={"format": "password"}),
Doc(
"""
`password` string. The OAuth2 spec requires the exact field name
@ -130,7 +130,7 @@ class OAuth2PasswordRequestForm:
] = None,
client_secret: Annotated[
Union[str, None],
Form(),
Form(json_schema_extra={"format": "password"}),
Doc(
"""
If there's a `client_password` (and a `client_id`), they can be sent
@ -457,11 +457,26 @@ class OAuth2PasswordBearer(OAuth2):
"""
),
] = True,
refreshUrl: Annotated[
Optional[str],
Doc(
"""
The URL to refresh the token and obtain a new one.
"""
),
] = None,
):
if not scopes:
scopes = {}
flows = OAuthFlowsModel(
password=cast(Any, {"tokenUrl": tokenUrl, "scopes": scopes})
password=cast(
Any,
{
"tokenUrl": tokenUrl,
"refreshUrl": refreshUrl,
"scopes": scopes,
},
)
)
super().__init__(
flows=flows,

4
scripts/label_approved.py

@ -27,7 +27,7 @@ if settings.debug:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
logging.debug(f"Using config: {settings.json()}")
logging.debug(f"Using config: {settings.model_dump_json()}")
g = Github(settings.token.get_secret_value())
repo = g.get_repo(settings.github_repository)
for pr in repo.get_pulls(state="open"):
@ -48,7 +48,7 @@ for pr in repo.get_pulls(state="open"):
]
config = settings.config or default_config
for approved_label, conf in config.items():
logging.debug(f"Processing config: {conf.json()}")
logging.debug(f"Processing config: {conf.model_dump_json()}")
if conf.await_label is None or (conf.await_label in pr_label_by_name):
logging.debug(f"Processable PR: {pr.number}")
if len(approved_reviews) >= conf.number:

31
tests/test_openapi_model_description_trim_on_formfeed.py

@ -0,0 +1,31 @@
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
app = FastAPI()
class MyModel(BaseModel):
"""
A model with a form feed character in the title.
\f
Text after form feed character.
"""
@app.get("/foo")
def foo(v: MyModel): # pragma: no cover
pass
client = TestClient(app)
def test_openapi():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
openapi_schema = response.json()
assert openapi_schema["components"]["schemas"]["MyModel"]["description"] == (
"A model with a form feed character in the title.\n"
)

13
tests/test_tutorial/test_security/test_tutorial003.py

@ -163,7 +163,11 @@ def test_openapi_schema(client: TestClient):
}
),
"username": {"title": "Username", "type": "string"},
"password": {"title": "Password", "type": "string"},
"password": {
"title": "Password",
"type": "string",
"format": "password",
},
"scope": {"title": "Scope", "type": "string", "default": ""},
"client_id": IsDict(
{
@ -179,11 +183,16 @@ def test_openapi_schema(client: TestClient):
{
"title": "Client Secret",
"anyOf": [{"type": "string"}, {"type": "null"}],
"format": "password",
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Client Secret", "type": "string"}
{
"title": "Client Secret",
"type": "string",
"format": "password",
}
),
},
},

13
tests/test_tutorial/test_security/test_tutorial005.py

@ -377,7 +377,11 @@ def test_openapi_schema(mod: ModuleType):
}
),
"username": {"title": "Username", "type": "string"},
"password": {"title": "Password", "type": "string"},
"password": {
"title": "Password",
"type": "string",
"format": "password",
},
"scope": {"title": "Scope", "type": "string", "default": ""},
"client_id": IsDict(
{
@ -393,11 +397,16 @@ def test_openapi_schema(mod: ModuleType):
{
"title": "Client Secret",
"anyOf": [{"type": "string"}, {"type": "null"}],
"format": "password",
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Client Secret", "type": "string"}
{
"title": "Client Secret",
"type": "string",
"format": "password",
}
),
},
},

20
tests/test_tutorial/test_settings/test_tutorial001.py

@ -1,14 +1,26 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from pytest import MonkeyPatch
from ...utils import needs_pydanticv2
from ...utils import needs_pydanticv1, needs_pydanticv2
@needs_pydanticv2
def test_settings(monkeypatch: MonkeyPatch):
@pytest.fixture(
name="app",
params=[
pytest.param("tutorial001", marks=needs_pydanticv2),
pytest.param("tutorial001_pv1", marks=needs_pydanticv1),
],
)
def get_app(request: pytest.FixtureRequest, monkeypatch: MonkeyPatch):
monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
from docs_src.settings.tutorial001 import app
mod = importlib.import_module(f"docs_src.settings.{request.param}")
return mod.app
def test_settings(app):
client = TestClient(app)
response = client.get("/info")
assert response.status_code == 200, response.text

19
tests/test_tutorial/test_settings/test_tutorial001_pv1.py

@ -1,19 +0,0 @@
from fastapi.testclient import TestClient
from pytest import MonkeyPatch
from ...utils import needs_pydanticv1
@needs_pydanticv1
def test_settings(monkeypatch: MonkeyPatch):
monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
from docs_src.settings.tutorial001_pv1 import app
client = TestClient(app)
response = client.get("/info")
assert response.status_code == 200, response.text
assert response.json() == {
"app_name": "Awesome API",
"admin_email": "admin@example.com",
"items_per_user": 50,
}

12
tests/test_validate_response_recursive/app_pv1.py → tests/test_validate_response_recursive/app.py

@ -1,6 +1,7 @@
from typing import List
from fastapi import FastAPI
from fastapi._compat import PYDANTIC_V2
from pydantic import BaseModel
app = FastAPI()
@ -11,9 +12,6 @@ class RecursiveItem(BaseModel):
name: str
RecursiveItem.update_forward_refs()
class RecursiveSubitemInSubmodel(BaseModel):
sub_items2: List["RecursiveItemViaSubmodel"] = []
name: str
@ -24,7 +22,13 @@ class RecursiveItemViaSubmodel(BaseModel):
name: str
RecursiveSubitemInSubmodel.update_forward_refs()
if PYDANTIC_V2:
RecursiveItem.model_rebuild()
RecursiveSubitemInSubmodel.model_rebuild()
RecursiveItemViaSubmodel.model_rebuild()
else:
RecursiveItem.update_forward_refs()
RecursiveSubitemInSubmodel.update_forward_refs()
@app.get("/items/recursive", response_model=RecursiveItem)

51
tests/test_validate_response_recursive/app_pv2.py

@ -1,51 +0,0 @@
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class RecursiveItem(BaseModel):
sub_items: List["RecursiveItem"] = []
name: str
RecursiveItem.model_rebuild()
class RecursiveSubitemInSubmodel(BaseModel):
sub_items2: List["RecursiveItemViaSubmodel"] = []
name: str
class RecursiveItemViaSubmodel(BaseModel):
sub_items1: List[RecursiveSubitemInSubmodel] = []
name: str
RecursiveSubitemInSubmodel.model_rebuild()
RecursiveItemViaSubmodel.model_rebuild()
@app.get("/items/recursive", response_model=RecursiveItem)
def get_recursive():
return {"name": "item", "sub_items": [{"name": "subitem", "sub_items": []}]}
@app.get("/items/recursive-submodel", response_model=RecursiveItemViaSubmodel)
def get_recursive_submodel():
return {
"name": "item",
"sub_items1": [
{
"name": "subitem",
"sub_items2": [
{
"name": "subsubitem",
"sub_items1": [{"name": "subsubsubitem", "sub_items2": []}],
}
],
}
],
}

5
tests/test_validate_response_recursive/test_validate_response_recursive_pv2.py → tests/test_validate_response_recursive/test_validate_response_recursive.py

@ -1,12 +1,9 @@
from fastapi.testclient import TestClient
from ..utils import needs_pydanticv2
from .app import app
@needs_pydanticv2
def test_recursive():
from .app_pv2 import app
client = TestClient(app)
response = client.get("/items/recursive")
assert response.status_code == 200, response.text

33
tests/test_validate_response_recursive/test_validate_response_recursive_pv1.py

@ -1,33 +0,0 @@
from fastapi.testclient import TestClient
from ..utils import needs_pydanticv1
@needs_pydanticv1
def test_recursive():
from .app_pv1 import app
client = TestClient(app)
response = client.get("/items/recursive")
assert response.status_code == 200, response.text
assert response.json() == {
"sub_items": [{"name": "subitem", "sub_items": []}],
"name": "item",
}
response = client.get("/items/recursive-submodel")
assert response.status_code == 200, response.text
assert response.json() == {
"name": "item",
"sub_items1": [
{
"name": "subitem",
"sub_items2": [
{
"name": "subsubitem",
"sub_items1": [{"name": "subsubsubitem", "sub_items2": []}],
}
],
}
],
}
Loading…
Cancel
Save