mirror of
https://github.com/fastapi/fastapi.git
synced 2025-12-28 00:30:58 -05:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
392ffaae43 | ||
|
|
202ee0497a | ||
|
|
321e873c95 | ||
|
|
4860631468 | ||
|
|
8e4c96c703 | ||
|
|
39813aa9b0 | ||
|
|
3e3278ed3f | ||
|
|
c8a07078cf | ||
|
|
59f91db1d2 | ||
|
|
f04b61bd16 | ||
|
|
253d58bc5c | ||
|
|
78b8a9b6ec | ||
|
|
c26db94a90 | ||
|
|
d1f3753e5e | ||
|
|
d5b0cc9f58 | ||
|
|
42daed222e | ||
|
|
fd3bfe9f50 | ||
|
|
1fea9c5626 | ||
|
|
d783463ebd | ||
|
|
8a4cfa52af |
2
.github/workflows/preview-docs.yml
vendored
2
.github/workflows/preview-docs.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
rm -rf ./site
|
||||
mkdir ./site
|
||||
- name: Download Artifact Docs
|
||||
uses: dawidd6/action-download-artifact@v2.24.3
|
||||
uses: dawidd6/action-download-artifact@v2.26.0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
workflow: build-docs.yml
|
||||
|
||||
2
.github/workflows/smokeshow.yml
vendored
2
.github/workflows/smokeshow.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
|
||||
- run: pip install smokeshow
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2.24.3
|
||||
- uses: dawidd6/action-download-artifact@v2.26.0
|
||||
with:
|
||||
workflow: test.yml
|
||||
commit: ${{ github.event.workflow_run.head_sha }}
|
||||
|
||||
@@ -4,7 +4,7 @@ default_language_version:
|
||||
python: python3.10
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.3.0
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
- id: check-toml
|
||||
@@ -14,14 +14,14 @@ repos:
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.2.2
|
||||
rev: v3.3.1
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args:
|
||||
- --py3-plus
|
||||
- --keep-runtime-typing
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.138
|
||||
rev: v0.0.254
|
||||
hooks:
|
||||
- id: ruff
|
||||
args:
|
||||
@@ -38,7 +38,7 @@ repos:
|
||||
name: isort (pyi)
|
||||
types: [pyi]
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.10.0
|
||||
rev: 23.1.0
|
||||
hooks:
|
||||
- id: black
|
||||
ci:
|
||||
|
||||
@@ -138,9 +138,6 @@ Here, the `shutdown` event handler function will write a text line `"Application
|
||||
|
||||
So, we declare the event handler function with standard `def` instead of `async def`.
|
||||
|
||||
!!! info
|
||||
You can read more about these event handlers in <a href="https://www.starlette.io/events/" class="external-link" target="_blank">Starlette's Events' docs</a>.
|
||||
|
||||
### `startup` and `shutdown` together
|
||||
|
||||
There's a high chance that the logic for your *startup* and *shutdown* is connected, you might want to start something and then finish it, acquire a resource and then release it, etc.
|
||||
@@ -155,6 +152,11 @@ Just a technical detail for the curious nerds. 🤓
|
||||
|
||||
Underneath, in the ASGI technical specification, this is part of the <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan Protocol</a>, and it defines events called `startup` and `shutdown`.
|
||||
|
||||
!!! info
|
||||
You can read more about the Starlette `lifespan` handlers in <a href="https://www.starlette.io/lifespan/" class="external-link" target="_blank">Starlette's Lifespan' docs</a>.
|
||||
|
||||
Including how to handle lifespan state that can be used in other areas of your code.
|
||||
|
||||
## Sub Applications
|
||||
|
||||
🚨 Have in mind that these lifespan events (startup and shutdown) will only be executed for the main application, not for [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}.
|
||||
|
||||
@@ -92,7 +92,7 @@ There are many other ASGI middlewares.
|
||||
|
||||
For example:
|
||||
|
||||
* <a href="https://docs.sentry.io/platforms/python/asgi/" class="external-link" target="_blank">Sentry</a>
|
||||
* <a href="https://docs.sentry.io/platforms/python/guides/fastapi/" class="external-link" target="_blank">Sentry</a>
|
||||
* <a href="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py" class="external-link" target="_blank">Uvicorn's `ProxyHeadersMiddleware`</a>
|
||||
* <a href="https://github.com/florimondmanca/msgpack-asgi" class="external-link" target="_blank">MessagePack</a>
|
||||
|
||||
|
||||
@@ -3,6 +3,29 @@
|
||||
## Latest Changes
|
||||
|
||||
|
||||
## 0.94.0
|
||||
|
||||
### Upgrades
|
||||
|
||||
* ⬆ Upgrade python-multipart to support 0.0.6. PR [#9212](https://github.com/tiangolo/fastapi/pull/9212) by [@musicinmybrain](https://github.com/musicinmybrain).
|
||||
* ⬆️ Upgrade Starlette version, support new `lifespan` with state. PR [#9239](https://github.com/tiangolo/fastapi/pull/9239) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update Sentry link in docs. PR [#9218](https://github.com/tiangolo/fastapi/pull/9218) by [@smeubank](https://github.com/smeubank).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Add Russian translation for `docs/ru/docs/history-design-future.md`. PR [#5986](https://github.com/tiangolo/fastapi/pull/5986) by [@Xewus](https://github.com/Xewus).
|
||||
|
||||
### Internal
|
||||
|
||||
* ➕ Add `pydantic` to PyPI classifiers. PR [#5914](https://github.com/tiangolo/fastapi/pull/5914) by [@yezz123](https://github.com/yezz123).
|
||||
* ⬆ Bump black from 22.10.0 to 23.1.0. PR [#5953](https://github.com/tiangolo/fastapi/pull/5953) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump types-ujson from 5.6.0.0 to 5.7.0.1. PR [#6027](https://github.com/tiangolo/fastapi/pull/6027) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump dawidd6/action-download-artifact from 2.24.3 to 2.26.0. PR [#6034](https://github.com/tiangolo/fastapi/pull/6034) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5709](https://github.com/tiangolo/fastapi/pull/5709) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
|
||||
|
||||
## 0.93.0
|
||||
|
||||
### Features
|
||||
|
||||
77
docs/ru/docs/history-design-future.md
Normal file
77
docs/ru/docs/history-design-future.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# История создания и дальнейшее развитие
|
||||
|
||||
Однажды, <a href="https://github.com/tiangolo/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">один из пользователей **FastAPI** задал вопрос</a>:
|
||||
|
||||
> Какова история этого проекта? Создаётся впечатление, что он явился из ниоткуда и завоевал мир за несколько недель [...]
|
||||
|
||||
Что ж, вот небольшая часть истории проекта.
|
||||
|
||||
## Альтернативы
|
||||
|
||||
В течение нескольких лет я, возглавляя различные команды разработчиков, создавал довольно сложные API для машинного обучения, распределённых систем, асинхронных задач, баз данных NoSQL и т.д.
|
||||
|
||||
В рамках работы над этими проектами я исследовал, проверял и использовал многие фреймворки.
|
||||
|
||||
Во многом история **FastAPI** - история его предшественников.
|
||||
|
||||
Как написано в разделе [Альтернативы](alternatives.md){.internal-link target=_blank}:
|
||||
|
||||
<blockquote markdown="1">
|
||||
|
||||
**FastAPI** не существовал бы, если б не было более ранних работ других людей.
|
||||
|
||||
Они создали большое количество инструментов, которые и вдохновили меня на создание **FastAPI**.
|
||||
|
||||
Я всячески избегал создания нового фреймворка в течение нескольких лет. Сначала я пытался собрать все нужные возможности, которые ныне есть в **FastAPI**, используя множество различных фреймворков, плагинов и инструментов.
|
||||
|
||||
Но в какой-то момент не осталось другого выбора, кроме как создать что-то, что предоставляло бы все эти возможности сразу. Взять самые лучшие идеи из предыдущих инструментов и, используя введённые в Python подсказки типов (которых не было до версии 3.6), объединить их.
|
||||
|
||||
</blockquote>
|
||||
|
||||
## Исследования
|
||||
|
||||
Благодаря опыту использования существующих альтернатив, мы с коллегами изучили их основные идеи и скомбинировали собранные знания наилучшим образом.
|
||||
|
||||
Например, стало ясно, что необходимо брать за основу стандартные подсказки типов Python, а самым лучшим подходом является использование уже существующих стандартов.
|
||||
|
||||
Итак, прежде чем приступить к написанию **FastAPI**, я потратил несколько месяцев на изучение OpenAPI, JSON Schema, OAuth2, и т.п. для понимания их взаимосвязей, совпадений и различий.
|
||||
|
||||
## Дизайн
|
||||
|
||||
Затем я потратил некоторое время на придумывание "API" разработчика, который я хотел иметь как пользователь (как разработчик, использующий FastAPI).
|
||||
|
||||
Я проверил несколько идей на самых популярных редакторах кода среди Python-разработчиков: PyCharm, VS Code, Jedi.
|
||||
|
||||
Данные по редакторам я взял из <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">опроса Python-разработчиков</a>, который охватываает около 80% пользователей.
|
||||
|
||||
Это означает, что **FastAPI** был специально проверен на редакторах, используемых 80% Python-разработчиками. И поскольку большинство других редакторов, как правило, работают аналогичным образом, все его преимущества должны работать практически для всех редакторов.
|
||||
|
||||
Таким образом, я смог найти наилучшие способы сократить дублирование кода, обеспечить повсеместное автодополнение, проверку типов и ошибок и т.д.
|
||||
|
||||
И все это, чтобы все пользователи могли получать наилучший опыт разработки.
|
||||
|
||||
## Зависимости
|
||||
|
||||
Протестировав несколько вариантов, я решил, что в качестве основы буду использовать <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">**Pydantic**</a> и его преимущества.
|
||||
|
||||
По моим предложениям был изменён код этого фреймворка, чтобы сделать его полностью совместимым с JSON Schema, поддержать различные способы определения ограничений и улучшить помощь редакторов (проверки типов, автозаполнение).
|
||||
|
||||
В то же время, я принимал участие в разработке <a href="https://www.starlette.io/" class="external-link" target="_blank">**Starlette**</a>, ещё один из основных компонентов FastAPI.
|
||||
|
||||
## Разработка
|
||||
|
||||
К тому времени, когда я начал создавать **FastAPI**, большинство необходимых деталей уже существовало, дизайн был определён, зависимости и прочие инструменты были готовы, а знания о стандартах и спецификациях были четкими и свежими.
|
||||
|
||||
## Будущее
|
||||
|
||||
Сейчас уже ясно, что **FastAPI** со своими идеями стал полезен многим людям.
|
||||
|
||||
При сравнении с альтернативами, выбор падает на него, поскольку он лучше подходит для множества вариантов использования.
|
||||
|
||||
Многие разработчики и команды уже используют **FastAPI** в своих проектах (включая меня и мою команду).
|
||||
|
||||
Но, тем не менее, грядёт добавление ещё многих улучшений и возможностей.
|
||||
|
||||
У **FastAPI** великое будущее.
|
||||
|
||||
И [ваш вклад в это](help-fastapi.md){.internal-link target=_blank} - очень ценнен.
|
||||
@@ -71,6 +71,7 @@ nav:
|
||||
- Развёртывание:
|
||||
- deployment/index.md
|
||||
- deployment/versions.md
|
||||
- history-design-future.md
|
||||
- external-links.md
|
||||
- contributing.md
|
||||
markdown_extensions:
|
||||
|
||||
@@ -25,7 +25,7 @@ async def update_item(
|
||||
item: Item,
|
||||
user: User,
|
||||
importance: int = Body(gt=0),
|
||||
q: Union[str, None] = None
|
||||
q: Union[str, None] = None,
|
||||
):
|
||||
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
|
||||
if q:
|
||||
|
||||
@@ -23,7 +23,7 @@ async def update_item(
|
||||
item: Item,
|
||||
user: User,
|
||||
importance: int = Body(gt=0),
|
||||
q: str | None = None
|
||||
q: str | None = None,
|
||||
):
|
||||
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
|
||||
if q:
|
||||
|
||||
@@ -8,7 +8,7 @@ async def read_items(
|
||||
*,
|
||||
item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
|
||||
q: str,
|
||||
size: float = Query(gt=0, lt=10.5)
|
||||
size: float = Query(gt=0, lt=10.5),
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.93.0"
|
||||
__version__ = "0.94.0"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from enum import Enum
|
||||
from typing import (
|
||||
Any,
|
||||
AsyncContextManager,
|
||||
Awaitable,
|
||||
Callable,
|
||||
Coroutine,
|
||||
@@ -42,7 +41,7 @@ from starlette.middleware.exceptions import ExceptionMiddleware
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import HTMLResponse, JSONResponse, Response
|
||||
from starlette.routing import BaseRoute
|
||||
from starlette.types import ASGIApp, Receive, Scope, Send
|
||||
from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
|
||||
|
||||
|
||||
class FastAPI(Starlette):
|
||||
@@ -72,7 +71,7 @@ class FastAPI(Starlette):
|
||||
] = None,
|
||||
on_startup: Optional[Sequence[Callable[[], Any]]] = None,
|
||||
on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
|
||||
lifespan: Optional[Callable[["FastAPI"], AsyncContextManager[Any]]] = None,
|
||||
lifespan: Optional[Lifespan] = None,
|
||||
terms_of_service: Optional[str] = None,
|
||||
contact: Optional[Dict[str, Union[str, Any]]] = None,
|
||||
license_info: Optional[Dict[str, Union[str, Any]]] = None,
|
||||
|
||||
@@ -696,7 +696,7 @@ async def request_body_to_args(
|
||||
fn: Callable[[], Coroutine[Any, Any, Any]]
|
||||
) -> None:
|
||||
result = await fn()
|
||||
results.append(result)
|
||||
results.append(result) # noqa: B023
|
||||
|
||||
async with anyio.create_task_group() as tg:
|
||||
for sub_value in value:
|
||||
|
||||
@@ -7,7 +7,6 @@ from contextlib import AsyncExitStack
|
||||
from enum import Enum, IntEnum
|
||||
from typing import (
|
||||
Any,
|
||||
AsyncContextManager,
|
||||
Callable,
|
||||
Coroutine,
|
||||
Dict,
|
||||
@@ -58,7 +57,7 @@ from starlette.routing import (
|
||||
websocket_session,
|
||||
)
|
||||
from starlette.status import WS_1008_POLICY_VIOLATION
|
||||
from starlette.types import ASGIApp, Scope
|
||||
from starlette.types import ASGIApp, Lifespan, Scope
|
||||
from starlette.websockets import WebSocket
|
||||
|
||||
|
||||
@@ -493,7 +492,7 @@ class APIRouter(routing.Router):
|
||||
route_class: Type[APIRoute] = APIRoute,
|
||||
on_startup: Optional[Sequence[Callable[[], Any]]] = None,
|
||||
on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
|
||||
lifespan: Optional[Callable[[Any], AsyncContextManager[Any]]] = None,
|
||||
lifespan: Optional[Lifespan] = None,
|
||||
deprecated: Optional[bool] = None,
|
||||
include_in_schema: bool = True,
|
||||
generate_unique_id_function: Callable[[APIRoute], str] = Default(
|
||||
@@ -1251,7 +1250,6 @@ class APIRouter(routing.Router):
|
||||
generate_unique_id
|
||||
),
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
|
||||
return self.api_route(
|
||||
path=path,
|
||||
response_model=response_model,
|
||||
|
||||
@@ -18,7 +18,7 @@ class APIKeyQuery(APIKeyBase):
|
||||
name: str,
|
||||
scheme_name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
auto_error: bool = True
|
||||
auto_error: bool = True,
|
||||
):
|
||||
self.model: APIKey = APIKey(
|
||||
**{"in": APIKeyIn.query}, name=name, description=description
|
||||
@@ -45,7 +45,7 @@ class APIKeyHeader(APIKeyBase):
|
||||
name: str,
|
||||
scheme_name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
auto_error: bool = True
|
||||
auto_error: bool = True,
|
||||
):
|
||||
self.model: APIKey = APIKey(
|
||||
**{"in": APIKeyIn.header}, name=name, description=description
|
||||
@@ -72,7 +72,7 @@ class APIKeyCookie(APIKeyBase):
|
||||
name: str,
|
||||
scheme_name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
auto_error: bool = True
|
||||
auto_error: bool = True,
|
||||
):
|
||||
self.model: APIKey = APIKey(
|
||||
**{"in": APIKeyIn.cookie}, name=name, description=description
|
||||
|
||||
@@ -119,7 +119,7 @@ class OAuth2(SecurityBase):
|
||||
flows: Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]] = OAuthFlowsModel(),
|
||||
scheme_name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
auto_error: bool = True
|
||||
auto_error: bool = True,
|
||||
):
|
||||
self.model = OAuth2Model(flows=flows, description=description)
|
||||
self.scheme_name = scheme_name or self.__class__.__name__
|
||||
|
||||
@@ -14,7 +14,7 @@ class OpenIdConnect(SecurityBase):
|
||||
openIdConnectUrl: str,
|
||||
scheme_name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
auto_error: bool = True
|
||||
auto_error: bool = True,
|
||||
):
|
||||
self.model = OpenIdConnectModel(
|
||||
openIdConnectUrl=openIdConnectUrl, description=description
|
||||
|
||||
@@ -27,6 +27,8 @@ classifiers = [
|
||||
"Environment :: Web Environment",
|
||||
"Framework :: AsyncIO",
|
||||
"Framework :: FastAPI",
|
||||
"Framework :: Pydantic",
|
||||
"Framework :: Pydantic :: 1",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
@@ -39,7 +41,7 @@ classifiers = [
|
||||
"Topic :: Internet :: WWW/HTTP",
|
||||
]
|
||||
dependencies = [
|
||||
"starlette>=0.25.0,<0.26.0",
|
||||
"starlette>=0.26.0,<0.27.0",
|
||||
"pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
@@ -54,7 +56,7 @@ test = [
|
||||
"coverage[toml] >= 6.5.0,< 8.0",
|
||||
"mypy ==0.982",
|
||||
"ruff ==0.0.138",
|
||||
"black == 22.10.0",
|
||||
"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",
|
||||
@@ -65,7 +67,7 @@ test = [
|
||||
"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.6",
|
||||
"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",
|
||||
@@ -73,7 +75,7 @@ test = [
|
||||
"passlib[bcrypt] >=1.7.2,<2.0.0",
|
||||
|
||||
# types
|
||||
"types-ujson ==5.6.0.0",
|
||||
"types-ujson ==5.7.0.1",
|
||||
"types-orjson ==3.6.2",
|
||||
]
|
||||
doc = [
|
||||
|
||||
@@ -150,7 +150,6 @@ def get_app():
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client(app: FastAPI):
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
@@ -152,7 +152,6 @@ def get_app():
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client(app: FastAPI):
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
Reference in New Issue
Block a user